2 * PROJECT: ReactOS Timedate Control Panel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/cpl/timedate/clock.c
5 * PURPOSE: Draws the analog clock
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
7 * Copyright 2007 Eric Kohl
10 /* Code based on clock.c from Programming Windows, Charles Petzold */
16 typedef struct _CLOCKDATA
23 SYSTEMTIME stPrevious
;
25 } CLOCKDATA
, *PCLOCKDATA
;
28 #define TWOPI (2 * 3.14159)
30 static const WCHAR szClockWndClass
[] = L
"ClockWndClass";
33 RotatePoint(POINT pt
[], INT iNum
, INT iAngle
)
38 for (i
= 0 ; i
< iNum
; i
++)
40 ptTemp
.x
= (INT
) (pt
[i
].x
* cos (TWOPI
* iAngle
/ 360) +
41 pt
[i
].y
* sin (TWOPI
* iAngle
/ 360));
43 ptTemp
.y
= (INT
) (pt
[i
].y
* cos (TWOPI
* iAngle
/ 360) -
44 pt
[i
].x
* sin (TWOPI
* iAngle
/ 360));
52 DrawClock(HDC hdc
, PCLOCKDATA pClockData
)
59 /* Grey brush to fill the dots */
60 hBrushOld
= SelectObject(hdc
, pClockData
->hGreyBrush
);
62 hPenOld
= GetCurrentObject(hdc
, OBJ_PEN
);
64 // TODO: Check if this conversion is correct resp. usable
65 Radius
= min(pClockData
->cxClient
,pClockData
->cyClient
) * 2;
67 for (iAngle
= 0; iAngle
< 360; iAngle
+= 6)
73 /* Rotate start coords */
74 RotatePoint(pt
, 1, iAngle
);
76 /* Determine whether it's a big dot or a little dot
77 * i.e. 1-4 or 5, 6-9 or 10, 11-14 or 15 */
80 pt
[2].x
= pt
[2].y
= 7;
81 SelectObject(hdc
, pClockData
->hGreyPen
);
85 pt
[2].x
= pt
[2].y
= 16;
86 SelectObject(hdc
, GetStockObject(BLACK_PEN
));
89 pt
[0].x
-= pt
[2].x
/ 2;
90 pt
[0].y
-= pt
[2].y
/ 2;
92 pt
[1].x
= pt
[0].x
+ pt
[2].x
;
93 pt
[1].y
= pt
[0].y
+ pt
[2].y
;
95 Ellipse(hdc
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
);
98 SelectObject(hdc
, hBrushOld
);
99 SelectObject(hdc
, hPenOld
);
105 DrawHands(HDC hdc
, SYSTEMTIME
* pst
, BOOL fChange
, INT Radius
)
107 POINT pt
[3][5] = { {{0, (INT
)-Radius
/6}, {(INT
)Radius
/9, 0},
108 {0, (INT
)Radius
/1.8}, {(INT
)-Radius
/9, 0}, {0, (INT
)-Radius
/6}},
109 {{0, (INT
)-Radius
/4.5}, {(INT
)Radius
/18, 0}, {0, (INT
) Radius
*0.89},
110 {(INT
)-Radius
/18, 0}, {0, (INT
)-Radius
/4.5}},
111 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, (INT
) Radius
*0.89}} };
115 /* Black pen for outline, white brush for fill */
116 SelectObject(hdc
, GetStockObject(BLACK_PEN
));
117 SelectObject(hdc
, GetStockObject(WHITE_BRUSH
));
119 iAngle
[0] = (pst
->wHour
* 30) % 360 + pst
->wMinute
/ 2;
120 iAngle
[1] = pst
->wMinute
* 6;
121 iAngle
[2] = pst
->wSecond
* 6;
123 CopyMemory(ptTemp
, pt
, sizeof(pt
));
125 for (i
= fChange
? 0 : 2; i
< 3; i
++)
127 RotatePoint(ptTemp
[i
], 5, iAngle
[i
]);
129 Polygon(hdc
, ptTemp
[i
], 5);
134 static LRESULT CALLBACK
135 ClockWndProc(HWND hwnd
,
140 PCLOCKDATA pClockData
;
144 pClockData
= (PCLOCKDATA
)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
149 pClockData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLOCKDATA
));
150 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, (LONG_PTR
)pClockData
);
152 pClockData
->hGreyPen
= CreatePen(PS_SOLID
, 1, RGB(128, 128, 128));
153 pClockData
->hGreyBrush
= CreateSolidBrush(RGB(128, 128, 128));
155 SetTimer(hwnd
, ID_TIMER
, 1000, NULL
);
156 pClockData
->bTimer
= TRUE
;
157 GetLocalTime(&pClockData
->stCurrent
);
158 pClockData
->stPrevious
= pClockData
->stCurrent
;
162 pClockData
->cxClient
= LOWORD(lParam
);
163 pClockData
->cyClient
= HIWORD(lParam
);
167 GetLocalTime(&pClockData
->stCurrent
);
168 InvalidateRect(hwnd
, NULL
, FALSE
);
169 pClockData
->stPrevious
= pClockData
->stCurrent
;
173 hdc
= BeginPaint(hwnd
, &ps
);
175 hdcMem
= CreateCompatibleDC(hdc
);
178 HBITMAP hBmp
, hBmpOld
;
180 hBmp
= CreateCompatibleBitmap(hdc
,
181 pClockData
->cxClient
,
182 pClockData
->cyClient
);
185 HBRUSH hWinBrush
, hWinBrushOld
;
189 hBmpOld
= SelectObject(hdcMem
, hBmp
);
191 hWinBrush
= GetSysColorBrush(COLOR_BTNFACE
);
192 hWinBrushOld
= SelectObject(hdcMem
, hWinBrush
);
196 pClockData
->cxClient
,
197 pClockData
->cyClient
,
200 oldMap
= SetMapMode(hdcMem
, MM_ISOTROPIC
);
201 SetWindowExtEx(hdcMem
, 3600, 2700, NULL
);
202 SetViewportExtEx(hdcMem
, 800, -600, NULL
);
203 SetViewportOrgEx(hdcMem
,
204 pClockData
->cxClient
/ 2,
205 pClockData
->cyClient
/ 2,
208 Radius
= DrawClock(hdcMem
, pClockData
);
209 DrawHands(hdcMem
, &pClockData
->stPrevious
, TRUE
, Radius
);
211 SetMapMode(hdcMem
, oldMap
);
212 SetViewportOrgEx(hdcMem
, oldOrg
.x
, oldOrg
.y
, NULL
);
217 pClockData
->cxClient
,
218 pClockData
->cyClient
,
224 SelectObject(hdcMem
, hWinBrushOld
);
225 SelectObject(hdcMem
, hBmpOld
);
236 DeleteObject(pClockData
->hGreyPen
);
237 DeleteObject(pClockData
->hGreyBrush
);
239 if (pClockData
->bTimer
)
240 KillTimer(hwnd
, ID_TIMER
);
242 HeapFree(GetProcessHeap(), 0, pClockData
);
246 if (pClockData
->bTimer
)
248 KillTimer(hwnd
, ID_TIMER
);
249 pClockData
->bTimer
= FALSE
;
254 if (!pClockData
->bTimer
)
256 SetTimer(hwnd
, ID_TIMER
, 1000, NULL
);
257 pClockData
->bTimer
= TRUE
;
273 RegisterClockControl(VOID
)
275 WNDCLASSEXW wc
= {0};
277 wc
.cbSize
= sizeof(WNDCLASSEXW
);
278 wc
.lpfnWndProc
= ClockWndProc
;
279 wc
.hInstance
= hApplet
;
280 wc
.hCursor
= LoadCursorW(NULL
, IDC_ARROW
);
281 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
282 wc
.lpszClassName
= szClockWndClass
;
284 return RegisterClassExW(&wc
) != (ATOM
)0;
289 UnregisterClockControl(VOID
)
291 UnregisterClassW(szClockWndClass
,