Changed my name, so update copyright info.
[wine] / programs / clock / winclock.c
1 /*
2  *  Clock (winclock.c)
3  *
4  *  Copyright 1998 by Marcel Baur <mbaur@g26.ethz.ch>
5  *
6  *  This file is based on  rolex.c  by Jim Peterson.
7  *
8  *  I just managed to move the relevant parts into the Clock application
9  *  and made it look like the original Windows one. You can find the original
10  *  rolex.c in the wine /libtest directory.
11  *
12  * This library is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public
14  * License as published by the Free Software Foundation; either
15  * version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with this library; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26 #include "config.h"
27 #include "wine/port.h"
28
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "windows.h"
33 #include "winclock.h"
34
35 #define Black  RGB(0,0,0)
36 #define Gray   RGB(128,128,128)
37 #define LtGray RGB(192,192,192)
38 #define White  RGB(255,255,255)
39
40 static const COLORREF FaceColor = LtGray;
41 static const COLORREF HandColor = White;
42 static const COLORREF TickColor = White;
43 static const COLORREF ShadowColor = Black;
44 static const COLORREF BackgroundColor = LtGray;
45
46 static const int SHADOW_DEPTH = 2;
47  
48 typedef struct
49 {
50     POINT Start;
51     POINT End;
52 } HandData;
53
54 HandData HourHand, MinuteHand, SecondHand;
55
56 static void DrawTicks(HDC dc, const POINT* centre, int radius)
57 {
58     int t;
59
60     /* Minute divisions */
61     if (radius>64)
62         for(t=0; t<60; t++) {
63             MoveToEx(dc,
64                      centre->x + sin(t*M_PI/30)*0.9*radius,
65                      centre->y - cos(t*M_PI/30)*0.9*radius,
66                      NULL);
67             LineTo(dc,
68                    centre->x + sin(t*M_PI/30)*0.89*radius,
69                    centre->y - cos(t*M_PI/30)*0.89*radius);
70         }
71
72     /* Hour divisions */
73     for(t=0; t<12; t++) {
74
75         MoveToEx(dc,
76                  centre->x + sin(t*M_PI/6)*0.9*radius,
77                  centre->y - cos(t*M_PI/6)*0.9*radius,
78                  NULL);
79         LineTo(dc,
80                centre->x + sin(t*M_PI/6)*0.8*radius,
81                centre->y - cos(t*M_PI/6)*0.8*radius);
82     }
83 }
84
85 static void DrawFace(HDC dc, const POINT* centre, int radius)
86 {
87     /* Ticks */
88     SelectObject(dc, CreatePen(PS_SOLID, 2, ShadowColor));
89     OffsetWindowOrgEx(dc, -SHADOW_DEPTH, -SHADOW_DEPTH, NULL);
90     DrawTicks(dc, centre, radius);
91     DeleteObject(SelectObject(dc, CreatePen(PS_SOLID, 2, TickColor)));
92     OffsetWindowOrgEx(dc, SHADOW_DEPTH, SHADOW_DEPTH, NULL);
93     DrawTicks(dc, centre, radius);
94
95     DeleteObject(SelectObject(dc, GetStockObject(NULL_BRUSH)));
96     DeleteObject(SelectObject(dc, GetStockObject(NULL_PEN)));
97 }
98
99 static void DrawHand(HDC dc,HandData* hand)
100 {
101     MoveToEx(dc, hand->Start.x, hand->Start.y, NULL);
102     LineTo(dc, hand->End.x, hand->End.y);
103 }
104
105 static void DrawHands(HDC dc, BOOL bSeconds)
106 {
107     if (bSeconds) {
108 #if 0
109         SelectObject(dc, CreatePen(PS_SOLID, 1, ShadowColor));
110         OffsetWindowOrgEx(dc, -SHADOW_DEPTH, -SHADOW_DEPTH, NULL);
111         DrawHand(dc, &SecondHand);
112         DeleteObject(SelectObject(dc, CreatePen(PS_SOLID, 1, HandColor)));
113         OffsetWindowOrgEx(dc, SHADOW_DEPTH, SHADOW_DEPTH, NULL);
114 #else
115         SelectObject(dc, CreatePen(PS_SOLID, 1, HandColor));
116 #endif
117         DrawHand(dc, &SecondHand);
118         DeleteObject(SelectObject(dc, GetStockObject(NULL_PEN)));
119     }
120
121     SelectObject(dc, CreatePen(PS_SOLID, 4, ShadowColor));
122
123     OffsetWindowOrgEx(dc, -SHADOW_DEPTH, -SHADOW_DEPTH, NULL);
124     DrawHand(dc, &MinuteHand);
125     DrawHand(dc, &HourHand);
126
127     DeleteObject(SelectObject(dc, CreatePen(PS_SOLID, 4, HandColor)));
128     OffsetWindowOrgEx(dc, SHADOW_DEPTH, SHADOW_DEPTH, NULL);
129     DrawHand(dc, &MinuteHand);
130     DrawHand(dc, &HourHand);
131
132     DeleteObject(SelectObject(dc, GetStockObject(NULL_PEN)));
133 }
134
135 static void PositionHand(const POINT* centre, double length, double angle, HandData* hand)
136 {
137     hand->Start = *centre;
138     hand->End.x = centre->x + sin(angle)*length;
139     hand->End.y = centre->y - cos(angle)*length;
140 }
141
142 static void PositionHands(const POINT* centre, int radius, BOOL bSeconds)
143 {
144     SYSTEMTIME st;
145     double hour, minute, second;
146
147     /* 0 <= hour,minute,second < 2pi */
148     /* Adding the millisecond count makes the second hand move more smoothly */
149
150     GetLocalTime(&st);
151
152     second = st.wSecond + st.wMilliseconds/1000.0;
153     minute = st.wMinute + second/60.0;
154     hour   = st.wHour % 12 + minute/60.0;
155
156     PositionHand(centre, radius * 0.5,  hour/12   * 2*M_PI, &HourHand);
157     PositionHand(centre, radius * 0.65, minute/60 * 2*M_PI, &MinuteHand);
158     if (bSeconds)
159         PositionHand(centre, radius * 0.79, second/60 * 2*M_PI, &SecondHand);  
160 }
161
162 void AnalogClock(HDC dc, int x, int y, BOOL bSeconds)
163 {
164     POINT centre;
165     int radius;
166     
167     radius = min(x, y)/2 - SHADOW_DEPTH;
168     if (radius < 0)
169         return;
170
171     centre.x = x/2;
172     centre.y = y/2;
173
174     DrawFace(dc, &centre, radius);
175
176     PositionHands(&centre, radius, bSeconds);
177     DrawHands(dc, bSeconds);
178 }
179
180
181 HFONT SizeFont(HDC dc, int x, int y, BOOL bSeconds, const LOGFONT* font)
182 {
183     SIZE extent;
184     LOGFONT lf;
185     double xscale, yscale;
186     HFONT oldFont, newFont;
187     CHAR szTime[255];
188     int chars;
189
190     chars = GetTimeFormat(LOCALE_USER_DEFAULT, bSeconds ? 0 : TIME_NOSECONDS, NULL,
191                           NULL, szTime, sizeof (szTime));
192     if (!chars)
193         return 0;
194
195     --chars;
196
197     lf = *font;
198     lf.lfHeight = -20;
199
200     x -= 2 * SHADOW_DEPTH;
201     y -= 2 * SHADOW_DEPTH;
202
203     oldFont = SelectObject(dc, CreateFontIndirect(&lf));
204     GetTextExtentPoint(dc, szTime, chars, &extent);
205     DeleteObject(SelectObject(dc, oldFont));
206
207     xscale = (double)x/extent.cx;
208     yscale = (double)y/extent.cy;
209     lf.lfHeight *= min(xscale, yscale);    
210     newFont = CreateFontIndirect(&lf);
211
212     return newFont;
213 }
214
215 void DigitalClock(HDC dc, int x, int y, BOOL bSeconds, HFONT font)
216 {
217     SIZE extent;
218     HFONT oldFont;
219     CHAR szTime[255];
220     int chars;
221
222     chars = GetTimeFormat(LOCALE_USER_DEFAULT, bSeconds ? 0 : TIME_NOSECONDS, NULL,
223                   NULL, szTime, sizeof (szTime));
224     if (!chars)
225         return;
226     --chars;
227
228     oldFont = SelectObject(dc, font);
229     GetTextExtentPoint(dc, szTime, chars, &extent);
230
231     SetBkColor(dc, BackgroundColor);
232     SetTextColor(dc, ShadowColor);
233     TextOut(dc, (x - extent.cx)/2 + SHADOW_DEPTH, (y - extent.cy)/2 + SHADOW_DEPTH,
234             szTime, chars);
235     SetBkMode(dc, TRANSPARENT);
236
237     SetTextColor(dc, HandColor);
238     TextOut(dc, (x - extent.cx)/2, (y - extent.cy)/2, szTime, chars);
239
240     SelectObject(dc, oldFont);
241 }