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 */
14 typedef struct _CLOCKDATA
21 SYSTEMTIME stPrevious
;
23 } CLOCKDATA
, *PCLOCKDATA
;
26 #define TWOPI (2 * 3.14159)
28 static const WCHAR szClockWndClass
[] = L
"ClockWndClass";
31 RotatePoint(POINT pt
[], INT iNum
, INT iAngle
)
36 for (i
= 0 ; i
< iNum
; i
++)
38 ptTemp
.x
= (INT
) (pt
[i
].x
* cos (TWOPI
* iAngle
/ 360) +
39 pt
[i
].y
* sin (TWOPI
* iAngle
/ 360));
41 ptTemp
.y
= (INT
) (pt
[i
].y
* cos (TWOPI
* iAngle
/ 360) -
42 pt
[i
].x
* sin (TWOPI
* iAngle
/ 360));
50 DrawClock(HDC hdc
, PCLOCKDATA pClockData
)
57 /* grey brush to fill the dots */
58 hBrushOld
= SelectObject(hdc
, pClockData
->hGreyBrush
);
60 hPenOld
= GetCurrentObject(hdc
, OBJ_PEN
);
62 // TODO: check if this conversion is correct resp. usable
63 Radius
= min(pClockData
->cxClient
,pClockData
->cyClient
) * 2;
65 for (iAngle
= 0; iAngle
< 360; iAngle
+= 6)
71 /* rotate start coords */
72 RotatePoint(pt
, 1, iAngle
);
74 /* determine whether it's a big dot or a little dot
75 * i.e. 1-4 or 5, 6-9 or 10, 11-14 or 15 */
78 pt
[2].x
= pt
[2].y
= 7;
79 SelectObject(hdc
, pClockData
->hGreyPen
);
83 pt
[2].x
= pt
[2].y
= 16;
84 SelectObject(hdc
, GetStockObject(BLACK_PEN
));
87 pt
[0].x
-= pt
[2].x
/ 2;
88 pt
[0].y
-= pt
[2].y
/ 2;
90 pt
[1].x
= pt
[0].x
+ pt
[2].x
;
91 pt
[1].y
= pt
[0].y
+ pt
[2].y
;
93 Ellipse(hdc
, pt
[0].x
, pt
[0].y
, pt
[1].x
, pt
[1].y
);
96 SelectObject(hdc
, hBrushOld
);
97 SelectObject(hdc
, hPenOld
);
103 DrawHands(HDC hdc
, SYSTEMTIME
* pst
, BOOL fChange
, INT Radius
)
105 POINT pt
[3][5] = { {{0, (INT
)-Radius
/6}, {(INT
)Radius
/9, 0},
106 {0, (INT
)Radius
/1.8}, {(INT
)-Radius
/9, 0}, {0, (INT
)-Radius
/6}},
107 {{0, (INT
)-Radius
/4.5}, {(INT
)Radius
/18, 0}, {0, (INT
) Radius
*0.89},
108 {(INT
)-Radius
/18, 0}, {0, (INT
)-Radius
/4.5}},
109 {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, (INT
) Radius
*0.89}} };
113 /* Black pen for outline, white brush for fill */
114 SelectObject(hdc
, GetStockObject(BLACK_PEN
));
115 SelectObject(hdc
, GetStockObject(WHITE_BRUSH
));
117 iAngle
[0] = (pst
->wHour
* 30) % 360 + pst
->wMinute
/ 2;
118 iAngle
[1] = pst
->wMinute
* 6;
119 iAngle
[2] = pst
->wSecond
* 6;
121 CopyMemory(ptTemp
, pt
, sizeof(pt
));
123 for (i
= fChange
? 0 : 2; i
< 3; i
++)
125 RotatePoint(ptTemp
[i
], 5, iAngle
[i
]);
127 Polygon(hdc
, ptTemp
[i
], 5);
132 static LRESULT CALLBACK
133 ClockWndProc(HWND hwnd
,
138 PCLOCKDATA pClockData
;
142 pClockData
= (PCLOCKDATA
)GetWindowLongPtrW(hwnd
, GWLP_USERDATA
);
147 pClockData
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLOCKDATA
));
148 SetWindowLongPtrW(hwnd
, GWLP_USERDATA
, (LONG_PTR
)pClockData
);
150 pClockData
->hGreyPen
= CreatePen(PS_SOLID
, 1, RGB(128, 128, 128));
151 pClockData
->hGreyBrush
= CreateSolidBrush(RGB(128, 128, 128));
153 SetTimer(hwnd
, ID_TIMER
, 1000, NULL
);
154 pClockData
->bTimer
= TRUE
;
155 GetLocalTime(&pClockData
->stCurrent
);
156 pClockData
->stPrevious
= pClockData
->stCurrent
;
160 pClockData
->cxClient
= LOWORD(lParam
);
161 pClockData
->cyClient
= HIWORD(lParam
);
165 GetLocalTime(&pClockData
->stCurrent
);
166 InvalidateRect(hwnd
, NULL
, FALSE
);
167 pClockData
->stPrevious
= pClockData
->stCurrent
;
171 hdc
= BeginPaint(hwnd
, &ps
);
173 hdcMem
= CreateCompatibleDC(hdc
);
176 HBITMAP hBmp
, hBmpOld
;
178 hBmp
= CreateCompatibleBitmap(hdc
,
179 pClockData
->cxClient
,
180 pClockData
->cyClient
);
183 HBRUSH hWinBrush
, hWinBrushOld
;
187 hBmpOld
= SelectObject(hdcMem
, hBmp
);
189 hWinBrush
= GetSysColorBrush(COLOR_BTNFACE
);
190 hWinBrushOld
= SelectObject(hdcMem
, hWinBrush
);
194 pClockData
->cxClient
,
195 pClockData
->cyClient
,
198 oldMap
= SetMapMode(hdcMem
, MM_ISOTROPIC
);
199 SetWindowExtEx(hdcMem
, 3600, 2700, NULL
);
200 SetViewportExtEx(hdcMem
, 800, -600, NULL
);
201 SetViewportOrgEx(hdcMem
,
202 pClockData
->cxClient
/ 2,
203 pClockData
->cyClient
/ 2,
206 Radius
= DrawClock(hdcMem
, pClockData
);
207 DrawHands(hdcMem
, &pClockData
->stPrevious
, TRUE
, Radius
);
209 SetMapMode(hdcMem
, oldMap
);
210 SetViewportOrgEx(hdcMem
, oldOrg
.x
, oldOrg
.y
, NULL
);
215 pClockData
->cxClient
,
216 pClockData
->cyClient
,
222 SelectObject(hdcMem
, hWinBrushOld
);
223 SelectObject(hdcMem
, hBmpOld
);
234 DeleteObject(pClockData
->hGreyPen
);
235 DeleteObject(pClockData
->hGreyBrush
);
237 if (pClockData
->bTimer
)
238 KillTimer(hwnd
, ID_TIMER
);
240 HeapFree(GetProcessHeap(), 0, pClockData
);
244 if (pClockData
->bTimer
)
246 KillTimer(hwnd
, ID_TIMER
);
247 pClockData
->bTimer
= FALSE
;
252 if (!pClockData
->bTimer
)
254 SetTimer(hwnd
, ID_TIMER
, 1000, NULL
);
255 pClockData
->bTimer
= TRUE
;
271 RegisterClockControl(VOID
)
273 WNDCLASSEXW wc
= {0};
275 wc
.cbSize
= sizeof(WNDCLASSEXW
);
276 wc
.lpfnWndProc
= ClockWndProc
;
277 wc
.hInstance
= hApplet
;
278 wc
.hCursor
= LoadCursorW(NULL
, IDC_ARROW
);
279 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
280 wc
.lpszClassName
= szClockWndClass
;
282 return RegisterClassExW(&wc
) != (ATOM
)0;
287 UnregisterClockControl(VOID
)
289 UnregisterClassW(szClockWndClass
,