Clock.cpp
/********************************************************************************
* Realistically-looking analog clock
* Created by Dimitry Rotstein
* Copyright (C) 2014 by Miranor
*******************************************************************************/
#include <elgrint.cpp>
class ClockFrame : public MMainFrame
{
public:
ClockFrame() : MMainFrame(MRect(AutoPoint,400,400)), m_dt(MSys::getDateTime())
{
// Initial mainframe confuguration
setCaption("Clock");
setBackColor(clWhite);
setForeColor(clBlack);
setHighQuality(true);
bar().close();
maxButton().close();
xButton().setBackColor(clGray+50);
xButton().setForeColor(clBlack);
minButton().setBackColor(clGray+50);
minButton().setForeColor(clBlack);
setTimer(0,50);
// Create app icon (shaped like a miniature clock)
MImage icon(MSize(32,32), clOrange+clWhite+clWhite);
for (int i = 0; i < 32; ++i) // Mini-frame
for (int j = 0; j < 32; ++j)
if (abs(i-16) > 13 || abs(j-16) > 13) icon.setPixel(MPoint(i,j),clBlack);
for (int i = 8; i <= 16; ++i) // Mini-handles
{
icon.setPixel(MPoint(i,i+2),clBlack);
icon.setPixel(MPoint(32-i,i+2),clBlack);
}
setIcon(icon);
}
ON_KeysEntered // Prints the clock to a file (for demonstration purposes)
{
if (digKeys() == kbCtrl+kbP)
MApp::screen().getImage(getRect()).saveAs("clock.png");
else
MMainFrame::OnKeysEntered();
}
ON_TimerExpired // Repaints the clock every second
{
if (digTimerID() == 0)
{
// Repaint only if seconds changed (otherwise repaint is redundant)
MDateTime dt = MSys::getDateTime();
if ((int)dt.second() != (int)m_dt.second()) { m_dt = dt; repaint(); }
// Schedule next check (1/20 seconds)
setTimer(0,50);
}
else // Default handling of the mainframe (e.g. resize/move)
MMainFrame::OnTimerExpired();
}
ON_Resized // Adjust frame buttons to the new size
{
MMainFrame::OnResized();
MSizeElem h = Min(getSize().h/12, (MSizeElem)24);
minButton().setSize( MSize(Same,h) );
xButton ().setSize( MSize(Same,h) );
}
ON_Paint // Draws the clock (on a 100x100 pixel canvas)
{
// Prepare
// Automatically scale the 100x100 pixel canvas to the actucal window size
setDrawTransform(MTransform(ZeroPoint,getSize()/100));
// Font must be set after setDrawTransform so it would be scaled properly
setDrawTextSettings(MFont("Times New Roman",10,taBold));
// Draw outer frame
MColor bc = clOrange+clBlack+clBlack; // Base color for the frame
// Left
setFillSettings(bc-80, bc+80, 0);
fillPoly(MPoint(0,0), MPoint(10,10), MPoint(10,10), MPoint(10,90),
MPoint(10,90), MPoint(0,100), MPoint(0,100), MPoint(0,0));
// Top
setFillSettings(bc-80, bc+80, 90);
fillPoly(MPoint(0,0), MPoint(10,10), MPoint(10,10), MPoint(90,10),
MPoint(90,10), MPoint(100,0), MPoint(100,0), MPoint(0,0));
// Right
setFillSettings(bc-80, bc+80, 0);
fillPoly(MPoint(100,0), MPoint(90,10), MPoint(90,10), MPoint(90,90),
MPoint(90,90), MPoint(100,100), MPoint(100,100), MPoint(100,0));
// Bottom
setFillSettings(bc-80, bc+80, 90);
fillPoly(MPoint(0,100), MPoint(10,90), MPoint(10,90), MPoint(90,90),
MPoint(90,90), MPoint(100,100), MPoint(100,100), MPoint(0,100));
// Draw clock face
setFillSettings(clWhite, clOrange+clWhite+clWhite, 45);
fillRect(MRect(10,10,80,80));
// Draw markings (points and digits)
setFillSettings(clBlack);
for (int i = 0; i < 60; ++i)
{
double a = (double)i*6/57.3;
fillArc(MPoint(50+cos(a)*37,50-sin(a)*37), MSize(1,1)*(i%5?0.2:0.8));
if (i%5 == 0)
drawText(3<=i/5 ? 15-i/5 : 3-i/5,
MRect(MPoint(50+cos(a)*30,50-sin(a)*30),NoneSize));
}
// Draw hours handle
setDrawSettings(clBlack,3);
double a = (-(double(m_dt.hour())+double(m_dt.minute())/60)*30+90)/57.3;
drawPoly(MPoint(50,50), MPoint(50+cos(a)*20,50-sin(a)*20));
// Draw minutes handle
setDrawSettings(clBlack+50,2);
a = (-(double(m_dt.minute())+m_dt.second()/60)*6+90)/57.3;
drawPoly(MPoint(50,50), MPoint(50+cos(a)*28,50-sin(a)*28));
// Draw seconds handle
setDrawSettings(clRed-50,1);
a = (-floor(m_dt.second())*6+90)/57.3;
drawPoly(MPoint(50,50), MPoint(50+cos(a)*33,50-sin(a)*33));
// Draw handles' centerpiece
setFillSettings(clBlack);
fillArc(MPoint(50,50),MSize(4,4));
setFillSettings(clWhite,clGray,225);
fillArc(MPoint(50,50),MSize(2,2));
}
private:
MDateTime m_dt; // Needed to prevent redundant repaints (see OnTimerExpired)
};
void MAppMain() { ClockFrame().runMessageLoop(); } // Main function