Last updated: 21. 2.1998, 0:52
<*/NOWARN:F*> MODULE AnaClock; (*----------------------------------------- ANACLOCK.C --- Analog Clock Program (c) Charles Petzold, 1996 AnaClock.mod --- Translation to Stony Brook Modula-2 (c) Peter Stadler, 1997 -----------------------------------------*) IMPORT WINUSER; IMPORT WINGDI; IMPORT WIN32; IMPORT WINX; IMPORT SYSTEM; IMPORT SysClock; IMPORT Str; IMPORT RealMath; IMPORT Lib; CONST ID_TIMER = 1; CONST TWOPI = 2.0 * 3.14159; CONST szAppName = "DigClock"; VAR cxClient : INTEGER; cyClient : INTEGER; (*static in WndProc *) dtPrevious : SysClock.DateTime; datetime : SysClock.DateTime; VAR hwnd : WIN32.HWND; msg : WINUSER.MSG; wc : WINUSER.WNDCLASSEX; iDHAngle : ARRAY[0..2] OF INTEGER; TYPE PTARRAY = ARRAY[0..2],[0..4] OF WIN32.POINT; VAR (* static in DrawHands *) pt : PTARRAY = { { {0, -150},{100, 0},{0, 600},{-100, 0},{0, -150} }, { {0, -200},{50, 0},{0, 800},{-50, 0},{0, -200} }, { {0, 0},{0, 0},{0, 0},{0, 0},{0, 800} } }; (*++++*****************************************************************) PROCEDURE SetIsotropic (hdc : WIN32.HDC; (**********************************************************************) cxClient : INTEGER; cyClient : INTEGER); BEGIN WINGDI.SetMapMode (hdc, WINGDI.MM_ISOTROPIC); WINGDI.SetWindowExtEx (hdc, 1000, 1000, WINX.NIL_SIZE); WINGDI.SetViewportExtEx (hdc, cxClient DIV 2, -cyClient DIV 2, WINX.NIL_SIZE); WINGDI.SetViewportOrgEx (hdc, cxClient DIV 2, cyClient DIV 2, WINX.NIL_POINT); END SetIsotropic; (*++++*****************************************************************) PROCEDURE RotatePoint (VAR pt : ARRAY OF WIN32.POINT; (**********************************************************************) iNum : INTEGER; iAngle : INTEGER); VAR i : INTEGER; ptTemp : WIN32.POINT; BEGIN FOR i := 0 TO iNum-1 DO ptTemp.x := VAL(INTEGER,FLOAT(pt[i].x) * RealMath.cos (TWOPI * FLOAT(iAngle)/ 360.) + FLOAT(pt[i].y) * RealMath.sin (TWOPI * FLOAT(iAngle)/ 360.)); ptTemp.y := VAL(INTEGER,FLOAT(pt[i].y) * RealMath.cos (TWOPI * FLOAT(iAngle)/ 360.) - FLOAT(pt[i].x) * RealMath.sin (TWOPI * FLOAT(iAngle)/ 360.)); pt[i] := ptTemp; END; END RotatePoint; (*++++*****************************************************************) PROCEDURE DrawClock (hdc : WIN32.HDC); (**********************************************************************) VAR iAngle : INTEGER; pt : ARRAY[0..2] OF WIN32.POINT; BEGIN FOR iAngle := 0 TO 360-1 BY 6 DO pt[0].x := 0; pt[0].y := 900; RotatePoint (pt, 1, iAngle); IF(iAngle REM 5 #0) THEN pt[2].x := 33; pt[2].y := 33; ELSE pt[2].x := 100; pt[2].y := 100; END; pt[0].x := pt[0].x - pt[2].x DIV 2; pt[0].y := pt[0].y - pt[2].y DIV 2; pt[1].x := pt[0].x + pt[2].x; pt[1].y := pt[0].y + pt[2].y; WINGDI.SelectObject (hdc, WINGDI.GetStockObject (WINGDI.BLACK_BRUSH)); WINGDI.Ellipse (hdc, pt[0].x, pt[0].y, pt[1].x, pt[1].y); END; END DrawClock; (*++++*****************************************************************) PROCEDURE DrawHands (hdc : WIN32.HDC; (**********************************************************************) datetime : SysClock.DateTime; bChange : BOOLEAN); VAR i : INTEGER; ptTemp: ARRAY[0..2],[0..4] OF WIN32.POINT; BEGIN iDHAngle[0] := (datetime.hour * 30) REM 360 + datetime.minute DIV 2; iDHAngle[1] := datetime.minute * 6; iDHAngle[2] := datetime.second * 6; Lib.Move(SYSTEM.ADR(pt),SYSTEM.ADR(ptTemp), SIZE(pt)); IF(bChange=TRUE) THEN FOR i := 0 TO 3-1 DO RotatePoint (ptTemp[i], 5, iDHAngle[i]); WINGDI.Polyline (hdc, ptTemp[i], 5); END; ELSE FOR i := 2 TO 3-1 DO RotatePoint (ptTemp[i], 5, iDHAngle[i]); WINGDI.Polyline (hdc, ptTemp[i], 5); END; END; END DrawHands; <*/PUSH*> %IF WIN32 %THEN <*/CALLS:WIN32SYSTEM*> %ELSE <*/CALLS:WINSYSTEM*> %END (*++++*****************************************************************) PROCEDURE WndProc (hwnd : WIN32.HWND; (**********************************************************************) iMsg : WIN32.UINT; wParam : WIN32.WPARAM; lParam : WIN32.LPARAM) : WIN32.LRESULT [EXPORT]; VAR hdc : WIN32.HDC; ps : WINUSER.PAINTSTRUCT; bChange: BOOLEAN; BEGIN CASE (iMsg) OF | WINUSER.WM_CREATE : SysClock.GetClock(datetime); dtPrevious := datetime; RETURN 0; | WINUSER.WM_SIZE : cxClient := WINUSER.LOWORD (lParam); cyClient := WINUSER.HIWORD (lParam); RETURN 0; | WINUSER.WM_TIMER : SysClock.GetClock(datetime); bChange := (datetime.hour # dtPrevious.hour) OR (datetime.minute # dtPrevious.minute); hdc := WINUSER.GetDC (hwnd); SetIsotropic (hdc, cxClient, cyClient); WINGDI.SelectObject (hdc, WINGDI.GetStockObject (WINGDI.WHITE_PEN)); DrawHands (hdc, dtPrevious, bChange); WINGDI.SelectObject (hdc, WINGDI.GetStockObject (WINGDI.BLACK_PEN)); DrawHands (hdc, datetime, TRUE); WINUSER.ReleaseDC (hwnd, hdc); dtPrevious := datetime; RETURN 0; | WINUSER.WM_PAINT : hdc := WINUSER.BeginPaint (hwnd, ps); SetIsotropic (hdc, cxClient, cyClient); DrawClock (hdc); DrawHands (hdc, dtPrevious, TRUE); WINUSER.EndPaint (hwnd, ps); RETURN 0; | WINUSER.WM_DESTROY : WINUSER.KillTimer (hwnd, ID_TIMER); WINUSER.PostQuitMessage (0); RETURN 0; ELSE RETURN WINUSER.DefWindowProc (hwnd, iMsg, wParam, lParam); END; END WndProc; <*/POP*> (*++++*****************************************************************) PROCEDURE InitApplication () : BOOLEAN; (**********************************************************************) VAR rc : CARDINAL; BEGIN wc.cbSize := SIZE(wc); wc.style := WINUSER.CS_HREDRAW BOR WINUSER.CS_VREDRAW; wc.lpfnWndProc := WndProc; wc.cbClsExtra := 0; wc.cbWndExtra := 0; wc.hInstance := WINX.Instance; wc.hIcon := NIL; wc.hCursor := WINUSER.LoadCursor (NIL, WINUSER.IDC_ARROW^); wc.hbrBackground := SYSTEM.CAST(WIN32.HBRUSH, WINGDI.GetStockObject (WINGDI.WHITE_BRUSH)); wc.lpszMenuName := NIL; wc.lpszClassName := SYSTEM.ADR(szAppName); wc.hIconSm := NIL; rc := WINUSER.RegisterClassEx(wc); RETURN rc#0; END InitApplication; (*++++*****************************************************************) PROCEDURE InitMainWindow () : BOOLEAN; (**********************************************************************) BEGIN hwnd := WINUSER.CreateWindow (szAppName, "Analog Clock: Translation to Stony Brook Modula-2", WINUSER.WS_OVERLAPPEDWINDOW, WINUSER.CW_USEDEFAULT, WINUSER.CW_USEDEFAULT, WINUSER.CW_USEDEFAULT, WINUSER.CW_USEDEFAULT, NIL, NIL, WINX.Instance, NIL); WHILE(WINUSER.SetTimer (hwnd, ID_TIMER, 1000, NIL)=0) DO WINUSER.MessageBox (hwnd, "Too many clocks or timers!", szAppName, WINUSER.MB_ICONEXCLAMATION BOR WINUSER.MB_OK); RETURN FALSE; END; WINUSER.ShowWindow (hwnd, WINUSER.SW_SHOWNOACTIVATE); (*????*) WINUSER.UpdateWindow (hwnd); RETURN TRUE; END InitMainWindow; BEGIN IF InitApplication() AND InitMainWindow() THEN WHILE (WINUSER.GetMessage(msg,NIL,0,0)) DO WINUSER.TranslateMessage(msg); WINUSER.DispatchMessage(msg); END; END; END AnaClock.