Commit | Line | Data |
---|---|---|
d144e4a3 AP |
1 | /* Month calendar control |
2 | ||
a867030e | 3 | * |
b2e91b6a | 4 | * Copyright 1998, 1999 Eric Kohl (ekohl@abo.rhein-zeitung.de) |
b7c84d3b AJ |
5 | * Copyright 1999 Alex Priem (alexp@sci.kun.nl) |
6 | * Copyright 1999 Chris Morgan <cmorgan@wpi.edu> and | |
7 | * James Abbatiello <abbeyj@wpi.edu> | |
b0067efa | 8 | * Copyright 2000 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> |
a867030e | 9 | * |
0799c1a7 AJ |
10 | * This library is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Lesser General Public | |
12 | * License as published by the Free Software Foundation; either | |
13 | * version 2.1 of the License, or (at your option) any later version. | |
14 | * | |
15 | * This library is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
18 | * Lesser General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU Lesser General Public | |
21 | * License along with this library; if not, write to the Free Software | |
360a3f91 | 22 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
0799c1a7 | 23 | * |
5d0366f5 DP |
24 | * NOTE |
25 | * | |
26 | * This code was audited for completeness against the documented features | |
27 | * of Comctl32.dll version 6.0 on Oct. 20, 2004, by Dimitrie O. Paun. | |
28 | * | |
29 | * Unless otherwise noted, we believe this code to be complete, as per | |
30 | * the specification mentioned above. | |
31 | * If you discover missing features, or bugs, please note them below. | |
32 | * | |
a867030e | 33 | * TODO: |
5d0366f5 DP |
34 | * -- MCM_[GS]ETUNICODEFORMAT |
35 | * -- MONTHCAL_GetMonthRange | |
5d0366f5 DP |
36 | * -- handle resources better (doesn't work now); |
37 | * -- take care of internationalization. | |
38 | * -- keyboard handling. | |
39 | * -- GetRange: At the moment, we copy ranges anyway, regardless of | |
93416cda | 40 | * infoPtr->rangeValid; an invalid range is simply filled |
5d0366f5 DP |
41 | * with zeros in SetRange. Is this the right behavior? |
42 | * -- search for FIXME | |
a867030e EK |
43 | */ |
44 | ||
0bb2e5ab | 45 | #include <math.h> |
e37c6e18 | 46 | #include <stdarg.h> |
d3e22d9d | 47 | #include <stdio.h> |
908464d4 | 48 | #include <stdlib.h> |
f4d5fefb | 49 | #include <string.h> |
0bb2e5ab | 50 | |
d3e22d9d | 51 | #include "windef.h" |
e37c6e18 | 52 | #include "winbase.h" |
d3e22d9d | 53 | #include "wingdi.h" |
b2e91b6a | 54 | #include "winuser.h" |
b2e91b6a | 55 | #include "winnls.h" |
a867030e | 56 | #include "commctrl.h" |
b2e91b6a | 57 | #include "comctl32.h" |
25464cee FR |
58 | #include "uxtheme.h" |
59 | #include "tmschema.h" | |
30a66a05 | 60 | #include "wine/unicode.h" |
0799c1a7 | 61 | #include "wine/debug.h" |
a867030e | 62 | |
0799c1a7 | 63 | WINE_DEFAULT_DEBUG_CHANNEL(monthcal); |
b4b9fae6 | 64 | |
70c9e095 AJ |
65 | #define MC_SEL_LBUTUP 1 /* Left button released */ |
66 | #define MC_SEL_LBUTDOWN 2 /* Left button pressed in calendar */ | |
67 | #define MC_PREVPRESSED 4 /* Prev month button pressed */ | |
68 | #define MC_NEXTPRESSED 8 /* Next month button pressed */ | |
69 | #define MC_NEXTMONTHDELAY 350 /* when continuously pressing `next */ | |
70 | /* month', wait 500 ms before going */ | |
71 | /* to the next month */ | |
72 | #define MC_NEXTMONTHTIMER 1 /* Timer ID's */ | |
9a624916 | 73 | #define MC_PREVMONTHTIMER 2 |
70c9e095 | 74 | |
30a66a05 DP |
75 | #define countof(arr) (sizeof(arr)/sizeof(arr[0])) |
76 | ||
70c9e095 AJ |
77 | typedef struct |
78 | { | |
00176e33 | 79 | HWND hwndSelf; |
70c9e095 AJ |
80 | COLORREF bk; |
81 | COLORREF txt; | |
82 | COLORREF titlebk; | |
83 | COLORREF titletxt; | |
84 | COLORREF monthbk; | |
85 | COLORREF trailingtxt; | |
86 | HFONT hFont; | |
87 | HFONT hBoldFont; | |
88 | int textHeight; | |
89 | int textWidth; | |
90 | int height_increment; | |
91 | int width_increment; | |
70c9e095 AJ |
92 | int firstDayplace; /* place of the first day of the current month */ |
93 | int delta; /* scroll rate; # of months that the */ | |
94 | /* control moves when user clicks a scroll button */ | |
95 | int visible; /* # of months visible */ | |
96 | int firstDay; /* Start month calendar with firstDay's day */ | |
6fb16fca | 97 | int firstDayHighWord; /* High word only used externally */ |
70c9e095 AJ |
98 | int monthRange; |
99 | MONTHDAYSTATE *monthdayState; | |
100 | SYSTEMTIME todaysDate; | |
101 | DWORD currentMonth; | |
102 | DWORD currentYear; | |
103 | int status; /* See MC_SEL flags */ | |
104 | int curSelDay; /* current selected day */ | |
105 | int firstSelDay; /* first selected day */ | |
106 | int maxSelCount; | |
107 | SYSTEMTIME minSel; | |
108 | SYSTEMTIME maxSel; | |
109 | DWORD rangeValid; | |
110 | SYSTEMTIME minDate; | |
111 | SYSTEMTIME maxDate; | |
9a624916 | 112 | |
70c9e095 AJ |
113 | RECT title; /* rect for the header above the calendar */ |
114 | RECT titlebtnnext; /* the `next month' button in the header */ | |
9a624916 | 115 | RECT titlebtnprev; /* the `prev month' button in the header */ |
70c9e095 AJ |
116 | RECT titlemonth; /* the `month name' txt in the header */ |
117 | RECT titleyear; /* the `year number' txt in the header */ | |
b0067efa UB |
118 | RECT wdays; /* week days at top */ |
119 | RECT days; /* calendar area */ | |
70c9e095 | 120 | RECT weeknums; /* week numbers at left side */ |
b0067efa | 121 | RECT todayrect; /* `today: xx/xx/xx' text rect */ |
c5940433 | 122 | HWND hwndNotify; /* Window to receive the notifications */ |
b0067efa UB |
123 | HWND hWndYearEdit; /* Window Handle of edit box to handle years */ |
124 | HWND hWndYearUpDown;/* Window Handle of updown box to handle years */ | |
70c9e095 AJ |
125 | } MONTHCAL_INFO, *LPMONTHCAL_INFO; |
126 | ||
127 | ||
a6659d26 | 128 | /* Offsets of days in the week to the weekday of january 1 in a leap year */ |
afa43155 | 129 | static const int DayOfWeekTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; |
b2e91b6a | 130 | |
25464cee | 131 | static const WCHAR themeClass[] = { 'S','c','r','o','l','l','b','a','r',0 }; |
b2e91b6a | 132 | |
cdb263e5 | 133 | #define MONTHCAL_GetInfoPtr(hwnd) ((MONTHCAL_INFO *)GetWindowLongPtrW(hwnd, 0)) |
a867030e | 134 | |
0bb2e5ab AJ |
135 | /* helper functions */ |
136 | ||
b0067efa | 137 | /* returns the number of days in any given month, checking for leap days */ |
0bb2e5ab | 138 | /* january is 1, december is 12 */ |
b0067efa | 139 | int MONTHCAL_MonthLength(int month, int year) |
0bb2e5ab | 140 | { |
882bc4d1 | 141 | const int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}; |
cd8d181a | 142 | /*Wrap around, this eases handling*/ |
b0067efa UB |
143 | if(month == 0) |
144 | month = 12; | |
145 | if(month == 13) | |
146 | month = 1; | |
147 | ||
0bb2e5ab AJ |
148 | /* if we have a leap year add 1 day to February */ |
149 | /* a leap year is a year either divisible by 400 */ | |
150 | /* or divisible by 4 and not by 100 */ | |
151 | if(month == 2) { /* February */ | |
152 | return mdays[month - 1] + ((year%400 == 0) ? 1 : ((year%100 != 0) && | |
b7c84d3b | 153 | (year%4 == 0)) ? 1 : 0); |
0bb2e5ab AJ |
154 | } |
155 | else { | |
156 | return mdays[month - 1]; | |
157 | } | |
158 | } | |
b2e91b6a AP |
159 | |
160 | ||
0bb2e5ab | 161 | /* make sure that time is valid */ |
9a624916 | 162 | static int MONTHCAL_ValidateTime(SYSTEMTIME time) |
b2e91b6a | 163 | { |
bc2b9e3f | 164 | if(time.wMonth < 1 || time.wMonth > 12 ) return FALSE; |
b7c84d3b AJ |
165 | if(time.wDayOfWeek > 6) return FALSE; |
166 | if(time.wDay > MONTHCAL_MonthLength(time.wMonth, time.wYear)) | |
167 | return FALSE; | |
b7c84d3b | 168 | |
0bb2e5ab | 169 | return TRUE; |
b2e91b6a AP |
170 | } |
171 | ||
b2e91b6a | 172 | |
9a624916 | 173 | /* Note:Depending on DST, this may be offset by a day. |
b2e91b6a AP |
174 | Need to find out if we're on a DST place & adjust the clock accordingly. |
175 | Above function assumes we have a valid data. | |
0bb2e5ab | 176 | Valid for year>1752; 1 <= d <= 31, 1 <= m <= 12. |
a6659d26 | 177 | 0 = Sunday. |
b2e91b6a AP |
178 | */ |
179 | ||
a6659d26 | 180 | /* returns the day in the week(0 == sunday, 6 == saturday) */ |
0bb2e5ab | 181 | /* day(1 == 1st, 2 == 2nd... etc), year is the year value */ |
70c9e095 | 182 | static int MONTHCAL_CalculateDayOfWeek(DWORD day, DWORD month, DWORD year) |
b2e91b6a | 183 | { |
b7c84d3b | 184 | year-=(month < 3); |
0bb2e5ab | 185 | |
9a624916 | 186 | return((year + year/4 - year/100 + year/400 + |
a6659d26 | 187 | DayOfWeekTable[month-1] + day ) % 7); |
b2e91b6a AP |
188 | } |
189 | ||
b0067efa UB |
190 | /* From a given point, calculate the row (weekpos), column(daypos) |
191 | and day in the calendar. day== 0 mean the last day of tha last month | |
192 | */ | |
a8a469c7 | 193 | static int MONTHCAL_CalcDayFromPos(const MONTHCAL_INFO *infoPtr, int x, int y, |
9a624916 | 194 | int *daypos,int *weekpos) |
b2e91b6a | 195 | { |
b0067efa | 196 | int retval, firstDay; |
00176e33 DT |
197 | RECT rcClient; |
198 | ||
199 | GetClientRect(infoPtr->hwndSelf, &rcClient); | |
b2e91b6a | 200 | |
0bb2e5ab | 201 | /* if the point is outside the x bounds of the window put |
62253b75 | 202 | it at the boundary */ |
00176e33 DT |
203 | if (x > rcClient.right) |
204 | x = rcClient.right; | |
205 | ||
b2e91b6a | 206 | |
b0067efa UB |
207 | *daypos = (x - infoPtr->days.left ) / infoPtr->width_increment; |
208 | *weekpos = (y - infoPtr->days.top ) / infoPtr->height_increment; | |
9a624916 | 209 | |
b0067efa UB |
210 | firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear)+6 - infoPtr->firstDay)%7; |
211 | retval = *daypos + (7 * *weekpos) - firstDay; | |
0bb2e5ab AJ |
212 | return retval; |
213 | } | |
214 | ||
215 | /* day is the day of the month, 1 == 1st day of the month */ | |
216 | /* sets x and y to be the position of the day */ | |
b0067efa | 217 | /* x == day, y == week where(0,0) == firstDay, 1st week */ |
a8a469c7 | 218 | static void MONTHCAL_CalcDayXY(const MONTHCAL_INFO *infoPtr, int day, int month, |
b2e91b6a | 219 | int *x, int *y) |
b2e91b6a | 220 | { |
b7c84d3b | 221 | int firstDay, prevMonth; |
b2e91b6a | 222 | |
b0067efa | 223 | firstDay = (MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear) +6 - infoPtr->firstDay)%7; |
0bb2e5ab | 224 | |
b7c84d3b | 225 | if(month==infoPtr->currentMonth) { |
0bb2e5ab AJ |
226 | *x = (day + firstDay) % 7; |
227 | *y = (day + firstDay - *x) / 7; | |
228 | return; | |
229 | } | |
b7c84d3b | 230 | if(month < infoPtr->currentMonth) { |
0bb2e5ab | 231 | prevMonth = month - 1; |
b7c84d3b | 232 | if(prevMonth==0) |
0bb2e5ab | 233 | prevMonth = 12; |
9a624916 | 234 | |
0bb2e5ab AJ |
235 | *x = (MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) - firstDay) % 7; |
236 | *y = 0; | |
237 | return; | |
238 | } | |
239 | ||
240 | *y = MONTHCAL_MonthLength(month, infoPtr->currentYear - 1) / 7; | |
241 | *x = (day + firstDay + MONTHCAL_MonthLength(month, | |
242 | infoPtr->currentYear)) % 7; | |
b2e91b6a AP |
243 | } |
244 | ||
245 | ||
0bb2e5ab | 246 | /* x: column(day), y: row(week) */ |
a8a469c7 | 247 | static void MONTHCAL_CalcDayRect(const MONTHCAL_INFO *infoPtr, RECT *r, int x, int y) |
b2e91b6a | 248 | { |
b0067efa | 249 | r->left = infoPtr->days.left + x * infoPtr->width_increment; |
0bb2e5ab | 250 | r->right = r->left + infoPtr->width_increment; |
b0067efa | 251 | r->top = infoPtr->days.top + y * infoPtr->height_increment; |
b2e91b6a | 252 | r->bottom = r->top + infoPtr->textHeight; |
b2e91b6a AP |
253 | } |
254 | ||
0bb2e5ab AJ |
255 | |
256 | /* sets the RECT struct r to the rectangle around the day and month */ | |
257 | /* day is the day value of the month(1 == 1st), month is the month */ | |
258 | /* value(january == 1, december == 12) */ | |
a8a469c7 | 259 | static inline void MONTHCAL_CalcPosFromDay(const MONTHCAL_INFO *infoPtr, |
b2e91b6a | 260 | int day, int month, RECT *r) |
b2e91b6a | 261 | { |
b7c84d3b | 262 | int x, y; |
b2e91b6a | 263 | |
b7c84d3b AJ |
264 | MONTHCAL_CalcDayXY(infoPtr, day, month, &x, &y); |
265 | MONTHCAL_CalcDayRect(infoPtr, r, x, y); | |
b2e91b6a AP |
266 | } |
267 | ||
268 | ||
0bb2e5ab AJ |
269 | /* day is the day in the month(1 == 1st of the month) */ |
270 | /* month is the month value(1 == january, 12 == december) */ | |
a8a469c7 | 271 | static void MONTHCAL_CircleDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month) |
b2e91b6a | 272 | { |
b7c84d3b AJ |
273 | HPEN hRedPen = CreatePen(PS_SOLID, 2, RGB(255, 0, 0)); |
274 | HPEN hOldPen2 = SelectObject(hdc, hRedPen); | |
0bb2e5ab | 275 | POINT points[13]; |
b7c84d3b | 276 | int x, y; |
0bb2e5ab | 277 | RECT day_rect; |
b2e91b6a | 278 | |
b2e91b6a | 279 | |
b7c84d3b | 280 | MONTHCAL_CalcPosFromDay(infoPtr, day, month, &day_rect); |
b2e91b6a | 281 | |
0bb2e5ab AJ |
282 | x = day_rect.left; |
283 | y = day_rect.top; | |
9a624916 | 284 | |
0bb2e5ab AJ |
285 | points[0].x = x; |
286 | points[0].y = y - 1; | |
287 | points[1].x = x + 0.8 * infoPtr->width_increment; | |
288 | points[1].y = y - 1; | |
289 | points[2].x = x + 0.9 * infoPtr->width_increment; | |
290 | points[2].y = y; | |
291 | points[3].x = x + infoPtr->width_increment; | |
b0067efa | 292 | points[3].y = y + 0.5 * infoPtr->height_increment; |
9a624916 | 293 | |
0bb2e5ab | 294 | points[4].x = x + infoPtr->width_increment; |
b0067efa | 295 | points[4].y = y + 0.9 * infoPtr->height_increment; |
0bb2e5ab | 296 | points[5].x = x + 0.6 * infoPtr->width_increment; |
b0067efa | 297 | points[5].y = y + 0.9 * infoPtr->height_increment; |
0bb2e5ab | 298 | points[6].x = x + 0.5 * infoPtr->width_increment; |
b0067efa | 299 | points[6].y = y + 0.9 * infoPtr->height_increment; /* bring the bottom up just |
0bb2e5ab | 300 | a hair to fit inside the day rectangle */ |
9a624916 | 301 | |
0bb2e5ab | 302 | points[7].x = x + 0.2 * infoPtr->width_increment; |
b0067efa | 303 | points[7].y = y + 0.8 * infoPtr->height_increment; |
0bb2e5ab | 304 | points[8].x = x + 0.1 * infoPtr->width_increment; |
b0067efa | 305 | points[8].y = y + 0.8 * infoPtr->height_increment; |
0bb2e5ab | 306 | points[9].x = x; |
b0067efa | 307 | points[9].y = y + 0.5 * infoPtr->height_increment; |
0bb2e5ab AJ |
308 | |
309 | points[10].x = x + 0.1 * infoPtr->width_increment; | |
b0067efa | 310 | points[10].y = y + 0.2 * infoPtr->height_increment; |
0bb2e5ab | 311 | points[11].x = x + 0.2 * infoPtr->width_increment; |
b0067efa UB |
312 | points[11].y = y + 0.3 * infoPtr->height_increment; |
313 | points[12].x = x + 0.4 * infoPtr->width_increment; | |
314 | points[12].y = y + 0.2 * infoPtr->height_increment; | |
9a624916 | 315 | |
b7c84d3b AJ |
316 | PolyBezier(hdc, points, 13); |
317 | DeleteObject(hRedPen); | |
318 | SelectObject(hdc, hOldPen2); | |
0bb2e5ab | 319 | } |
b2e91b6a AP |
320 | |
321 | ||
a8a469c7 | 322 | static void MONTHCAL_DrawDay(const MONTHCAL_INFO *infoPtr, HDC hdc, int day, int month, |
043c3e79 | 323 | int x, int y, int bold) |
b2e91b6a | 324 | { |
30a66a05 DP |
325 | static const WCHAR fmtW[] = { '%','d',0 }; |
326 | WCHAR buf[10]; | |
b2e91b6a | 327 | RECT r; |
b7c84d3b | 328 | static int haveBoldFont, haveSelectedDay = FALSE; |
0bb2e5ab | 329 | HBRUSH hbr; |
0bb2e5ab AJ |
330 | COLORREF oldCol = 0; |
331 | COLORREF oldBk = 0; | |
b2e91b6a | 332 | |
30a66a05 | 333 | wsprintfW(buf, fmtW, day); |
b2e91b6a | 334 | |
9a624916 | 335 | /* No need to check styles: when selection is not valid, it is set to zero. |
c2a7914d | 336 | * 1<day<31, so everything is OK. |
b2e91b6a AP |
337 | */ |
338 | ||
b7c84d3b | 339 | MONTHCAL_CalcDayRect(infoPtr, &r, x, y); |
b2e91b6a | 340 | |
b7c84d3b | 341 | if((day>=infoPtr->minSel.wDay) && (day<=infoPtr->maxSel.wDay) |
0bb2e5ab AJ |
342 | && (month==infoPtr->currentMonth)) { |
343 | HRGN hrgn; | |
344 | RECT r2; | |
345 | ||
b7c84d3b | 346 | TRACE("%d %d %d\n",day, infoPtr->minSel.wDay, infoPtr->maxSel.wDay); |
39804012 | 347 | TRACE("%s\n", wine_dbgstr_rect(&r)); |
b7c84d3b AJ |
348 | oldCol = SetTextColor(hdc, infoPtr->monthbk); |
349 | oldBk = SetBkColor(hdc, infoPtr->trailingtxt); | |
350 | hbr = GetSysColorBrush(COLOR_GRAYTEXT); | |
351 | hrgn = CreateEllipticRgn(r.left, r.top, r.right, r.bottom); | |
352 | FillRgn(hdc, hrgn, hbr); | |
0bb2e5ab AJ |
353 | |
354 | /* FIXME: this may need to be changed now b/c of the other | |
355 | drawing changes 11/3/99 CMM */ | |
356 | r2.left = r.left - 0.25 * infoPtr->textWidth; | |
357 | r2.top = r.top; | |
358 | r2.right = r.left + 0.5 * infoPtr->textWidth; | |
359 | r2.bottom = r.bottom; | |
b7c84d3b | 360 | if(haveSelectedDay) FillRect(hdc, &r2, hbr); |
0bb2e5ab AJ |
361 | haveSelectedDay = TRUE; |
362 | } else { | |
363 | haveSelectedDay = FALSE; | |
364 | } | |
b2e91b6a | 365 | |
0bb2e5ab | 366 | /* need to add some code for multiple selections */ |
b2e91b6a | 367 | |
b7c84d3b AJ |
368 | if((bold) &&(!haveBoldFont)) { |
369 | SelectObject(hdc, infoPtr->hBoldFont); | |
0bb2e5ab AJ |
370 | haveBoldFont = TRUE; |
371 | } | |
b7c84d3b AJ |
372 | if((!bold) &&(haveBoldFont)) { |
373 | SelectObject(hdc, infoPtr->hFont); | |
0bb2e5ab AJ |
374 | haveBoldFont = FALSE; |
375 | } | |
376 | ||
b7c84d3b | 377 | if(haveSelectedDay) { |
0bb2e5ab AJ |
378 | SetTextColor(hdc, oldCol); |
379 | SetBkColor(hdc, oldBk); | |
380 | } | |
b2e91b6a | 381 | |
b0067efa | 382 | SetBkMode(hdc,TRANSPARENT); |
30a66a05 | 383 | DrawTextW(hdc, buf, -1, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); |
b2e91b6a | 384 | |
0bb2e5ab | 385 | /* draw a rectangle around the currently selected days text */ |
fbcc21be RS |
386 | if((day==infoPtr->curSelDay) && (month==infoPtr->currentMonth)) |
387 | DrawFocusRect(hdc, &r); | |
b2e91b6a AP |
388 | } |
389 | ||
390 | ||
a8a469c7 | 391 | static void paint_button (const MONTHCAL_INFO *infoPtr, HDC hdc, BOOL btnNext, |
25464cee FR |
392 | BOOL pressed, RECT* r) |
393 | { | |
394 | HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); | |
395 | ||
396 | if (theme) | |
397 | { | |
398 | static const int states[] = { | |
399 | /* Prev button */ | |
400 | ABS_LEFTNORMAL, ABS_LEFTPRESSED, ABS_LEFTDISABLED, | |
401 | /* Next button */ | |
402 | ABS_RIGHTNORMAL, ABS_RIGHTPRESSED, ABS_RIGHTDISABLED | |
403 | }; | |
404 | int stateNum = btnNext ? 3 : 0; | |
405 | if (pressed) | |
406 | stateNum += 1; | |
407 | else | |
408 | { | |
409 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); | |
410 | if (dwStyle & WS_DISABLED) stateNum += 2; | |
411 | } | |
412 | DrawThemeBackground (theme, hdc, SBP_ARROWBTN, states[stateNum], r, NULL); | |
413 | } | |
414 | else | |
415 | { | |
416 | int style = btnNext ? DFCS_SCROLLRIGHT : DFCS_SCROLLLEFT; | |
417 | if (pressed) | |
418 | style |= DFCS_PUSHED; | |
419 | else | |
420 | { | |
421 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); | |
422 | if (dwStyle & WS_DISABLED) style |= DFCS_INACTIVE; | |
423 | } | |
424 | ||
425 | DrawFrameControl(hdc, r, DFC_SCROLL, style); | |
426 | } | |
427 | } | |
428 | ||
429 | ||
a8a469c7 | 430 | static void MONTHCAL_Refresh(MONTHCAL_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps) |
b2e91b6a | 431 | { |
30a66a05 DP |
432 | static const WCHAR todayW[] = { 'T','o','d','a','y',':',0 }; |
433 | static const WCHAR fmt1W[] = { '%','s',' ','%','l','d',0 }; | |
434 | static const WCHAR fmt2W[] = { '%','s',' ','%','s',0 }; | |
435 | static const WCHAR fmt3W[] = { '%','d',0 }; | |
0bb2e5ab AJ |
436 | RECT *title=&infoPtr->title; |
437 | RECT *prev=&infoPtr->titlebtnprev; | |
438 | RECT *next=&infoPtr->titlebtnnext; | |
439 | RECT *titlemonth=&infoPtr->titlemonth; | |
440 | RECT *titleyear=&infoPtr->titleyear; | |
b7c84d3b AJ |
441 | RECT dayrect; |
442 | RECT *days=&dayrect; | |
b0067efa UB |
443 | RECT rtoday; |
444 | int i, j, m, mask, day, firstDay, weeknum, weeknum1,prevMonth; | |
bab7871c | 445 | int textHeight = infoPtr->textHeight; |
0bb2e5ab AJ |
446 | SIZE size; |
447 | HBRUSH hbr; | |
448 | HFONT currentFont; | |
30a66a05 DP |
449 | WCHAR buf[20]; |
450 | WCHAR buf1[20]; | |
451 | WCHAR buf2[32]; | |
b7c84d3b | 452 | COLORREF oldTextColor, oldBkColor; |
30bebfdc | 453 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); |
043c3e79 CM |
454 | RECT rcTemp; |
455 | RECT rcDay; /* used in MONTHCAL_CalcDayRect() */ | |
b0067efa UB |
456 | SYSTEMTIME localtime; |
457 | int startofprescal; | |
0bb2e5ab | 458 | |
cf67786e | 459 | oldTextColor = SetTextColor(hdc, comctl32_color.clrWindowText); |
b2e91b6a | 460 | |
b43639e7 CM |
461 | /* fill background */ |
462 | hbr = CreateSolidBrush (infoPtr->bk); | |
00176e33 | 463 | FillRect(hdc, &ps->rcPaint, hbr); |
9a624916 | 464 | DeleteObject(hbr); |
b2e91b6a | 465 | |
0bb2e5ab | 466 | /* draw header */ |
043c3e79 CM |
467 | if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) |
468 | { | |
469 | hbr = CreateSolidBrush(infoPtr->titlebk); | |
470 | FillRect(hdc, title, hbr); | |
b43639e7 | 471 | DeleteObject(hbr); |
043c3e79 | 472 | } |
9a624916 | 473 | |
0bb2e5ab | 474 | /* if the previous button is pressed draw it depressed */ |
043c3e79 | 475 | if(IntersectRect(&rcTemp, &(ps->rcPaint), prev)) |
25464cee | 476 | paint_button (infoPtr, hdc, FALSE, infoPtr->status & MC_PREVPRESSED, prev); |
0bb2e5ab | 477 | |
9a624916 | 478 | /* if next button is depressed draw it depressed */ |
043c3e79 | 479 | if(IntersectRect(&rcTemp, &(ps->rcPaint), next)) |
25464cee | 480 | paint_button (infoPtr, hdc, TRUE, infoPtr->status & MC_NEXTPRESSED, next); |
0bb2e5ab | 481 | |
b7c84d3b | 482 | oldBkColor = SetBkColor(hdc, infoPtr->titlebk); |
0bb2e5ab | 483 | SetTextColor(hdc, infoPtr->titletxt); |
b7c84d3b | 484 | currentFont = SelectObject(hdc, infoPtr->hBoldFont); |
0bb2e5ab | 485 | |
30a66a05 DP |
486 | GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+infoPtr->currentMonth -1, |
487 | buf1,countof(buf1)); | |
488 | wsprintfW(buf, fmt1W, buf1, infoPtr->currentYear); | |
9a624916 | 489 | |
320814fb | 490 | if(IntersectRect(&rcTemp, &(ps->rcPaint), title)) |
043c3e79 | 491 | { |
320814fb | 492 | DrawTextW(hdc, buf, strlenW(buf), title, |
b7c84d3b | 493 | DT_CENTER | DT_VCENTER | DT_SINGLELINE); |
043c3e79 CM |
494 | } |
495 | ||
b7c84d3b | 496 | /* titlemonth left/right contained rect for whole titletxt('June 1999') |
b2e91b6a | 497 | * MCM_HitTestInfo wants month & year rects, so prepare these now. |
9a624916 | 498 | *(no, we can't draw them separately; the whole text is centered) |
b2e91b6a | 499 | */ |
30a66a05 | 500 | GetTextExtentPoint32W(hdc, buf, strlenW(buf), &size); |
320814fb DC |
501 | titlemonth->left = title->right / 2 + title->left / 2 - size.cx / 2; |
502 | titleyear->right = title->right / 2 + title->left / 2 + size.cx / 2; | |
30a66a05 | 503 | GetTextExtentPoint32W(hdc, buf1, strlenW(buf1), &size); |
b7c84d3b | 504 | titlemonth->right = titlemonth->left + size.cx; |
b0067efa | 505 | titleyear->left = titlemonth->right; |
9a624916 | 506 | |
b0067efa UB |
507 | /* draw month area */ |
508 | rcTemp.top=infoPtr->wdays.top; | |
509 | rcTemp.left=infoPtr->wdays.left; | |
510 | rcTemp.bottom=infoPtr->todayrect.bottom; | |
511 | rcTemp.right =infoPtr->todayrect.right; | |
512 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcTemp)) | |
513 | { | |
514 | hbr = CreateSolidBrush(infoPtr->monthbk); | |
515 | FillRect(hdc, &rcTemp, hbr); | |
516 | DeleteObject(hbr); | |
517 | } | |
9a624916 | 518 | |
c2a7914d | 519 | /* draw line under day abbreviations */ |
b2e91b6a | 520 | |
b0067efa | 521 | MoveToEx(hdc, infoPtr->days.left + 3, title->bottom + textHeight + 1, NULL); |
00176e33 | 522 | LineTo(hdc, infoPtr->days.right - 3, title->bottom + textHeight + 1); |
9a624916 | 523 | |
b0067efa UB |
524 | prevMonth = infoPtr->currentMonth - 1; |
525 | if(prevMonth == 0) /* if currentMonth is january(1) prevMonth is */ | |
526 | prevMonth = 12; /* december(12) of the previous year */ | |
527 | ||
528 | infoPtr->wdays.left = infoPtr->days.left = infoPtr->weeknums.right; | |
b7c84d3b | 529 | /* draw day abbreviations */ |
b2e91b6a | 530 | |
320814fb | 531 | SelectObject(hdc, infoPtr->hFont); |
b7c84d3b | 532 | SetBkColor(hdc, infoPtr->monthbk); |
0bb2e5ab | 533 | SetTextColor(hdc, infoPtr->trailingtxt); |
b2e91b6a | 534 | |
b7c84d3b AJ |
535 | /* copy this rect so we can change the values without changing */ |
536 | /* the original version */ | |
b0067efa UB |
537 | days->left = infoPtr->wdays.left; |
538 | days->right = days->left + infoPtr->width_increment; | |
539 | days->top = infoPtr->wdays.top; | |
540 | days->bottom = infoPtr->wdays.bottom; | |
b7c84d3b | 541 | |
0bb2e5ab | 542 | i = infoPtr->firstDay; |
b2e91b6a | 543 | |
b7c84d3b | 544 | for(j=0; j<7; j++) { |
a6659d26 | 545 | GetLocaleInfoW( LOCALE_USER_DEFAULT,LOCALE_SABBREVDAYNAME1 + (i+j+6)%7, buf, countof(buf)); |
30a66a05 | 546 | DrawTextW(hdc, buf, strlenW(buf), days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); |
0bb2e5ab AJ |
547 | days->left+=infoPtr->width_increment; |
548 | days->right+=infoPtr->width_increment; | |
549 | } | |
b2e91b6a | 550 | |
b2e91b6a | 551 | /* draw day numbers; first, the previous month */ |
9a624916 | 552 | |
b7c84d3b | 553 | firstDay = MONTHCAL_CalculateDayOfWeek(1, infoPtr->currentMonth, infoPtr->currentYear); |
9a624916 VB |
554 | |
555 | day = MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear) + | |
b0067efa UB |
556 | (infoPtr->firstDay + 7 - firstDay)%7 + 1; |
557 | if (day > MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) | |
558 | day -=7; | |
559 | startofprescal = day; | |
0bb2e5ab AJ |
560 | mask = 1<<(day-1); |
561 | ||
562 | i = 0; | |
563 | m = 0; | |
b7c84d3b | 564 | while(day <= MONTHCAL_MonthLength(prevMonth, infoPtr->currentYear)) { |
043c3e79 CM |
565 | MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); |
566 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) | |
567 | { | |
30bebfdc | 568 | MONTHCAL_DrawDay(infoPtr, hdc, day, prevMonth, i, 0, |
0bb2e5ab | 569 | infoPtr->monthdayState[m] & mask); |
043c3e79 CM |
570 | } |
571 | ||
0bb2e5ab AJ |
572 | mask<<=1; |
573 | day++; | |
574 | i++; | |
575 | } | |
576 | ||
b2e91b6a AP |
577 | /* draw `current' month */ |
578 | ||
0bb2e5ab AJ |
579 | day = 1; /* start at the beginning of the current month */ |
580 | ||
581 | infoPtr->firstDayplace = i; | |
582 | SetTextColor(hdc, infoPtr->txt); | |
583 | m++; | |
584 | mask = 1; | |
585 | ||
586 | /* draw the first week of the current month */ | |
b7c84d3b | 587 | while(i<7) { |
043c3e79 CM |
588 | MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, 0); |
589 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) | |
590 | { | |
591 | ||
30bebfdc | 592 | MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, 0, |
0bb2e5ab AJ |
593 | infoPtr->monthdayState[m] & mask); |
594 | ||
043c3e79 CM |
595 | if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && |
596 | (day==infoPtr->todaysDate.wDay) && | |
597 | (infoPtr->currentYear == infoPtr->todaysDate.wYear)) { | |
b0067efa | 598 | if(!(dwStyle & MCS_NOTODAYCIRCLE)) |
30bebfdc | 599 | MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); |
043c3e79 | 600 | } |
0bb2e5ab AJ |
601 | } |
602 | ||
603 | mask<<=1; | |
604 | day++; | |
605 | i++; | |
606 | } | |
607 | ||
608 | j = 1; /* move to the 2nd week of the current month */ | |
609 | i = 0; /* move back to sunday */ | |
9a624916 | 610 | while(day <= MONTHCAL_MonthLength(infoPtr->currentMonth, infoPtr->currentYear)) { |
043c3e79 CM |
611 | MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); |
612 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) | |
613 | { | |
30bebfdc | 614 | MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth, i, j, |
0bb2e5ab AJ |
615 | infoPtr->monthdayState[m] & mask); |
616 | ||
043c3e79 CM |
617 | if((infoPtr->currentMonth==infoPtr->todaysDate.wMonth) && |
618 | (day==infoPtr->todaysDate.wDay) && | |
9a624916 VB |
619 | (infoPtr->currentYear == infoPtr->todaysDate.wYear)) |
620 | if(!(dwStyle & MCS_NOTODAYCIRCLE)) | |
30bebfdc | 621 | MONTHCAL_CircleDay(infoPtr, hdc, day, infoPtr->currentMonth); |
043c3e79 | 622 | } |
0bb2e5ab AJ |
623 | mask<<=1; |
624 | day++; | |
625 | i++; | |
b7c84d3b | 626 | if(i>6) { /* past saturday, goto the next weeks sunday */ |
0bb2e5ab AJ |
627 | i = 0; |
628 | j++; | |
629 | } | |
630 | } | |
b2e91b6a AP |
631 | |
632 | /* draw `next' month */ | |
633 | ||
0bb2e5ab AJ |
634 | day = 1; /* start at the first day of the next month */ |
635 | m++; | |
636 | mask = 1; | |
637 | ||
638 | SetTextColor(hdc, infoPtr->trailingtxt); | |
b7c84d3b | 639 | while((i<7) &&(j<6)) { |
043c3e79 CM |
640 | MONTHCAL_CalcDayRect(infoPtr, &rcDay, i, j); |
641 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rcDay)) | |
9a624916 | 642 | { |
30bebfdc | 643 | MONTHCAL_DrawDay(infoPtr, hdc, day, infoPtr->currentMonth + 1, i, j, |
0bb2e5ab | 644 | infoPtr->monthdayState[m] & mask); |
043c3e79 | 645 | } |
0bb2e5ab AJ |
646 | |
647 | mask<<=1; | |
648 | day++; | |
9a624916 | 649 | i++; |
b7c84d3b | 650 | if(i==7) { /* past saturday, go to next week's sunday */ |
0bb2e5ab AJ |
651 | i = 0; |
652 | j++; | |
653 | } | |
654 | } | |
655 | SetTextColor(hdc, infoPtr->txt); | |
b2e91b6a AP |
656 | |
657 | ||
658 | /* draw `today' date if style allows it, and draw a circle before today's | |
0bb2e5ab | 659 | * date if necessary */ |
b2e91b6a | 660 | |
b7c84d3b | 661 | if(!(dwStyle & MCS_NOTODAY)) { |
043c3e79 | 662 | if(!(dwStyle & MCS_NOTODAYCIRCLE)) { |
b0067efa | 663 | /*day is the number of days from nextmonth we put on the calendar */ |
30bebfdc | 664 | MONTHCAL_CircleDay(infoPtr, hdc, |
9a624916 | 665 | day+MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear), |
b0067efa | 666 | infoPtr->currentMonth); |
0bb2e5ab | 667 | } |
30a66a05 | 668 | if (!LoadStringW(COMCTL32_hModule,IDM_TODAY,buf1,countof(buf1))) |
b0067efa UB |
669 | { |
670 | WARN("Can't load resource\n"); | |
30a66a05 | 671 | strcpyW(buf1, todayW); |
b0067efa UB |
672 | } |
673 | MONTHCAL_CalcDayRect(infoPtr, &rtoday, 1, 6); | |
674 | MONTHCAL_CopyTime(&infoPtr->todaysDate,&localtime); | |
30a66a05 DP |
675 | GetDateFormatW(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&localtime,NULL,buf2,countof(buf2)); |
676 | wsprintfW(buf, fmt2W, buf1, buf2); | |
b7c84d3b | 677 | SelectObject(hdc, infoPtr->hBoldFont); |
043c3e79 | 678 | |
320814fb | 679 | DrawTextW(hdc, buf, -1, &rtoday, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE); |
b0067efa | 680 | if(IntersectRect(&rcTemp, &(ps->rcPaint), &rtoday)) |
043c3e79 | 681 | { |
30a66a05 | 682 | DrawTextW(hdc, buf, -1, &rtoday, DT_LEFT | DT_VCENTER | DT_SINGLELINE); |
043c3e79 | 683 | } |
b7c84d3b | 684 | SelectObject(hdc, infoPtr->hFont); |
0bb2e5ab | 685 | } |
b2e91b6a | 686 | |
9a624916 | 687 | /*eventually draw week numbers*/ |
b7c84d3b | 688 | if(dwStyle & MCS_WEEKNUMBERS) { |
0bb2e5ab | 689 | /* display weeknumbers*/ |
b0067efa UB |
690 | int mindays; |
691 | ||
692 | /* Rules what week to call the first week of a new year: | |
693 | LOCALE_IFIRSTWEEKOFYEAR == 0 (e.g US?): | |
694 | The week containing Jan 1 is the first week of year | |
9a624916 | 695 | LOCALE_IFIRSTWEEKOFYEAR == 2 (e.g. Germany): |
b0067efa UB |
696 | First week of year must contain 4 days of the new year |
697 | LOCALE_IFIRSTWEEKOFYEAR == 1 (what contries?) | |
698 | The first week of the year must contain only days of the new year | |
699 | */ | |
30a66a05 DP |
700 | GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTWEEKOFYEAR, buf, countof(buf)); |
701 | weeknum = atoiW(buf); | |
b0067efa UB |
702 | switch (weeknum) |
703 | { | |
704 | case 1: mindays = 6; | |
705 | break; | |
706 | case 2: mindays = 3; | |
707 | break; | |
708 | case 0: | |
709 | default: | |
710 | mindays = 0; | |
711 | } | |
712 | if (infoPtr->currentMonth < 2) | |
713 | { | |
714 | /* calculate all those exceptions for january */ | |
715 | weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); | |
9a624916 | 716 | if ((infoPtr->firstDay +7 - weeknum1)%7 > mindays) |
b0067efa UB |
717 | weeknum =1; |
718 | else | |
719 | { | |
720 | weeknum = 0; | |
9a624916 | 721 | for(i=0; i<11; i++) |
b0067efa UB |
722 | weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear-1); |
723 | weeknum +=startofprescal+ 7; | |
724 | weeknum /=7; | |
725 | weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear-1); | |
726 | if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) | |
727 | weeknum++; | |
728 | } | |
729 | } | |
730 | else | |
731 | { | |
732 | weeknum = 0; | |
9a624916 | 733 | for(i=0; i<prevMonth-1; i++) |
b0067efa UB |
734 | weeknum+=MONTHCAL_MonthLength(i+1, infoPtr->currentYear); |
735 | weeknum +=startofprescal+ 7; | |
736 | weeknum /=7; | |
737 | weeknum1=MONTHCAL_CalculateDayOfWeek(1,1,infoPtr->currentYear); | |
738 | if ((infoPtr->firstDay + 7 - weeknum1)%7 > mindays) | |
739 | weeknum++; | |
740 | } | |
741 | days->left = infoPtr->weeknums.left; | |
742 | days->right = infoPtr->weeknums.right; | |
743 | days->top = infoPtr->weeknums.top; | |
744 | days->bottom = days->top +infoPtr->height_increment; | |
b7c84d3b | 745 | for(i=0; i<6; i++) { |
b0067efa UB |
746 | if((i==0)&&(weeknum>50)) |
747 | { | |
30a66a05 | 748 | wsprintfW(buf, fmt3W, weeknum); |
b0067efa UB |
749 | weeknum=0; |
750 | } | |
751 | else if((i==5)&&(weeknum>47)) | |
752 | { | |
30a66a05 | 753 | wsprintfW(buf, fmt3W, 1); |
b0067efa UB |
754 | } |
755 | else | |
30a66a05 DP |
756 | wsprintfW(buf, fmt3W, weeknum + i); |
757 | DrawTextW(hdc, buf, -1, days, DT_CENTER | DT_VCENTER | DT_SINGLELINE ); | |
b0067efa UB |
758 | days->top+=infoPtr->height_increment; |
759 | days->bottom+=infoPtr->height_increment; | |
0bb2e5ab | 760 | } |
9a624916 | 761 | |
b0067efa UB |
762 | MoveToEx(hdc, infoPtr->weeknums.right, infoPtr->weeknums.top + 3 , NULL); |
763 | LineTo(hdc, infoPtr->weeknums.right, infoPtr->weeknums.bottom ); | |
9a624916 | 764 | |
0bb2e5ab | 765 | } |
0bb2e5ab | 766 | /* currentFont was font at entering Refresh */ |
b2e91b6a | 767 | |
b7c84d3b | 768 | SetBkColor(hdc, oldBkColor); |
9a624916 | 769 | SelectObject(hdc, currentFont); |
b7c84d3b | 770 | SetTextColor(hdc, oldTextColor); |
b2e91b6a AP |
771 | } |
772 | ||
773 | ||
9a624916 | 774 | static LRESULT |
a8a469c7 | 775 | MONTHCAL_GetMinReqRect(const MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 776 | { |
b7c84d3b | 777 | LPRECT lpRect = (LPRECT) lParam; |
30bebfdc DT |
778 | |
779 | TRACE("rect %p\n", lpRect); | |
9a624916 | 780 | |
b2e91b6a AP |
781 | /* validate parameters */ |
782 | ||
b7c84d3b | 783 | if((infoPtr==NULL) ||(lpRect == NULL) ) return FALSE; |
b2e91b6a | 784 | |
00176e33 DT |
785 | lpRect->left = infoPtr->title.left; |
786 | lpRect->top = infoPtr->title.top; | |
787 | lpRect->right = infoPtr->title.right; | |
788 | lpRect->bottom = infoPtr->todayrect.bottom; | |
30bebfdc | 789 | AdjustWindowRect(lpRect, GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE), FALSE); |
00176e33 DT |
790 | |
791 | TRACE("%s\n", wine_dbgstr_rect(lpRect)); | |
792 | ||
0bb2e5ab | 793 | return TRUE; |
b2e91b6a AP |
794 | } |
795 | ||
043c3e79 | 796 | |
9a624916 | 797 | static LRESULT |
a8a469c7 | 798 | MONTHCAL_GetColor(const MONTHCAL_INFO *infoPtr, WPARAM wParam) |
b2e91b6a | 799 | { |
30bebfdc | 800 | TRACE("\n"); |
0bb2e5ab | 801 | |
b7c84d3b | 802 | switch((int)wParam) { |
0bb2e5ab AJ |
803 | case MCSC_BACKGROUND: |
804 | return infoPtr->bk; | |
805 | case MCSC_TEXT: | |
806 | return infoPtr->txt; | |
807 | case MCSC_TITLEBK: | |
808 | return infoPtr->titlebk; | |
809 | case MCSC_TITLETEXT: | |
810 | return infoPtr->titletxt; | |
811 | case MCSC_MONTHBK: | |
812 | return infoPtr->monthbk; | |
813 | case MCSC_TRAILINGTEXT: | |
814 | return infoPtr->trailingtxt; | |
815 | } | |
816 | ||
817 | return -1; | |
b2e91b6a AP |
818 | } |
819 | ||
043c3e79 | 820 | |
9a624916 | 821 | static LRESULT |
30bebfdc | 822 | MONTHCAL_SetColor(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) |
b2e91b6a | 823 | { |
b7c84d3b | 824 | int prev = -1; |
0bb2e5ab | 825 | |
3c9e7a7f | 826 | TRACE("%ld: color %08lx\n", wParam, lParam); |
0bb2e5ab | 827 | |
b7c84d3b | 828 | switch((int)wParam) { |
0bb2e5ab AJ |
829 | case MCSC_BACKGROUND: |
830 | prev = infoPtr->bk; | |
831 | infoPtr->bk = (COLORREF)lParam; | |
832 | break; | |
833 | case MCSC_TEXT: | |
834 | prev = infoPtr->txt; | |
835 | infoPtr->txt = (COLORREF)lParam; | |
836 | break; | |
837 | case MCSC_TITLEBK: | |
838 | prev = infoPtr->titlebk; | |
839 | infoPtr->titlebk = (COLORREF)lParam; | |
840 | break; | |
841 | case MCSC_TITLETEXT: | |
842 | prev=infoPtr->titletxt; | |
843 | infoPtr->titletxt = (COLORREF)lParam; | |
844 | break; | |
845 | case MCSC_MONTHBK: | |
846 | prev = infoPtr->monthbk; | |
847 | infoPtr->monthbk = (COLORREF)lParam; | |
848 | break; | |
849 | case MCSC_TRAILINGTEXT: | |
850 | prev = infoPtr->trailingtxt; | |
851 | infoPtr->trailingtxt = (COLORREF)lParam; | |
852 | break; | |
853 | } | |
854 | ||
30bebfdc | 855 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
0bb2e5ab | 856 | return prev; |
b2e91b6a AP |
857 | } |
858 | ||
043c3e79 | 859 | |
9a624916 | 860 | static LRESULT |
a8a469c7 | 861 | MONTHCAL_GetMonthDelta(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 862 | { |
30bebfdc | 863 | TRACE("\n"); |
9a624916 | 864 | |
b7c84d3b | 865 | if(infoPtr->delta) |
0bb2e5ab AJ |
866 | return infoPtr->delta; |
867 | else | |
868 | return infoPtr->visible; | |
b2e91b6a AP |
869 | } |
870 | ||
043c3e79 | 871 | |
9a624916 | 872 | static LRESULT |
30bebfdc | 873 | MONTHCAL_SetMonthDelta(MONTHCAL_INFO *infoPtr, WPARAM wParam) |
b2e91b6a | 874 | { |
0bb2e5ab | 875 | int prev = infoPtr->delta; |
b2e91b6a | 876 | |
3c9e7a7f | 877 | TRACE("delta %ld\n", wParam); |
9a624916 | 878 | |
0bb2e5ab AJ |
879 | infoPtr->delta = (int)wParam; |
880 | return prev; | |
b2e91b6a AP |
881 | } |
882 | ||
883 | ||
9a624916 | 884 | static LRESULT |
a8a469c7 | 885 | MONTHCAL_GetFirstDayOfWeek(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 886 | { |
6fb16fca | 887 | return MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord); |
b2e91b6a AP |
888 | } |
889 | ||
b2e91b6a | 890 | |
0bb2e5ab | 891 | /* sets the first day of the week that will appear in the control */ |
a6659d26 | 892 | /* 0 == Sunday, 6 == Saturday */ |
0bb2e5ab AJ |
893 | /* FIXME: this needs to be implemented properly in MONTHCAL_Refresh() */ |
894 | /* FIXME: we need more error checking here */ | |
9a624916 | 895 | static LRESULT |
30bebfdc | 896 | MONTHCAL_SetFirstDayOfWeek(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 897 | { |
6fb16fca | 898 | int prev = MAKELONG(infoPtr->firstDay, infoPtr->firstDayHighWord); |
86ea6b58 | 899 | int localFirstDay; |
30a66a05 | 900 | WCHAR buf[40]; |
0bb2e5ab | 901 | |
30bebfdc | 902 | TRACE("day %ld\n", lParam); |
0bb2e5ab | 903 | |
86ea6b58 FA |
904 | GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_IFIRSTDAYOFWEEK, buf, countof(buf)); |
905 | TRACE("%s %d\n", debugstr_w(buf), strlenW(buf)); | |
906 | ||
907 | localFirstDay = atoiW(buf); | |
908 | ||
909 | if(lParam == -1) | |
6fb16fca LZ |
910 | { |
911 | infoPtr->firstDay = localFirstDay; | |
912 | infoPtr->firstDayHighWord = FALSE; | |
913 | } | |
86ea6b58 | 914 | else if(lParam >= 7) |
6fb16fca | 915 | { |
a7762476 | 916 | infoPtr->firstDay = 6; /* max first day allowed */ |
6fb16fca LZ |
917 | infoPtr->firstDayHighWord = TRUE; |
918 | } | |
b0067efa | 919 | else |
6fb16fca LZ |
920 | { |
921 | infoPtr->firstDay = lParam; | |
922 | infoPtr->firstDayHighWord = TRUE; | |
923 | } | |
86ea6b58 | 924 | |
0bb2e5ab | 925 | return prev; |
b2e91b6a AP |
926 | } |
927 | ||
928 | ||
b2e91b6a | 929 | static LRESULT |
a8a469c7 | 930 | MONTHCAL_GetMonthRange(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 931 | { |
30bebfdc | 932 | TRACE("\n"); |
0bb2e5ab | 933 | |
b2e91b6a AP |
934 | return infoPtr->monthRange; |
935 | } | |
936 | ||
0bb2e5ab | 937 | |
b2e91b6a | 938 | static LRESULT |
a8a469c7 | 939 | MONTHCAL_GetMaxTodayWidth(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 940 | { |
b0067efa | 941 | return(infoPtr->todayrect.right - infoPtr->todayrect.left); |
b2e91b6a AP |
942 | } |
943 | ||
0bb2e5ab | 944 | |
b2e91b6a | 945 | static LRESULT |
30bebfdc | 946 | MONTHCAL_SetRange(MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) |
b2e91b6a | 947 | { |
bc2b9e3f | 948 | SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *)lParam; |
97747453 | 949 | FILETIME ft_min, ft_max; |
bc2b9e3f | 950 | |
3c9e7a7f | 951 | TRACE("%lx %lx\n", wParam, lParam); |
bc2b9e3f VM |
952 | |
953 | if ((wParam & GDTR_MIN && !MONTHCAL_ValidateTime(lprgSysTimeArray[0])) || | |
954 | (wParam & GDTR_MAX && !MONTHCAL_ValidateTime(lprgSysTimeArray[1]))) | |
955 | return FALSE; | |
956 | ||
957 | if (wParam & GDTR_MIN) | |
958 | { | |
959 | MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minDate); | |
960 | infoPtr->rangeValid |= GDTR_MIN; | |
0bb2e5ab | 961 | } |
bc2b9e3f VM |
962 | if (wParam & GDTR_MAX) |
963 | { | |
964 | MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxDate); | |
965 | infoPtr->rangeValid |= GDTR_MAX; | |
0bb2e5ab | 966 | } |
0bb2e5ab | 967 | |
97747453 VM |
968 | /* Only one limit set - we are done */ |
969 | if ((infoPtr->rangeValid & (GDTR_MIN | GDTR_MAX)) != (GDTR_MIN | GDTR_MAX)) | |
970 | return TRUE; | |
971 | ||
972 | SystemTimeToFileTime(&infoPtr->maxDate, &ft_max); | |
973 | SystemTimeToFileTime(&infoPtr->minDate, &ft_min); | |
974 | ||
975 | if (CompareFileTime(&ft_min, &ft_max) > 0) | |
976 | { | |
977 | if ((wParam & (GDTR_MIN | GDTR_MAX)) == (GDTR_MIN | GDTR_MAX)) | |
978 | { | |
979 | /* Native swaps limits only when both limits are being set. */ | |
980 | SYSTEMTIME st_tmp = infoPtr->minDate; | |
981 | infoPtr->minDate = infoPtr->maxDate; | |
982 | infoPtr->maxDate = st_tmp; | |
983 | } | |
984 | else | |
985 | { | |
986 | /* Reset the other limit. */ | |
987 | /* FIXME: native sets date&time to 0. Should we do this too? */ | |
988 | infoPtr->rangeValid &= wParam & GDTR_MIN ? ~GDTR_MAX : ~GDTR_MIN ; | |
989 | } | |
990 | } | |
991 | ||
f273bdc0 | 992 | return TRUE; |
b2e91b6a AP |
993 | } |
994 | ||
a867030e | 995 | |
b2e91b6a | 996 | static LRESULT |
3dbdb311 | 997 | MONTHCAL_GetRange(HWND hwnd, LPARAM lParam) |
b2e91b6a | 998 | { |
0bb2e5ab AJ |
999 | MONTHCAL_INFO *infoPtr = MONTHCAL_GetInfoPtr(hwnd); |
1000 | SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *)lParam; | |
b2e91b6a AP |
1001 | |
1002 | /* validate parameters */ | |
1003 | ||
b7c84d3b | 1004 | if((infoPtr==NULL) || (lprgSysTimeArray==NULL)) return FALSE; |
b2e91b6a | 1005 | |
b7c84d3b AJ |
1006 | MONTHCAL_CopyTime(&infoPtr->maxDate, &lprgSysTimeArray[1]); |
1007 | MONTHCAL_CopyTime(&infoPtr->minDate, &lprgSysTimeArray[0]); | |
b2e91b6a AP |
1008 | |
1009 | return infoPtr->rangeValid; | |
1010 | } | |
1011 | ||
0bb2e5ab | 1012 | |
b2e91b6a | 1013 | static LRESULT |
a8a469c7 | 1014 | MONTHCAL_SetDayState(const MONTHCAL_INFO *infoPtr, WPARAM wParam, LPARAM lParam) |
b2e91b6a AP |
1015 | |
1016 | { | |
0bb2e5ab AJ |
1017 | int i, iMonths = (int)wParam; |
1018 | MONTHDAYSTATE *dayStates = (LPMONTHDAYSTATE)lParam; | |
b2e91b6a | 1019 | |
3c9e7a7f | 1020 | TRACE("%lx %lx\n", wParam, lParam); |
b7c84d3b | 1021 | if(iMonths!=infoPtr->monthRange) return 0; |
b2e91b6a | 1022 | |
9a624916 | 1023 | for(i=0; i<iMonths; i++) |
b7c84d3b | 1024 | infoPtr->monthdayState[i] = dayStates[i]; |
b2e91b6a AP |
1025 | return 1; |
1026 | } | |
1027 | ||
9a624916 | 1028 | static LRESULT |
a8a469c7 | 1029 | MONTHCAL_GetCurSel(const MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1030 | { |
0bb2e5ab | 1031 | SYSTEMTIME *lpSel = (SYSTEMTIME *) lParam; |
b2e91b6a | 1032 | |
30bebfdc | 1033 | TRACE("%lx\n", lParam); |
b7c84d3b | 1034 | if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; |
30bebfdc | 1035 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; |
b2e91b6a | 1036 | |
b7c84d3b | 1037 | MONTHCAL_CopyTime(&infoPtr->minSel, lpSel); |
c401aa84 | 1038 | TRACE("%d/%d/%d\n", lpSel->wYear, lpSel->wMonth, lpSel->wDay); |
b2e91b6a AP |
1039 | return TRUE; |
1040 | } | |
1041 | ||
b2e91b6a AP |
1042 | /* FIXME: if the specified date is not visible, make it visible */ |
1043 | /* FIXME: redraw? */ | |
9a624916 | 1044 | static LRESULT |
30bebfdc | 1045 | MONTHCAL_SetCurSel(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1046 | { |
b7c84d3b | 1047 | SYSTEMTIME *lpSel = (SYSTEMTIME *)lParam; |
b2e91b6a | 1048 | |
30bebfdc | 1049 | TRACE("%lx\n", lParam); |
b7c84d3b | 1050 | if((infoPtr==NULL) ||(lpSel==NULL)) return FALSE; |
30bebfdc | 1051 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) return FALSE; |
b2e91b6a | 1052 | |
d0f75b59 FA |
1053 | if(!MONTHCAL_ValidateTime(*lpSel)) return FALSE; |
1054 | ||
c401aa84 KF |
1055 | infoPtr->currentMonth=lpSel->wMonth; |
1056 | infoPtr->currentYear=lpSel->wYear; | |
b2e91b6a | 1057 | |
b7c84d3b AJ |
1058 | MONTHCAL_CopyTime(lpSel, &infoPtr->minSel); |
1059 | MONTHCAL_CopyTime(lpSel, &infoPtr->maxSel); | |
b2e91b6a | 1060 | |
30bebfdc | 1061 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
043c3e79 | 1062 | |
b2e91b6a AP |
1063 | return TRUE; |
1064 | } | |
1065 | ||
0bb2e5ab | 1066 | |
9a624916 | 1067 | static LRESULT |
a8a469c7 | 1068 | MONTHCAL_GetMaxSelCount(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 1069 | { |
b2e91b6a AP |
1070 | return infoPtr->maxSelCount; |
1071 | } | |
1072 | ||
0bb2e5ab | 1073 | |
9a624916 | 1074 | static LRESULT |
30bebfdc | 1075 | MONTHCAL_SetMaxSelCount(MONTHCAL_INFO *infoPtr, WPARAM wParam) |
b2e91b6a | 1076 | { |
3c9e7a7f | 1077 | TRACE("%lx\n", wParam); |
b2e91b6a | 1078 | |
30bebfdc | 1079 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { |
0bb2e5ab | 1080 | infoPtr->maxSelCount = wParam; |
b2e91b6a AP |
1081 | } |
1082 | ||
1083 | return TRUE; | |
1084 | } | |
1085 | ||
1086 | ||
9a624916 | 1087 | static LRESULT |
a8a469c7 | 1088 | MONTHCAL_GetSelRange(const MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1089 | { |
0bb2e5ab | 1090 | SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; |
b2e91b6a | 1091 | |
30bebfdc | 1092 | TRACE("%lx\n", lParam); |
b2e91b6a AP |
1093 | |
1094 | /* validate parameters */ | |
1095 | ||
b7c84d3b | 1096 | if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; |
b2e91b6a | 1097 | |
30bebfdc | 1098 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) |
b7c84d3b AJ |
1099 | { |
1100 | MONTHCAL_CopyTime(&infoPtr->maxSel, &lprgSysTimeArray[1]); | |
1101 | MONTHCAL_CopyTime(&infoPtr->minSel, &lprgSysTimeArray[0]); | |
1102 | TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); | |
0bb2e5ab | 1103 | return TRUE; |
b2e91b6a | 1104 | } |
9a624916 | 1105 | |
b2e91b6a AP |
1106 | return FALSE; |
1107 | } | |
1108 | ||
0bb2e5ab | 1109 | |
9a624916 | 1110 | static LRESULT |
30bebfdc | 1111 | MONTHCAL_SetSelRange(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1112 | { |
0bb2e5ab | 1113 | SYSTEMTIME *lprgSysTimeArray = (SYSTEMTIME *) lParam; |
b2e91b6a | 1114 | |
30bebfdc | 1115 | TRACE("%lx\n", lParam); |
b2e91b6a AP |
1116 | |
1117 | /* validate parameters */ | |
1118 | ||
b7c84d3b | 1119 | if((infoPtr==NULL) ||(lprgSysTimeArray==NULL)) return FALSE; |
b2e91b6a | 1120 | |
30bebfdc | 1121 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) |
b7c84d3b AJ |
1122 | { |
1123 | MONTHCAL_CopyTime(&lprgSysTimeArray[1], &infoPtr->maxSel); | |
1124 | MONTHCAL_CopyTime(&lprgSysTimeArray[0], &infoPtr->minSel); | |
1125 | TRACE("[min,max]=[%d %d]\n", infoPtr->minSel.wDay, infoPtr->maxSel.wDay); | |
0bb2e5ab | 1126 | return TRUE; |
b2e91b6a | 1127 | } |
9a624916 | 1128 | |
b2e91b6a AP |
1129 | return FALSE; |
1130 | } | |
1131 | ||
1132 | ||
9a624916 | 1133 | static LRESULT |
a8a469c7 | 1134 | MONTHCAL_GetToday(const MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1135 | { |
0bb2e5ab | 1136 | SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; |
b2e91b6a | 1137 | |
30bebfdc | 1138 | TRACE("%lx\n", lParam); |
b2e91b6a AP |
1139 | |
1140 | /* validate parameters */ | |
1141 | ||
b7c84d3b AJ |
1142 | if((infoPtr==NULL) || (lpToday==NULL)) return FALSE; |
1143 | MONTHCAL_CopyTime(&infoPtr->todaysDate, lpToday); | |
b2e91b6a AP |
1144 | return TRUE; |
1145 | } | |
1146 | ||
1147 | ||
9a624916 | 1148 | static LRESULT |
30bebfdc | 1149 | MONTHCAL_SetToday(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
d144e4a3 | 1150 | { |
0bb2e5ab | 1151 | SYSTEMTIME *lpToday = (SYSTEMTIME *) lParam; |
b2e91b6a | 1152 | |
30bebfdc | 1153 | TRACE("%lx\n", lParam); |
b2e91b6a | 1154 | |
d144e4a3 | 1155 | /* validate parameters */ |
b2e91b6a | 1156 | |
b7c84d3b AJ |
1157 | if((infoPtr==NULL) ||(lpToday==NULL)) return FALSE; |
1158 | MONTHCAL_CopyTime(lpToday, &infoPtr->todaysDate); | |
30bebfdc | 1159 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
d144e4a3 | 1160 | return TRUE; |
b2e91b6a AP |
1161 | } |
1162 | ||
1163 | ||
1164 | static LRESULT | |
a8a469c7 | 1165 | MONTHCAL_HitTest(const MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1166 | { |
b0067efa UB |
1167 | PMCHITTESTINFO lpht = (PMCHITTESTINFO)lParam; |
1168 | UINT x,y; | |
1169 | DWORD retval; | |
1170 | int day,wday,wnum; | |
9a624916 VB |
1171 | |
1172 | ||
b0067efa UB |
1173 | x = lpht->pt.x; |
1174 | y = lpht->pt.y; | |
b2e91b6a | 1175 | |
8b20d720 | 1176 | ZeroMemory(&lpht->st, sizeof(lpht->st)); |
9a624916 VB |
1177 | |
1178 | /* Comment in for debugging... | |
1179 | TRACE("%d %d wd[%d %d %d %d] d[%d %d %d %d] t[%d %d %d %d] wn[%d %d %d %d]\n", x, y, | |
b0067efa UB |
1180 | infoPtr->wdays.left, infoPtr->wdays.right, |
1181 | infoPtr->wdays.top, infoPtr->wdays.bottom, | |
1182 | infoPtr->days.left, infoPtr->days.right, | |
1183 | infoPtr->days.top, infoPtr->days.bottom, | |
1184 | infoPtr->todayrect.left, infoPtr->todayrect.right, | |
1185 | infoPtr->todayrect.top, infoPtr->todayrect.bottom, | |
1186 | infoPtr->weeknums.left, infoPtr->weeknums.right, | |
1187 | infoPtr->weeknums.top, infoPtr->weeknums.bottom); | |
1188 | */ | |
b2e91b6a | 1189 | |
b0067efa | 1190 | /* are we in the header? */ |
9a624916 | 1191 | |
b7c84d3b AJ |
1192 | if(PtInRect(&infoPtr->title, lpht->pt)) { |
1193 | if(PtInRect(&infoPtr->titlebtnprev, lpht->pt)) { | |
0bb2e5ab AJ |
1194 | retval = MCHT_TITLEBTNPREV; |
1195 | goto done; | |
1196 | } | |
b7c84d3b | 1197 | if(PtInRect(&infoPtr->titlebtnnext, lpht->pt)) { |
0bb2e5ab AJ |
1198 | retval = MCHT_TITLEBTNNEXT; |
1199 | goto done; | |
1200 | } | |
b7c84d3b | 1201 | if(PtInRect(&infoPtr->titlemonth, lpht->pt)) { |
0bb2e5ab AJ |
1202 | retval = MCHT_TITLEMONTH; |
1203 | goto done; | |
1204 | } | |
b7c84d3b | 1205 | if(PtInRect(&infoPtr->titleyear, lpht->pt)) { |
0bb2e5ab AJ |
1206 | retval = MCHT_TITLEYEAR; |
1207 | goto done; | |
1208 | } | |
9a624916 | 1209 | |
0bb2e5ab AJ |
1210 | retval = MCHT_TITLE; |
1211 | goto done; | |
1212 | } | |
9a624916 | 1213 | |
b0067efa UB |
1214 | day = MONTHCAL_CalcDayFromPos(infoPtr,x,y,&wday,&wnum); |
1215 | if(PtInRect(&infoPtr->wdays, lpht->pt)) { | |
1216 | retval = MCHT_CALENDARDAY; | |
1217 | lpht->st.wYear = infoPtr->currentYear; | |
1218 | lpht->st.wMonth = (day < 1)? infoPtr->currentMonth -1 : infoPtr->currentMonth; | |
9a624916 | 1219 | lpht->st.wDay = (day < 1)? |
b0067efa | 1220 | MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : day; |
0bb2e5ab AJ |
1221 | goto done; |
1222 | } | |
9a624916 VB |
1223 | if(PtInRect(&infoPtr->weeknums, lpht->pt)) { |
1224 | retval = MCHT_CALENDARWEEKNUM; | |
b0067efa | 1225 | lpht->st.wYear = infoPtr->currentYear; |
9a624916 VB |
1226 | lpht->st.wMonth = (day < 1) ? infoPtr->currentMonth -1 : |
1227 | (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? | |
b0067efa | 1228 | infoPtr->currentMonth +1 :infoPtr->currentMonth; |
9a624916 VB |
1229 | lpht->st.wDay = (day < 1 ) ? |
1230 | MONTHCAL_MonthLength(infoPtr->currentMonth-1,infoPtr->currentYear) -day : | |
1231 | (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) ? | |
b0067efa | 1232 | day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) : day; |
9a624916 | 1233 | goto done; |
0bb2e5ab | 1234 | } |
9a624916 | 1235 | if(PtInRect(&infoPtr->days, lpht->pt)) |
b0067efa UB |
1236 | { |
1237 | lpht->st.wYear = infoPtr->currentYear; | |
9a624916 | 1238 | if ( day < 1) |
b0067efa UB |
1239 | { |
1240 | retval = MCHT_CALENDARDATEPREV; | |
1241 | lpht->st.wMonth = infoPtr->currentMonth - 1; | |
1242 | if (lpht->st.wMonth <1) | |
1243 | { | |
1244 | lpht->st.wMonth = 12; | |
1245 | lpht->st.wYear--; | |
1246 | } | |
1247 | lpht->st.wDay = MONTHCAL_MonthLength(lpht->st.wMonth,lpht->st.wYear) -day; | |
1248 | } | |
1249 | else if (day > MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear)) | |
1250 | { | |
1251 | retval = MCHT_CALENDARDATENEXT; | |
1252 | lpht->st.wMonth = infoPtr->currentMonth + 1; | |
1253 | if (lpht->st.wMonth <12) | |
1254 | { | |
1255 | lpht->st.wMonth = 1; | |
1256 | lpht->st.wYear++; | |
1257 | } | |
1258 | lpht->st.wDay = day - MONTHCAL_MonthLength(infoPtr->currentMonth,infoPtr->currentYear) ; | |
1259 | } | |
1260 | else { | |
1261 | retval = MCHT_CALENDARDATE; | |
1262 | lpht->st.wMonth = infoPtr->currentMonth; | |
1263 | lpht->st.wDay = day; | |
a6659d26 | 1264 | lpht->st.wDayOfWeek = MONTHCAL_CalculateDayOfWeek(day,lpht->st.wMonth,lpht->st.wYear); |
b0067efa UB |
1265 | } |
1266 | goto done; | |
1267 | } | |
1268 | if(PtInRect(&infoPtr->todayrect, lpht->pt)) { | |
9a624916 | 1269 | retval = MCHT_TODAYLINK; |
0bb2e5ab AJ |
1270 | goto done; |
1271 | } | |
9a624916 VB |
1272 | |
1273 | ||
0bb2e5ab | 1274 | /* Hit nothing special? What's left must be background :-) */ |
9a624916 VB |
1275 | |
1276 | retval = MCHT_CALENDARBK; | |
1277 | done: | |
0bb2e5ab | 1278 | lpht->uHit = retval; |
b2e91b6a AP |
1279 | return retval; |
1280 | } | |
1281 | ||
1282 | ||
30bebfdc | 1283 | static void MONTHCAL_GoToNextMonth(MONTHCAL_INFO *infoPtr) |
d144e4a3 | 1284 | { |
30bebfdc | 1285 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); |
d144e4a3 | 1286 | |
b7c84d3b | 1287 | TRACE("MONTHCAL_GoToNextMonth\n"); |
d144e4a3 | 1288 | |
0bb2e5ab | 1289 | infoPtr->currentMonth++; |
b7c84d3b | 1290 | if(infoPtr->currentMonth > 12) { |
0bb2e5ab AJ |
1291 | infoPtr->currentYear++; |
1292 | infoPtr->currentMonth = 1; | |
1293 | } | |
d144e4a3 | 1294 | |
b7c84d3b | 1295 | if(dwStyle & MCS_DAYSTATE) { |
0bb2e5ab AJ |
1296 | NMDAYSTATE nmds; |
1297 | int i; | |
d144e4a3 | 1298 | |
30bebfdc DT |
1299 | nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; |
1300 | nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
0bb2e5ab AJ |
1301 | nmds.nmhdr.code = MCN_GETDAYSTATE; |
1302 | nmds.cDayState = infoPtr->monthRange; | |
7de279a7 | 1303 | nmds.prgDayState = Alloc(infoPtr->monthRange * sizeof(MONTHDAYSTATE)); |
d144e4a3 | 1304 | |
bf6e766d AS |
1305 | nmds.stStart = infoPtr->todaysDate; |
1306 | nmds.stStart.wYear = infoPtr->currentYear; | |
1307 | nmds.stStart.wMonth = infoPtr->currentMonth; | |
1308 | nmds.stStart.wDay = 1; | |
1309 | ||
867f254b | 1310 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds); |
b7c84d3b | 1311 | for(i=0; i<infoPtr->monthRange; i++) |
0bb2e5ab AJ |
1312 | infoPtr->monthdayState[i] = nmds.prgDayState[i]; |
1313 | } | |
d144e4a3 AP |
1314 | } |
1315 | ||
1316 | ||
30bebfdc | 1317 | static void MONTHCAL_GoToPrevMonth(MONTHCAL_INFO *infoPtr) |
d144e4a3 | 1318 | { |
30bebfdc | 1319 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); |
0bb2e5ab | 1320 | |
30bebfdc | 1321 | TRACE("\n"); |
0bb2e5ab AJ |
1322 | |
1323 | infoPtr->currentMonth--; | |
b7c84d3b | 1324 | if(infoPtr->currentMonth < 1) { |
0bb2e5ab AJ |
1325 | infoPtr->currentYear--; |
1326 | infoPtr->currentMonth = 12; | |
1327 | } | |
1328 | ||
b7c84d3b | 1329 | if(dwStyle & MCS_DAYSTATE) { |
0bb2e5ab AJ |
1330 | NMDAYSTATE nmds; |
1331 | int i; | |
1332 | ||
30bebfdc DT |
1333 | nmds.nmhdr.hwndFrom = infoPtr->hwndSelf; |
1334 | nmds.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
0bb2e5ab AJ |
1335 | nmds.nmhdr.code = MCN_GETDAYSTATE; |
1336 | nmds.cDayState = infoPtr->monthRange; | |
7de279a7 | 1337 | nmds.prgDayState = Alloc |
b7c84d3b | 1338 | (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); |
0bb2e5ab | 1339 | |
bf6e766d AS |
1340 | nmds.stStart = infoPtr->todaysDate; |
1341 | nmds.stStart.wYear = infoPtr->currentYear; | |
1342 | nmds.stStart.wMonth = infoPtr->currentMonth; | |
1343 | nmds.stStart.wDay = 1; | |
1344 | ||
867f254b | 1345 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmds.nmhdr.idFrom, (LPARAM)&nmds); |
b7c84d3b AJ |
1346 | for(i=0; i<infoPtr->monthRange; i++) |
1347 | infoPtr->monthdayState[i] = nmds.prgDayState[i]; | |
0bb2e5ab | 1348 | } |
d144e4a3 AP |
1349 | } |
1350 | ||
b0067efa | 1351 | static LRESULT |
30bebfdc | 1352 | MONTHCAL_RButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b0067efa | 1353 | { |
30a66a05 | 1354 | static const WCHAR todayW[] = { 'G','o',' ','t','o',' ','T','o','d','a','y',':',0 }; |
b0067efa UB |
1355 | HMENU hMenu; |
1356 | POINT menupoint; | |
30a66a05 | 1357 | WCHAR buf[32]; |
9a624916 | 1358 | |
b0067efa | 1359 | hMenu = CreatePopupMenu(); |
30a66a05 | 1360 | if (!LoadStringW(COMCTL32_hModule,IDM_GOTODAY,buf,countof(buf))) |
b0067efa UB |
1361 | { |
1362 | WARN("Can't load resource\n"); | |
30a66a05 | 1363 | strcpyW(buf, todayW); |
b0067efa | 1364 | } |
30a66a05 | 1365 | AppendMenuW(hMenu, MF_STRING|MF_ENABLED,1, buf); |
7cca8563 AJ |
1366 | menupoint.x=(short)LOWORD(lParam); |
1367 | menupoint.y=(short)HIWORD(lParam); | |
30bebfdc | 1368 | ClientToScreen(infoPtr->hwndSelf, &menupoint); |
b0067efa | 1369 | if( TrackPopupMenu(hMenu,TPM_RIGHTBUTTON| TPM_NONOTIFY|TPM_RETURNCMD, |
30bebfdc | 1370 | menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL)) |
b0067efa UB |
1371 | { |
1372 | infoPtr->currentMonth=infoPtr->todaysDate.wMonth; | |
1373 | infoPtr->currentYear=infoPtr->todaysDate.wYear; | |
30bebfdc | 1374 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
9a624916 | 1375 | } |
b0067efa UB |
1376 | return 0; |
1377 | } | |
d144e4a3 | 1378 | |
b2e91b6a | 1379 | static LRESULT |
30bebfdc | 1380 | MONTHCAL_LButtonDown(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1381 | { |
30a66a05 | 1382 | static const WCHAR EditW[] = { 'E','D','I','T',0 }; |
0bb2e5ab | 1383 | MCHITTESTINFO ht; |
0bb2e5ab AJ |
1384 | DWORD hit; |
1385 | HMENU hMenu; | |
043c3e79 | 1386 | RECT rcDay; /* used in determining area to invalidate */ |
30a66a05 | 1387 | WCHAR buf[32]; |
b0067efa UB |
1388 | int i; |
1389 | POINT menupoint; | |
30bebfdc DT |
1390 | |
1391 | TRACE("%lx\n", lParam); | |
9a624916 | 1392 | |
b0067efa UB |
1393 | if (infoPtr->hWndYearUpDown) |
1394 | { | |
62e17fa8 | 1395 | infoPtr->currentYear=SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, 0); |
b0067efa UB |
1396 | if(!DestroyWindow(infoPtr->hWndYearUpDown)) |
1397 | { | |
1398 | FIXME("Can't destroy Updown Control\n"); | |
1399 | } | |
1400 | else | |
1401 | infoPtr->hWndYearUpDown=0; | |
1402 | if(!DestroyWindow(infoPtr->hWndYearEdit)) | |
1403 | { | |
1404 | FIXME("Can't destroy Updown Control\n"); | |
1405 | } | |
1406 | else | |
1407 | infoPtr->hWndYearEdit=0; | |
30bebfdc | 1408 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
b0067efa | 1409 | } |
9a624916 | 1410 | |
7cca8563 AJ |
1411 | ht.pt.x = (short)LOWORD(lParam); |
1412 | ht.pt.y = (short)HIWORD(lParam); | |
30bebfdc | 1413 | hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); |
0bb2e5ab AJ |
1414 | |
1415 | /* FIXME: these flags should be checked by */ | |
b7c84d3b | 1416 | /*((hit & MCHT_XXX) == MCHT_XXX) b/c some of the flags are */ |
0bb2e5ab | 1417 | /* multi-bit */ |
b0067efa | 1418 | if(hit ==MCHT_TITLEBTNNEXT) { |
30bebfdc | 1419 | MONTHCAL_GoToNextMonth(infoPtr); |
0bb2e5ab | 1420 | infoPtr->status = MC_NEXTPRESSED; |
30bebfdc DT |
1421 | SetTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER, MC_NEXTMONTHDELAY, 0); |
1422 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); | |
76949d37 | 1423 | return 0; |
0bb2e5ab | 1424 | } |
9a624916 | 1425 | if(hit == MCHT_TITLEBTNPREV){ |
30bebfdc | 1426 | MONTHCAL_GoToPrevMonth(infoPtr); |
b7c84d3b | 1427 | infoPtr->status = MC_PREVPRESSED; |
30bebfdc DT |
1428 | SetTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER, MC_NEXTMONTHDELAY, 0); |
1429 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); | |
76949d37 | 1430 | return 0; |
0bb2e5ab AJ |
1431 | } |
1432 | ||
b7c84d3b | 1433 | if(hit == MCHT_TITLEMONTH) { |
b0067efa | 1434 | hMenu = CreatePopupMenu(); |
9a624916 | 1435 | |
b0067efa UB |
1436 | for (i=0; i<12;i++) |
1437 | { | |
30a66a05 DP |
1438 | GetLocaleInfoW(LOCALE_USER_DEFAULT,LOCALE_SMONTHNAME1+i, buf,countof(buf)); |
1439 | AppendMenuW(hMenu, MF_STRING|MF_ENABLED,i+1, buf); | |
b0067efa UB |
1440 | } |
1441 | menupoint.x=infoPtr->titlemonth.right; | |
1442 | menupoint.y=infoPtr->titlemonth.bottom; | |
30bebfdc | 1443 | ClientToScreen(infoPtr->hwndSelf, &menupoint); |
b0067efa | 1444 | i= TrackPopupMenu(hMenu,TPM_LEFTALIGN | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_RETURNCMD, |
30bebfdc | 1445 | menupoint.x, menupoint.y, 0, infoPtr->hwndSelf, NULL); |
b0067efa UB |
1446 | if ((i>0) && (i<13)) |
1447 | { | |
1448 | infoPtr->currentMonth=i; | |
30bebfdc | 1449 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
b0067efa | 1450 | } |
0bb2e5ab | 1451 | } |
b7c84d3b | 1452 | if(hit == MCHT_TITLEYEAR) { |
30a66a05 DP |
1453 | infoPtr->hWndYearEdit=CreateWindowExW(0, |
1454 | EditW, | |
b0067efa UB |
1455 | 0, |
1456 | WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT, | |
1457 | infoPtr->titleyear.left+3,infoPtr->titlebtnnext.top, | |
320814fb | 1458 | infoPtr->titleyear.right-infoPtr->titleyear.left+4, |
b0067efa | 1459 | infoPtr->textHeight, |
30bebfdc | 1460 | infoPtr->hwndSelf, |
d2667a4c FG |
1461 | NULL, |
1462 | NULL, | |
b0067efa | 1463 | NULL); |
320814fb | 1464 | SendMessageW( infoPtr->hWndYearEdit, WM_SETFONT, (WPARAM) infoPtr->hBoldFont, (LPARAM)TRUE); |
30a66a05 DP |
1465 | infoPtr->hWndYearUpDown=CreateWindowExW(0, |
1466 | UPDOWN_CLASSW, | |
b0067efa UB |
1467 | 0, |
1468 | WS_VISIBLE | WS_CHILD |UDS_SETBUDDYINT|UDS_NOTHOUSANDS|UDS_ARROWKEYS, | |
320814fb DC |
1469 | infoPtr->titleyear.right+7,infoPtr->titlebtnnext.top, |
1470 | 18, | |
b0067efa | 1471 | infoPtr->textHeight, |
30bebfdc | 1472 | infoPtr->hwndSelf, |
d2667a4c FG |
1473 | NULL, |
1474 | NULL, | |
b0067efa | 1475 | NULL); |
62e17fa8 MS |
1476 | SendMessageW(infoPtr->hWndYearUpDown, UDM_SETRANGE, 0, MAKELONG (9999, 1753)); |
1477 | SendMessageW(infoPtr->hWndYearUpDown, UDM_SETBUDDY, (WPARAM) infoPtr->hWndYearEdit, 0); | |
1478 | SendMessageW(infoPtr->hWndYearUpDown, UDM_SETPOS, 0, infoPtr->currentYear); | |
76949d37 | 1479 | return 0; |
9a624916 | 1480 | |
0bb2e5ab | 1481 | } |
b7c84d3b | 1482 | if(hit == MCHT_TODAYLINK) { |
d81b6fa8 LZ |
1483 | NMSELCHANGE nmsc; |
1484 | ||
e58e4679 LZ |
1485 | infoPtr->curSelDay = infoPtr->todaysDate.wDay; |
1486 | infoPtr->firstSelDay = infoPtr->todaysDate.wDay; | |
b0067efa UB |
1487 | infoPtr->currentMonth=infoPtr->todaysDate.wMonth; |
1488 | infoPtr->currentYear=infoPtr->todaysDate.wYear; | |
e58e4679 LZ |
1489 | MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minSel); |
1490 | MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxSel); | |
30bebfdc | 1491 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
d81b6fa8 LZ |
1492 | |
1493 | nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; | |
1494 | nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
1495 | nmsc.nmhdr.code = MCN_SELCHANGE; | |
1496 | MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart); | |
1497 | MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd); | |
867f254b | 1498 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc); |
d81b6fa8 LZ |
1499 | |
1500 | nmsc.nmhdr.code = MCN_SELECT; | |
867f254b | 1501 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc); |
76949d37 | 1502 | return 0; |
0bb2e5ab | 1503 | } |
c401aa84 | 1504 | if(hit == MCHT_CALENDARDATE) { |
0bb2e5ab AJ |
1505 | SYSTEMTIME selArray[2]; |
1506 | NMSELCHANGE nmsc; | |
1507 | ||
c401aa84 KF |
1508 | MONTHCAL_CopyTime(&ht.st, &selArray[0]); |
1509 | MONTHCAL_CopyTime(&ht.st, &selArray[1]); | |
b7cc9c66 AT |
1510 | MONTHCAL_SetSelRange(infoPtr, (LPARAM)selArray); |
1511 | MONTHCAL_SetCurSel(infoPtr, (LPARAM)selArray); | |
b0067efa | 1512 | TRACE("MCHT_CALENDARDATE\n"); |
30bebfdc DT |
1513 | nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; |
1514 | nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
0bb2e5ab | 1515 | nmsc.nmhdr.code = MCN_SELCHANGE; |
c401aa84 KF |
1516 | MONTHCAL_CopyTime(&infoPtr->minSel,&nmsc.stSelStart); |
1517 | MONTHCAL_CopyTime(&infoPtr->maxSel,&nmsc.stSelEnd); | |
9a624916 | 1518 | |
867f254b | 1519 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc); |
d144e4a3 | 1520 | |
b7c84d3b | 1521 | |
043c3e79 | 1522 | /* redraw both old and new days if the selected day changed */ |
b7c84d3b | 1523 | if(infoPtr->curSelDay != ht.st.wDay) { |
043c3e79 | 1524 | MONTHCAL_CalcPosFromDay(infoPtr, ht.st.wDay, ht.st.wMonth, &rcDay); |
30bebfdc | 1525 | InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); |
043c3e79 CM |
1526 | |
1527 | MONTHCAL_CalcPosFromDay(infoPtr, infoPtr->curSelDay, infoPtr->currentMonth, &rcDay); | |
30bebfdc | 1528 | InvalidateRect(infoPtr->hwndSelf, &rcDay, TRUE); |
b7c84d3b | 1529 | } |
b2e91b6a | 1530 | |
0bb2e5ab AJ |
1531 | infoPtr->firstSelDay = ht.st.wDay; |
1532 | infoPtr->curSelDay = ht.st.wDay; | |
1533 | infoPtr->status = MC_SEL_LBUTDOWN; | |
76949d37 | 1534 | return 0; |
b7c84d3b AJ |
1535 | } |
1536 | ||
76949d37 | 1537 | return 1; |
b2e91b6a AP |
1538 | } |
1539 | ||
0bb2e5ab | 1540 | |
b2e91b6a | 1541 | static LRESULT |
30bebfdc | 1542 | MONTHCAL_LButtonUp(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1543 | { |
0bb2e5ab AJ |
1544 | NMSELCHANGE nmsc; |
1545 | NMHDR nmhdr; | |
b7c84d3b | 1546 | BOOL redraw = FALSE; |
b0067efa UB |
1547 | MCHITTESTINFO ht; |
1548 | DWORD hit; | |
b7c84d3b AJ |
1549 | |
1550 | TRACE("\n"); | |
d144e4a3 | 1551 | |
b7c84d3b | 1552 | if(infoPtr->status & MC_NEXTPRESSED) { |
30bebfdc | 1553 | KillTimer(infoPtr->hwndSelf, MC_NEXTMONTHTIMER); |
c401aa84 | 1554 | infoPtr->status &= ~MC_NEXTPRESSED; |
b7c84d3b AJ |
1555 | redraw = TRUE; |
1556 | } | |
1557 | if(infoPtr->status & MC_PREVPRESSED) { | |
30bebfdc | 1558 | KillTimer(infoPtr->hwndSelf, MC_PREVMONTHTIMER); |
c401aa84 | 1559 | infoPtr->status &= ~MC_PREVPRESSED; |
b7c84d3b AJ |
1560 | redraw = TRUE; |
1561 | } | |
b2e91b6a | 1562 | |
7cca8563 AJ |
1563 | ht.pt.x = (short)LOWORD(lParam); |
1564 | ht.pt.y = (short)HIWORD(lParam); | |
30bebfdc | 1565 | hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); |
b0067efa | 1566 | |
0bb2e5ab | 1567 | infoPtr->status = MC_SEL_LBUTUP; |
d144e4a3 | 1568 | |
b0067efa | 1569 | if(hit ==MCHT_CALENDARDATENEXT) { |
30bebfdc DT |
1570 | MONTHCAL_GoToNextMonth(infoPtr); |
1571 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); | |
b0067efa UB |
1572 | return TRUE; |
1573 | } | |
9a624916 | 1574 | if(hit == MCHT_CALENDARDATEPREV){ |
30bebfdc DT |
1575 | MONTHCAL_GoToPrevMonth(infoPtr); |
1576 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); | |
b0067efa UB |
1577 | return TRUE; |
1578 | } | |
30bebfdc DT |
1579 | nmhdr.hwndFrom = infoPtr->hwndSelf; |
1580 | nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
0bb2e5ab | 1581 | nmhdr.code = NM_RELEASEDCAPTURE; |
30bebfdc | 1582 | TRACE("Sent notification from %p to %p\n", infoPtr->hwndSelf, infoPtr->hwndNotify); |
d144e4a3 | 1583 | |
867f254b | 1584 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr); |
b7c84d3b | 1585 | /* redraw if necessary */ |
043c3e79 | 1586 | if(redraw) |
30bebfdc | 1587 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
c401aa84 KF |
1588 | /* only send MCN_SELECT if currently displayed month's day was selected */ |
1589 | if(hit == MCHT_CALENDARDATE) { | |
30bebfdc DT |
1590 | nmsc.nmhdr.hwndFrom = infoPtr->hwndSelf; |
1591 | nmsc.nmhdr.idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID); | |
c401aa84 KF |
1592 | nmsc.nmhdr.code = MCN_SELECT; |
1593 | MONTHCAL_CopyTime(&infoPtr->minSel, &nmsc.stSelStart); | |
1594 | MONTHCAL_CopyTime(&infoPtr->maxSel, &nmsc.stSelEnd); | |
9a624916 | 1595 | |
867f254b | 1596 | SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmsc.nmhdr.idFrom, (LPARAM)&nmsc); |
c401aa84 KF |
1597 | |
1598 | } | |
0bb2e5ab | 1599 | return 0; |
b2e91b6a AP |
1600 | } |
1601 | ||
0bb2e5ab | 1602 | |
d144e4a3 | 1603 | static LRESULT |
30bebfdc | 1604 | MONTHCAL_Timer(MONTHCAL_INFO *infoPtr, WPARAM wParam) |
d144e4a3 | 1605 | { |
b7c84d3b | 1606 | BOOL redraw = FALSE; |
0bb2e5ab | 1607 | |
3c9e7a7f | 1608 | TRACE("%ld\n", wParam); |
0bb2e5ab | 1609 | |
b7c84d3b | 1610 | switch(wParam) { |
9a624916 | 1611 | case MC_NEXTMONTHTIMER: |
b7c84d3b | 1612 | redraw = TRUE; |
30bebfdc | 1613 | MONTHCAL_GoToNextMonth(infoPtr); |
0bb2e5ab AJ |
1614 | break; |
1615 | case MC_PREVMONTHTIMER: | |
b7c84d3b | 1616 | redraw = TRUE; |
30bebfdc | 1617 | MONTHCAL_GoToPrevMonth(infoPtr); |
0bb2e5ab AJ |
1618 | break; |
1619 | default: | |
1620 | ERR("got unknown timer\n"); | |
30bebfdc | 1621 | break; |
0bb2e5ab | 1622 | } |
d144e4a3 | 1623 | |
b7c84d3b | 1624 | /* redraw only if necessary */ |
043c3e79 | 1625 | if(redraw) |
30bebfdc | 1626 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
b7c84d3b | 1627 | |
0bb2e5ab AJ |
1628 | return 0; |
1629 | } | |
d144e4a3 | 1630 | |
b2e91b6a AP |
1631 | |
1632 | static LRESULT | |
3dbdb311 | 1633 | MONTHCAL_MouseMove(MONTHCAL_INFO *infoPtr, LPARAM lParam) |
b2e91b6a | 1634 | { |
0bb2e5ab | 1635 | MCHITTESTINFO ht; |
0bb2e5ab AJ |
1636 | int oldselday, selday, hit; |
1637 | RECT r; | |
b2e91b6a | 1638 | |
b7c84d3b | 1639 | if(!(infoPtr->status & MC_SEL_LBUTDOWN)) return 0; |
b2e91b6a | 1640 | |
7cca8563 AJ |
1641 | ht.pt.x = (short)LOWORD(lParam); |
1642 | ht.pt.y = (short)HIWORD(lParam); | |
9a624916 | 1643 | |
30bebfdc | 1644 | hit = MONTHCAL_HitTest(infoPtr, (LPARAM)&ht); |
9a624916 | 1645 | |
0bb2e5ab | 1646 | /* not on the calendar date numbers? bail out */ |
b7c84d3b AJ |
1647 | TRACE("hit:%x\n",hit); |
1648 | if((hit & MCHT_CALENDARDATE) != MCHT_CALENDARDATE) return 0; | |
0bb2e5ab AJ |
1649 | |
1650 | selday = ht.st.wDay; | |
1651 | oldselday = infoPtr->curSelDay; | |
1652 | infoPtr->curSelDay = selday; | |
b7c84d3b | 1653 | MONTHCAL_CalcPosFromDay(infoPtr, selday, ht.st. wMonth, &r); |
0bb2e5ab | 1654 | |
30bebfdc | 1655 | if(GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE) & MCS_MULTISELECT) { |
0bb2e5ab AJ |
1656 | SYSTEMTIME selArray[2]; |
1657 | int i; | |
1658 | ||
b7cc9c66 | 1659 | MONTHCAL_GetSelRange(infoPtr, (LPARAM)selArray); |
0bb2e5ab | 1660 | i = 0; |
b7c84d3b AJ |
1661 | if(infoPtr->firstSelDay==selArray[0].wDay) i=1; |
1662 | TRACE("oldRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); | |
9a624916 | 1663 | if(infoPtr->firstSelDay==selArray[1].wDay) { |
0bb2e5ab AJ |
1664 | /* 1st time we get here: selArray[0]=selArray[1]) */ |
1665 | /* if we're still at the first selected date, return */ | |
b7c84d3b AJ |
1666 | if(infoPtr->firstSelDay==selday) goto done; |
1667 | if(selday<infoPtr->firstSelDay) i = 0; | |
0bb2e5ab | 1668 | } |
9a624916 | 1669 | |
b7c84d3b AJ |
1670 | if(abs(infoPtr->firstSelDay - selday) >= infoPtr->maxSelCount) { |
1671 | if(selday>infoPtr->firstSelDay) | |
0bb2e5ab AJ |
1672 | selday = infoPtr->firstSelDay + infoPtr->maxSelCount; |
1673 | else | |
1674 | selday = infoPtr->firstSelDay - infoPtr->maxSelCount; | |
1675 | } | |
9a624916 | 1676 | |
b7c84d3b AJ |
1677 | if(selArray[i].wDay!=selday) { |
1678 | TRACE("newRange:%d %d %d %d\n", infoPtr->firstSelDay, selArray[0].wDay, selArray[1].wDay, i); | |
9a624916 | 1679 | |
0bb2e5ab | 1680 | selArray[i].wDay = selday; |
b2e91b6a | 1681 | |
b7c84d3b | 1682 | if(selArray[0].wDay>selArray[1].wDay) { |
0bb2e5ab AJ |
1683 | DWORD tempday; |
1684 | tempday = selArray[1].wDay; | |
1685 | selArray[1].wDay = selArray[0].wDay; | |
1686 | selArray[0].wDay = tempday; | |
1687 | } | |
b2e91b6a | 1688 | |
b7cc9c66 | 1689 | MONTHCAL_SetSelRange(infoPtr, (LPARAM)selArray); |
0bb2e5ab AJ |
1690 | } |
1691 | } | |
b2e91b6a AP |
1692 | |
1693 | done: | |
1694 | ||
0bb2e5ab | 1695 | /* only redraw if the currently selected day changed */ |
043c3e79 | 1696 | /* FIXME: this should specify a rectangle containing only the days that changed */ |
a4591933 | 1697 | /* using InvalidateRect */ |
043c3e79 | 1698 | if(oldselday != infoPtr->curSelDay) |
30bebfdc | 1699 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
b2e91b6a | 1700 | |
0bb2e5ab | 1701 | return 0; |
b2e91b6a AP |
1702 | } |
1703 | ||
0bb2e5ab | 1704 | |
b2e91b6a | 1705 | static LRESULT |
30bebfdc | 1706 | MONTHCAL_Paint(MONTHCAL_INFO *infoPtr, WPARAM wParam) |
b2e91b6a | 1707 | { |
0bb2e5ab AJ |
1708 | HDC hdc; |
1709 | PAINTSTRUCT ps; | |
b2e91b6a | 1710 | |
00176e33 DT |
1711 | if (wParam) |
1712 | { | |
30bebfdc | 1713 | GetClientRect(infoPtr->hwndSelf, &ps.rcPaint); |
00176e33 DT |
1714 | hdc = (HDC)wParam; |
1715 | } | |
1716 | else | |
30bebfdc | 1717 | hdc = BeginPaint(infoPtr->hwndSelf, &ps); |
043c3e79 | 1718 | |
30bebfdc DT |
1719 | MONTHCAL_Refresh(infoPtr, hdc, &ps); |
1720 | if (!wParam) EndPaint(infoPtr->hwndSelf, &ps); | |
0bb2e5ab | 1721 | return 0; |
b2e91b6a AP |
1722 | } |
1723 | ||
0bb2e5ab | 1724 | |
b2e91b6a | 1725 | static LRESULT |
d055cb8d | 1726 | MONTHCAL_KillFocus(const MONTHCAL_INFO *infoPtr, HWND hFocusWnd) |
b2e91b6a | 1727 | { |
b7c84d3b | 1728 | TRACE("\n"); |
b2e91b6a | 1729 | |
d055cb8d GB |
1730 | if (infoPtr->hwndNotify != hFocusWnd) |
1731 | ShowWindow(infoPtr->hwndSelf, SW_HIDE); | |
1732 | else | |
1733 | InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); | |
b2e91b6a | 1734 | |
0bb2e5ab | 1735 | return 0; |
b2e91b6a AP |
1736 | } |
1737 | ||
1738 | ||
1739 | static LRESULT | |
a8a469c7 | 1740 | MONTHCAL_SetFocus(const MONTHCAL_INFO *infoPtr) |
b2e91b6a | 1741 | { |
b7c84d3b | 1742 | TRACE("\n"); |
9a624916 | 1743 | |
30bebfdc | 1744 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); |
b2e91b6a | 1745 | |
0bb2e5ab | 1746 | return 0; |
b2e91b6a AP |
1747 | } |
1748 | ||
b7c84d3b | 1749 | /* sets the size information */ |
30bebfdc | 1750 | static void MONTHCAL_UpdateSize(MONTHCAL_INFO *infoPtr) |
b7c84d3b | 1751 | { |
30a66a05 DP |
1752 | static const WCHAR SunW[] = { 'S','u','n',0 }; |
1753 | static const WCHAR O0W[] = { '0','0',0 }; | |
30bebfdc | 1754 | HDC hdc = GetDC(infoPtr->hwndSelf); |
b7c84d3b AJ |
1755 | RECT *title=&infoPtr->title; |
1756 | RECT *prev=&infoPtr->titlebtnprev; | |
1757 | RECT *next=&infoPtr->titlebtnnext; | |
1758 | RECT *titlemonth=&infoPtr->titlemonth; | |
1759 | RECT *titleyear=&infoPtr->titleyear; | |
b0067efa UB |
1760 | RECT *wdays=&infoPtr->wdays; |
1761 | RECT *weeknumrect=&infoPtr->weeknums; | |
b7c84d3b | 1762 | RECT *days=&infoPtr->days; |
b0067efa | 1763 | RECT *todayrect=&infoPtr->todayrect; |
b7c84d3b | 1764 | SIZE size; |
30a66a05 | 1765 | TEXTMETRICW tm; |
30bebfdc | 1766 | DWORD dwStyle = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); |
b7c84d3b | 1767 | HFONT currentFont; |
00176e33 DT |
1768 | int xdiv, left_offset; |
1769 | RECT rcClient; | |
b7c84d3b | 1770 | |
30bebfdc | 1771 | GetClientRect(infoPtr->hwndSelf, &rcClient); |
b7c84d3b | 1772 | |
00176e33 | 1773 | currentFont = SelectObject(hdc, infoPtr->hFont); |
b7c84d3b AJ |
1774 | |
1775 | /* get the height and width of each day's text */ | |
30a66a05 | 1776 | GetTextMetricsW(hdc, &tm); |
00176e33 | 1777 | infoPtr->textHeight = tm.tmHeight + tm.tmExternalLeading + tm.tmInternalLeading; |
30a66a05 | 1778 | GetTextExtentPoint32W(hdc, SunW, 3, &size); |
b7c84d3b AJ |
1779 | infoPtr->textWidth = size.cx + 2; |
1780 | ||
00176e33 | 1781 | /* recalculate the height and width increments and offsets */ |
30a66a05 | 1782 | GetTextExtentPoint32W(hdc, O0W, 2, &size); |
b7c84d3b | 1783 | |
00176e33 | 1784 | xdiv = (dwStyle & MCS_WEEKNUMBERS) ? 8 : 7; |
b7c84d3b | 1785 | |
320814fb | 1786 | infoPtr->width_increment = size.cx * 2 + 4; |
00176e33 DT |
1787 | infoPtr->height_increment = infoPtr->textHeight; |
1788 | left_offset = (rcClient.right - rcClient.left) - (infoPtr->width_increment * xdiv); | |
9a624916 | 1789 | |
b7c84d3b | 1790 | /* calculate title area */ |
00176e33 DT |
1791 | title->top = rcClient.top; |
1792 | title->bottom = title->top + 3 * infoPtr->height_increment / 2; | |
1793 | title->left = left_offset; | |
1794 | title->right = rcClient.right; | |
b7c84d3b | 1795 | |
b7c84d3b AJ |
1796 | /* set the dimensions of the next and previous buttons and center */ |
1797 | /* the month text vertically */ | |
00176e33 DT |
1798 | prev->top = next->top = title->top + 4; |
1799 | prev->bottom = next->bottom = title->bottom - 4; | |
1800 | prev->left = title->left + 4; | |
b0067efa | 1801 | prev->right = prev->left + (title->bottom - title->top) ; |
00176e33 | 1802 | next->right = title->right - 4; |
b0067efa | 1803 | next->left = next->right - (title->bottom - title->top); |
9a624916 | 1804 | |
b7c84d3b AJ |
1805 | /* titlemonth->left and right change based upon the current month */ |
1806 | /* and are recalculated in refresh as the current month may change */ | |
1807 | /* without the control being resized */ | |
b0067efa UB |
1808 | titlemonth->top = titleyear->top = title->top + (infoPtr->height_increment)/2; |
1809 | titlemonth->bottom = titleyear->bottom = title->bottom - (infoPtr->height_increment)/2; | |
9a624916 | 1810 | |
b7c84d3b AJ |
1811 | /* setup the dimensions of the rectangle we draw the names of the */ |
1812 | /* days of the week in */ | |
00176e33 | 1813 | weeknumrect->left = left_offset; |
9a624916 | 1814 | if(dwStyle & MCS_WEEKNUMBERS) |
b0067efa UB |
1815 | weeknumrect->right=prev->right; |
1816 | else | |
1817 | weeknumrect->right=weeknumrect->left; | |
1818 | wdays->left = days->left = weeknumrect->right; | |
1819 | wdays->right = days->right = wdays->left + 7 * infoPtr->width_increment; | |
1820 | wdays->top = title->bottom ; | |
1821 | wdays->bottom = wdays->top + infoPtr->height_increment; | |
9a624916 | 1822 | |
b0067efa | 1823 | days->top = weeknumrect->top = wdays->bottom ; |
00176e33 | 1824 | days->bottom = weeknumrect->bottom = days->top + 6 * infoPtr->height_increment; |
9a624916 | 1825 | |
00176e33 DT |
1826 | todayrect->left = rcClient.left; |
1827 | todayrect->right = rcClient.right; | |
b0067efa UB |
1828 | todayrect->top = days->bottom; |
1829 | todayrect->bottom = days->bottom + infoPtr->height_increment; | |
1830 | ||
00176e33 | 1831 | TRACE("dx=%d dy=%d client[%s] title[%s] wdays[%s] days[%s] today[%s]\n", |
b0067efa | 1832 | infoPtr->width_increment,infoPtr->height_increment, |
00176e33 DT |
1833 | wine_dbgstr_rect(&rcClient), |
1834 | wine_dbgstr_rect(title), | |
1835 | wine_dbgstr_rect(wdays), | |
1836 | wine_dbgstr_rect(days), | |
1837 | wine_dbgstr_rect(todayrect)); | |
9a624916 | 1838 | |
b7c84d3b | 1839 | /* restore the originally selected font */ |
9a624916 | 1840 | SelectObject(hdc, currentFont); |
b7c84d3b | 1841 | |
30bebfdc | 1842 | ReleaseDC(infoPtr->hwndSelf, hdc); |
b7c84d3b AJ |
1843 | } |
1844 | ||
30bebfdc | 1845 | static LRESULT MONTHCAL_Size(MONTHCAL_INFO *infoPtr, int Width, int Height) |
b7c84d3b | 1846 | { |
30bebfdc | 1847 | TRACE("(width=%d, height=%d)\n", Width, Height); |
b7c84d3b | 1848 | |
30bebfdc | 1849 | MONTHCAL_UpdateSize(infoPtr); |
b7c84d3b AJ |
1850 | |
1851 | /* invalidate client area and erase background */ | |
30bebfdc | 1852 | InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); |
b7c84d3b AJ |
1853 | |
1854 | return 0; | |
1855 | } | |
b2e91b6a | 1856 | |
a8a469c7 | 1857 | static LRESULT MONTHCAL_GetFont(const MONTHCAL_INFO *infoPtr) |
30bebfdc DT |
1858 | { |
1859 | return (LRESULT)infoPtr->hFont; | |
1860 | } | |
1861 | ||
1862 | static LRESULT MONTHCAL_SetFont(MONTHCAL_INFO *infoPtr, HFONT hFont, BOOL redraw) | |
1863 | { | |
1864 | HFONT hOldFont; | |
1865 | LOGFONTW lf; | |
1866 | ||
1867 | if (!hFont) return 0; | |
1868 | ||
1869 | hOldFont = infoPtr->hFont; | |
1870 | infoPtr->hFont = hFont; | |
1871 | ||
1872 | GetObjectW(infoPtr->hFont, sizeof(lf), &lf); | |
1873 | lf.lfWeight = FW_BOLD; | |
1874 | infoPtr->hBoldFont = CreateFontIndirectW(&lf); | |
1875 | ||
9f1ea3f1 CS |
1876 | MONTHCAL_UpdateSize(infoPtr); |
1877 | ||
30bebfdc DT |
1878 | if (redraw) |
1879 | InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); | |
1880 | ||
1881 | return (LRESULT)hOldFont; | |
1882 | } | |
1883 | ||
25464cee | 1884 | /* update theme after a WM_THEMECHANGED message */ |
a8a469c7 | 1885 | static LRESULT theme_changed (const MONTHCAL_INFO* infoPtr) |
25464cee FR |
1886 | { |
1887 | HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); | |
1888 | CloseThemeData (theme); | |
56301248 | 1889 | OpenThemeData (infoPtr->hwndSelf, themeClass); |
25464cee FR |
1890 | return 0; |
1891 | } | |
1892 | ||
b2e91b6a | 1893 | /* FIXME: check whether dateMin/dateMax need to be adjusted. */ |
a867030e | 1894 | static LRESULT |
3dbdb311 | 1895 | MONTHCAL_Create(HWND hwnd, LPARAM lParam) |
a867030e | 1896 | { |
0bb2e5ab | 1897 | MONTHCAL_INFO *infoPtr; |
a867030e | 1898 | |
0bb2e5ab | 1899 | /* allocate memory for info structure */ |
b723e6f6 | 1900 | infoPtr = Alloc(sizeof(MONTHCAL_INFO)); |
cdb263e5 | 1901 | SetWindowLongPtrW(hwnd, 0, (DWORD_PTR)infoPtr); |
b2e91b6a | 1902 | |
b7c84d3b AJ |
1903 | if(infoPtr == NULL) { |
1904 | ERR( "could not allocate info memory!\n"); | |
0bb2e5ab AJ |
1905 | return 0; |
1906 | } | |
a867030e | 1907 | |
00176e33 | 1908 | infoPtr->hwndSelf = hwnd; |
c5940433 DP |
1909 | infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent; |
1910 | ||
30bebfdc | 1911 | MONTHCAL_SetFont(infoPtr, GetStockObject(DEFAULT_GUI_FONT), FALSE); |
0bb2e5ab AJ |
1912 | |
1913 | /* initialize info structure */ | |
b7c84d3b | 1914 | /* FIXME: calculate systemtime ->> localtime(substract timezoneinfo) */ |
0bb2e5ab | 1915 | |
320814fb | 1916 | GetLocalTime(&infoPtr->todaysDate); |
6fb16fca | 1917 | infoPtr->firstDayHighWord = FALSE; |
30bebfdc | 1918 | MONTHCAL_SetFirstDayOfWeek(infoPtr, (LPARAM)-1); |
0bb2e5ab AJ |
1919 | infoPtr->currentMonth = infoPtr->todaysDate.wMonth; |
1920 | infoPtr->currentYear = infoPtr->todaysDate.wYear; | |
b7c84d3b AJ |
1921 | MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->minDate); |
1922 | MONTHCAL_CopyTime(&infoPtr->todaysDate, &infoPtr->maxDate); | |
c401aa84 KF |
1923 | infoPtr->maxDate.wYear=2050; |
1924 | infoPtr->minDate.wYear=1950; | |
b0067efa | 1925 | infoPtr->maxSelCount = 7; |
0bb2e5ab | 1926 | infoPtr->monthRange = 3; |
7de279a7 | 1927 | infoPtr->monthdayState = Alloc |
b7c84d3b | 1928 | (infoPtr->monthRange * sizeof(MONTHDAYSTATE)); |
cf67786e NS |
1929 | infoPtr->titlebk = comctl32_color.clrActiveCaption; |
1930 | infoPtr->titletxt = comctl32_color.clrWindow; | |
1931 | infoPtr->monthbk = comctl32_color.clrWindow; | |
1932 | infoPtr->trailingtxt = comctl32_color.clrGrayText; | |
1933 | infoPtr->bk = comctl32_color.clrWindow; | |
1934 | infoPtr->txt = comctl32_color.clrWindowText; | |
b7c84d3b | 1935 | |
c5b8df48 VKK |
1936 | /* set the current day for highlighing */ |
1937 | infoPtr->minSel.wDay = infoPtr->todaysDate.wDay; | |
1938 | infoPtr->maxSel.wDay = infoPtr->todaysDate.wDay; | |
1939 | ||
b7c84d3b AJ |
1940 | /* call MONTHCAL_UpdateSize to set all of the dimensions */ |
1941 | /* of the control */ | |
30bebfdc | 1942 | MONTHCAL_UpdateSize(infoPtr); |
25464cee FR |
1943 | |
1944 | OpenThemeData (infoPtr->hwndSelf, themeClass); | |
0bb2e5ab AJ |
1945 | |
1946 | return 0; | |
a867030e EK |
1947 | } |
1948 | ||
1949 | ||
1950 | static LRESULT | |
30bebfdc | 1951 | MONTHCAL_Destroy(MONTHCAL_INFO *infoPtr) |
a867030e | 1952 | { |
0bb2e5ab | 1953 | /* free month calendar info data */ |
8784d47c | 1954 | Free(infoPtr->monthdayState); |
30bebfdc | 1955 | SetWindowLongPtrW(infoPtr->hwndSelf, 0, 0); |
8784d47c | 1956 | |
25464cee FR |
1957 | CloseThemeData (GetWindowTheme (infoPtr->hwndSelf)); |
1958 | ||
7de279a7 | 1959 | Free(infoPtr); |
0bb2e5ab | 1960 | return 0; |
a867030e EK |
1961 | } |
1962 | ||
1963 | ||
26ffb3cd | 1964 | static LRESULT WINAPI |
b7c84d3b | 1965 | MONTHCAL_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) |
a867030e | 1966 | { |
30bebfdc DT |
1967 | MONTHCAL_INFO *infoPtr; |
1968 | ||
3c9e7a7f | 1969 | TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam); |
30bebfdc DT |
1970 | |
1971 | infoPtr = MONTHCAL_GetInfoPtr(hwnd); | |
1972 | if (!infoPtr && (uMsg != WM_CREATE)) | |
30a66a05 | 1973 | return DefWindowProcW(hwnd, uMsg, wParam, lParam); |
b7c84d3b | 1974 | switch(uMsg) |
0bb2e5ab AJ |
1975 | { |
1976 | case MCM_GETCURSEL: | |
30bebfdc | 1977 | return MONTHCAL_GetCurSel(infoPtr, lParam); |
d144e4a3 | 1978 | |
0bb2e5ab | 1979 | case MCM_SETCURSEL: |
30bebfdc | 1980 | return MONTHCAL_SetCurSel(infoPtr, lParam); |
b2e91b6a | 1981 | |
0bb2e5ab | 1982 | case MCM_GETMAXSELCOUNT: |
30bebfdc | 1983 | return MONTHCAL_GetMaxSelCount(infoPtr); |
b2e91b6a | 1984 | |
0bb2e5ab | 1985 | case MCM_SETMAXSELCOUNT: |
30bebfdc | 1986 | return MONTHCAL_SetMaxSelCount(infoPtr, wParam); |
b2e91b6a | 1987 | |
0bb2e5ab | 1988 | case MCM_GETSELRANGE: |
30bebfdc | 1989 | return MONTHCAL_GetSelRange(infoPtr, lParam); |
b2e91b6a | 1990 | |
0bb2e5ab | 1991 | case MCM_SETSELRANGE: |
30bebfdc | 1992 | return MONTHCAL_SetSelRange(infoPtr, lParam); |
b2e91b6a | 1993 | |
0bb2e5ab | 1994 | case MCM_GETMONTHRANGE: |
30bebfdc | 1995 | return MONTHCAL_GetMonthRange(infoPtr); |
b2e91b6a | 1996 | |
0bb2e5ab | 1997 | case MCM_SETDAYSTATE: |
30bebfdc | 1998 | return MONTHCAL_SetDayState(infoPtr, wParam, lParam); |
b2e91b6a | 1999 | |
0bb2e5ab | 2000 | case MCM_GETMINREQRECT: |
30bebfdc | 2001 | return MONTHCAL_GetMinReqRect(infoPtr, lParam); |
b2e91b6a | 2002 | |
0bb2e5ab | 2003 | case MCM_GETCOLOR: |
30bebfdc | 2004 | return MONTHCAL_GetColor(infoPtr, wParam); |
b2e91b6a | 2005 | |
0bb2e5ab | 2006 | case MCM_SETCOLOR: |
30bebfdc | 2007 | return MONTHCAL_SetColor(infoPtr, wParam, lParam); |
b2e91b6a | 2008 | |
0bb2e5ab | 2009 | case MCM_GETTODAY: |
30bebfdc | 2010 | return MONTHCAL_GetToday(infoPtr, lParam); |
b2e91b6a | 2011 | |
0bb2e5ab | 2012 | case MCM_SETTODAY: |
30bebfdc | 2013 | return MONTHCAL_SetToday(infoPtr, lParam); |
b2e91b6a | 2014 | |
0bb2e5ab | 2015 | case MCM_HITTEST: |
30bebfdc | 2016 | return MONTHCAL_HitTest(infoPtr, lParam); |
b2e91b6a | 2017 | |
0bb2e5ab | 2018 | case MCM_GETFIRSTDAYOFWEEK: |
30bebfdc | 2019 | return MONTHCAL_GetFirstDayOfWeek(infoPtr); |
b2e91b6a | 2020 | |
0bb2e5ab | 2021 | case MCM_SETFIRSTDAYOFWEEK: |
30bebfdc | 2022 | return MONTHCAL_SetFirstDayOfWeek(infoPtr, lParam); |
b2e91b6a | 2023 | |
0bb2e5ab | 2024 | case MCM_GETRANGE: |
3dbdb311 | 2025 | return MONTHCAL_GetRange(hwnd, lParam); |
b2e91b6a | 2026 | |
0bb2e5ab | 2027 | case MCM_SETRANGE: |
30bebfdc | 2028 | return MONTHCAL_SetRange(infoPtr, wParam, lParam); |
b2e91b6a | 2029 | |
0bb2e5ab | 2030 | case MCM_GETMONTHDELTA: |
30bebfdc | 2031 | return MONTHCAL_GetMonthDelta(infoPtr); |
b2e91b6a | 2032 | |
0bb2e5ab | 2033 | case MCM_SETMONTHDELTA: |
30bebfdc | 2034 | return MONTHCAL_SetMonthDelta(infoPtr, wParam); |
b2e91b6a | 2035 | |
0bb2e5ab | 2036 | case MCM_GETMAXTODAYWIDTH: |
30bebfdc | 2037 | return MONTHCAL_GetMaxTodayWidth(infoPtr); |
b2e91b6a | 2038 | |
0bb2e5ab AJ |
2039 | case WM_GETDLGCODE: |
2040 | return DLGC_WANTARROWS | DLGC_WANTCHARS; | |
b2e91b6a | 2041 | |
0bb2e5ab | 2042 | case WM_KILLFOCUS: |
d055cb8d | 2043 | return MONTHCAL_KillFocus(infoPtr, (HWND)wParam); |
b2e91b6a | 2044 | |
b0067efa | 2045 | case WM_RBUTTONDOWN: |
30bebfdc | 2046 | return MONTHCAL_RButtonDown(infoPtr, lParam); |
b0067efa | 2047 | |
0bb2e5ab | 2048 | case WM_LBUTTONDOWN: |
30bebfdc | 2049 | return MONTHCAL_LButtonDown(infoPtr, lParam); |
b2e91b6a | 2050 | |
0bb2e5ab | 2051 | case WM_MOUSEMOVE: |
3dbdb311 | 2052 | return MONTHCAL_MouseMove(infoPtr, lParam); |
b2e91b6a | 2053 | |
0bb2e5ab | 2054 | case WM_LBUTTONUP: |
30bebfdc | 2055 | return MONTHCAL_LButtonUp(infoPtr, lParam); |
b2e91b6a | 2056 | |
e9310da5 | 2057 | case WM_PRINTCLIENT: |
0bb2e5ab | 2058 | case WM_PAINT: |
30bebfdc | 2059 | return MONTHCAL_Paint(infoPtr, wParam); |
b2e91b6a | 2060 | |
0bb2e5ab | 2061 | case WM_SETFOCUS: |
30bebfdc | 2062 | return MONTHCAL_SetFocus(infoPtr); |
b7c84d3b AJ |
2063 | |
2064 | case WM_SIZE: | |
30bebfdc | 2065 | return MONTHCAL_Size(infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam)); |
a867030e | 2066 | |
0bb2e5ab | 2067 | case WM_CREATE: |
3dbdb311 | 2068 | return MONTHCAL_Create(hwnd, lParam); |
a867030e | 2069 | |
30bebfdc DT |
2070 | case WM_SETFONT: |
2071 | return MONTHCAL_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); | |
2072 | ||
2073 | case WM_GETFONT: | |
2074 | return MONTHCAL_GetFont(infoPtr); | |
2075 | ||
0bb2e5ab | 2076 | case WM_TIMER: |
30bebfdc | 2077 | return MONTHCAL_Timer(infoPtr, wParam); |
25464cee FR |
2078 | |
2079 | case WM_THEMECHANGED: | |
2080 | return theme_changed (infoPtr); | |
d144e4a3 | 2081 | |
0bb2e5ab | 2082 | case WM_DESTROY: |
30bebfdc | 2083 | return MONTHCAL_Destroy(infoPtr); |
a867030e | 2084 | |
cf67786e NS |
2085 | case WM_SYSCOLORCHANGE: |
2086 | COMCTL32_RefreshSysColors(); | |
2087 | return 0; | |
2088 | ||
0bb2e5ab | 2089 | default: |
60a1e20b | 2090 | if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) |
3c9e7a7f | 2091 | ERR( "unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam); |
30a66a05 | 2092 | return DefWindowProcW(hwnd, uMsg, wParam, lParam); |
0bb2e5ab | 2093 | } |
a867030e EK |
2094 | } |
2095 | ||
2096 | ||
d144e4a3 | 2097 | void |
b7c84d3b | 2098 | MONTHCAL_Register(void) |
a867030e | 2099 | { |
30a66a05 | 2100 | WNDCLASSW wndClass; |
0bb2e5ab | 2101 | |
30a66a05 | 2102 | ZeroMemory(&wndClass, sizeof(WNDCLASSW)); |
0bb2e5ab | 2103 | wndClass.style = CS_GLOBALCLASS; |
8d28e031 | 2104 | wndClass.lpfnWndProc = MONTHCAL_WindowProc; |
0bb2e5ab AJ |
2105 | wndClass.cbClsExtra = 0; |
2106 | wndClass.cbWndExtra = sizeof(MONTHCAL_INFO *); | |
30a66a05 | 2107 | wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW); |
0bb2e5ab | 2108 | wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); |
30a66a05 | 2109 | wndClass.lpszClassName = MONTHCAL_CLASSW; |
9a624916 | 2110 | |
30a66a05 | 2111 | RegisterClassW(&wndClass); |
a867030e EK |
2112 | } |
2113 | ||
2114 | ||
d144e4a3 | 2115 | void |
b7c84d3b | 2116 | MONTHCAL_Unregister(void) |
a867030e | 2117 | { |
30a66a05 | 2118 | UnregisterClassW(MONTHCAL_CLASSW, NULL); |
a867030e | 2119 | } |