datetime.c 31.7 KB
Newer Older
1 2 3
/*
 * Date and time picker control
 *
4
 * Copyright 1998, 1999 Eric Kohl
5
 * Copyright 1999, 2000 Alex Priem <alexp@sci.kun.nl>
6
 * Copyright 2000 Chris Morgan <cmorgan@wpi.edu>
7 8 9 10 11 12 13 14
 *
 *
 * TODO:
 *   - All messages.
 *   - All notifications.
 *
 */

15 16 17 18
#include <math.h>
#include <string.h>
#include <stdio.h>

19
#include "winbase.h"
20
#include "wingdi.h"
21
#include "commctrl.h"
22
#include "debugtools.h"
23

24
DEFAULT_DEBUG_CHANNEL(datetime);
25

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
typedef struct
{
	HWND hMonthCal;
	HWND hUpdown;
	SYSTEMTIME date;
	BOOL dateValid;
	HWND hwndCheckbut;
	RECT rcClient; /* rect around the edge of the window */
	RECT rcDraw; /* rect inside of the border */
	RECT checkbox;  /* checkbox allowing the control to be enabled/disabled */
	RECT calbutton; /* button that toggles the dropdown of the monthcal control */
	BOOL bCalDepressed; /* TRUE = cal button is depressed */
	int  select;
	HFONT hFont;
	int nrFieldsAllocated;
	int nrFields;
	int haveFocus;
	int *fieldspec;
	RECT *fieldRect;
	int  *buflen;		
	char textbuf[256];
        POINT monthcal_pos;
} DATETIME_INFO, *LPDATETIME_INFO;

/* in monthcal.c */
51
extern int MONTHCAL_MonthLength(int month, int year);
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

/* this list of defines is closely related to `allowedformatchars' defined
 * in datetime.c; the high nibble indicates the `base type' of the format
 * specifier. 
 * Do not change without first reading DATETIME_UseFormat.
 * 
 */

#define DT_END_FORMAT      0 
#define ONEDIGITDAY   	0x01
#define TWODIGITDAY   	0x02
#define THREECHARDAY  	0x03
#define FULLDAY         0x04
#define ONEDIGIT12HOUR  0x11
#define TWODIGIT12HOUR  0x12
#define ONEDIGIT24HOUR  0x21
#define TWODIGIT24HOUR  0x22
#define ONEDIGITMINUTE  0x31
#define TWODIGITMINUTE  0x32
#define ONEDIGITMONTH   0x41
#define TWODIGITMONTH   0x42
#define THREECHARMONTH  0x43
#define FULLMONTH       0x44
#define ONEDIGITSECOND  0x51
#define TWODIGITSECOND  0x52
#define ONELETTERAMPM   0x61
#define TWOLETTERAMPM   0x62
#define ONEDIGITYEAR    0x71
#define TWODIGITYEAR    0x72
#define FULLYEAR        0x73
#define FORMATCALLBACK  0x81      /* -> maximum of 0x80 callbacks possible */
#define FORMATCALLMASK  0x80
#define DT_STRING 	0x0100

#define DTHT_DATEFIELD  0xff      /* for hit-testing */

#define DTHT_NONE     0
#define DTHT_CHECKBOX 0x200	/* these should end at '00' , to make */
#define DTHT_MCPOPUP  0x300     /* & DTHT_DATEFIELD 0 when DATETIME_KeyDown */
#define DTHT_GOTFOCUS 0x400     /* tests for date-fields */
92

93
#define DATETIME_GetInfoPtr(hwnd) ((DATETIME_INFO *)GetWindowLongA (hwnd, 0))
94

95 96 97 98 99 100
static BOOL DATETIME_SendSimpleNotify (HWND hwnd, UINT code);
static BOOL DATETIME_SendDateTimeChangeNotify (HWND hwnd);
extern void MONTHCAL_CopyTime(const SYSTEMTIME *from, SYSTEMTIME *to);
static const char *allowedformatchars = {"dhHmMstyX'"};
static const int maxrepetition [] = {4,2,2,2,4,2,2,3,-1,-1};

101 102 103 104 105 106 107 108

static LRESULT
DATETIME_GetSystemTime (HWND hwnd, WPARAM wParam, LPARAM lParam )
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
  DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
  SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;

109
  TRACE("%04x %08lx\n",wParam,lParam);
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
  if (!lParam) return GDT_NONE;

  if ((dwStyle & DTS_SHOWNONE) && 
       (SendMessageA (infoPtr->hwndCheckbut, BM_GETCHECK, 0, 0)))
        return GDT_NONE;

  MONTHCAL_CopyTime (&infoPtr->date, lprgSysTimeArray);

  return GDT_VALID;
}


static LRESULT
DATETIME_SetSystemTime (HWND hwnd, WPARAM wParam, LPARAM lParam )
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
  SYSTEMTIME *lprgSysTimeArray=(SYSTEMTIME *) lParam;

128
  TRACE("%04x %08lx\n",wParam,lParam);
129 130 131 132 133 134 135 136 137 138 139 140
  if (!lParam) return 0;

  if (lParam==GDT_VALID) 
  	MONTHCAL_CopyTime (lprgSysTimeArray, &infoPtr->date);
  if (lParam==GDT_NONE) {
	infoPtr->dateValid=FALSE;
    SendMessageA (infoPtr->hwndCheckbut, BM_SETCHECK, 0, 0);
	}
  return 1;
}


141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
static LRESULT
DATETIME_GetRange (HWND hwnd, LPARAM lParam )
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
  LRESULT ret;

  TRACE("%08lx\n", lParam);
  ret =  SendMessageA (infoPtr->hMonthCal, MCM_GETRANGE, 0, lParam);
  if (!ret) ret = 1; /* bug emulation... */
  return ret;
}

static LRESULT
DATETIME_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam )
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);

  TRACE("%04x %08lx\n",wParam,lParam);

  return SendMessageA (infoPtr->hMonthCal, MCM_SETRANGE, wParam, lParam);
}

163 164 165 166 167
static LRESULT
DATETIME_GetMonthCalColor (HWND hwnd, WPARAM wParam)
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);

168
  TRACE("%04x\n",wParam);
169 170 171
  return SendMessageA (infoPtr->hMonthCal, MCM_GETCOLOR, wParam, 0);
}

172

173 174 175 176 177
static LRESULT
DATETIME_SetMonthCalColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);

178
  TRACE("%04x %08lx\n",wParam,lParam);
179 180 181 182 183 184 185 186 187 188
  return SendMessageA (infoPtr->hMonthCal, MCM_SETCOLOR, wParam, lParam);
}


/* FIXME: need to get way to force font into monthcal structure */
static LRESULT
DATETIME_GetMonthCal (HWND hwnd)
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);

189
  TRACE("\n");
190 191 192 193 194 195 196 197 198 199 200
  return infoPtr->hMonthCal;
}



/* FIXME: need to get way to force font into monthcal structure */

static LRESULT
DATETIME_GetMonthCalFont (HWND hwnd)
{

201
  TRACE("\n");
202 203 204
  return 0;
}

205

206 207 208 209
static LRESULT
DATETIME_SetMonthCalFont (HWND hwnd, WPARAM wParam, LPARAM lParam)
{

210
  TRACE("%04x %08lx\n",wParam,lParam);
211 212 213 214
  return 0;
}


215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
/* 
   Split up a formattxt in actions. 
   See ms documentation for the meaning of the letter codes/'specifiers'.

   Notes: 
   *'dddddd' is handled as 'dddd' plus 'dd'.
   *unrecognized formats are strings (here given the type DT_STRING; 
   start of the string is encoded in lower bits of DT_STRING.
   Therefore, 'string' ends finally up as '<show seconds>tring'.

 */


static void 
DATETIME_UseFormat (DATETIME_INFO *infoPtr, const char *formattxt)
{
 int i,j,k,len;
 int *nrFields=& infoPtr->nrFields;

 TRACE ("%s\n",formattxt);


 *nrFields=0;
 infoPtr->fieldspec[*nrFields]=0;
 len=strlen(allowedformatchars);
 k=0;

 for (i=0; i<strlen (formattxt); i++)  {
	TRACE ("\n%d %c:",i, formattxt[i]);
 	for (j=0; j<len; j++) {
 		if (allowedformatchars[j]==formattxt[i]) {   
			TRACE ("%c[%d,%x]",allowedformatchars[j], *nrFields,
							 infoPtr->fieldspec[*nrFields]);
			if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) {
				infoPtr->fieldspec[*nrFields]=(j<<4) +1;
				break;
			}
			if (infoPtr->fieldspec[*nrFields]>>4!=j) {   
				(*nrFields)++;	
				infoPtr->fieldspec[*nrFields]=(j<<4) +1;
				break;
			}
			if ((infoPtr->fieldspec[*nrFields] & 0x0f)==maxrepetition[j]) {
				(*nrFields)++;	
				infoPtr->fieldspec[*nrFields]=(j<<4) +1;
				break;
			}
			infoPtr->fieldspec[*nrFields]++;
			break;
		}   /* if allowedformatchar */
	 } /* for j */


			/* char is not a specifier: handle char like a string */
	if (j==len) {
		if ((*nrFields==0) && (infoPtr->fieldspec[*nrFields]==0)) {
			infoPtr->fieldspec[*nrFields]=DT_STRING+k;
			infoPtr->buflen[*nrFields]=0;
        } else 
		if ((infoPtr->fieldspec[*nrFields] & DT_STRING)!=DT_STRING)  {
			(*nrFields)++;
			infoPtr->fieldspec[*nrFields]=DT_STRING+k;
			infoPtr->buflen[*nrFields]=0;
		} 
		infoPtr->textbuf[k]=formattxt[i];
		k++;
		infoPtr->buflen[*nrFields]++;
	}   /* if j=len */

	if (*nrFields==infoPtr->nrFieldsAllocated) {
		FIXME ("out of memory; should reallocate. crash ahead.\n");
	}

  } /* for i */

290 291 292
  TRACE("\n");

  if (infoPtr->fieldspec[*nrFields]!=0) (*nrFields)++;
293 294
}

295

296 297 298 299
static LRESULT 
DATETIME_SetFormat (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
 DATETIME_INFO *infoPtr= DATETIME_GetInfoPtr (hwnd);
300 301
 char format_buf[80];
 DWORD format_item;
302

303
 TRACE("%04x %08lx\n",wParam,lParam);
304 305 306 307
 if (!lParam) {
  	DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);

	if (dwStyle & DTS_LONGDATEFORMAT) 
308
		format_item=LOCALE_SLONGDATE;
309
	else if (dwStyle & DTS_TIMEFORMAT) 
310
		format_item=LOCALE_STIMEFORMAT;
311
        else /* DTS_SHORTDATEFORMAT */
312 313 314
		format_item=LOCALE_SSHORTDATE;
	GetLocaleInfoA( GetSystemDefaultLCID(), format_item,format_buf,sizeof(format_buf));
	DATETIME_UseFormat (infoPtr, format_buf);
315 316 317 318 319 320 321
 } 	
 else
 	DATETIME_UseFormat (infoPtr, (char *) lParam);

 return infoPtr->nrFields;
}

322

323 324 325 326
static LRESULT 
DATETIME_SetFormatW (HWND hwnd, WPARAM wParam, LPARAM lParam)

{
327
 TRACE("%04x %08lx\n",wParam,lParam);
328 329 330
 if (lParam) {
	LPSTR buf;
	int retval;
331
        int len = WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lParam, -1, NULL, 0, NULL, NULL );
332 333

 	buf = (LPSTR) COMCTL32_Alloc (len);
334
        WideCharToMultiByte( CP_ACP, 0, (LPWSTR)lParam, -1, buf, len, NULL, NULL );
335 336 337 338 339 340 341 342 343
	retval=DATETIME_SetFormat (hwnd, 0, (LPARAM) buf);
	COMCTL32_Free (buf);
	return retval;
 } 
 else
	return DATETIME_SetFormat (hwnd, 0, 0);

}

344

345 346 347 348 349
static void 
DATETIME_ReturnTxt (DATETIME_INFO *infoPtr, int count, char *result)
{
 SYSTEMTIME date = infoPtr->date;
 int spec;
350
 char buffer[80];
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370

 *result=0;
 TRACE ("%d,%d\n", infoPtr->nrFields, count);
 if ((count>infoPtr->nrFields) || (count<0)) {
	WARN ("buffer overrun, have %d want %d\n", infoPtr->nrFields, count);
	return;
 }

 if (!infoPtr->fieldspec) return;
 
 spec=infoPtr->fieldspec[count];
 if (spec & DT_STRING) {
	int txtlen=infoPtr->buflen[count];

	strncpy (result, infoPtr->textbuf + (spec &~ DT_STRING), txtlen);
	result[txtlen]=0;
	TRACE ("arg%d=%x->[%s]\n",count,infoPtr->fieldspec[count],result);
	return;
 }

371
		
372 373 374 375 376 377 378 379 380 381 382
 switch (spec) {
	case DT_END_FORMAT: 
		*result=0;
		break;
	case ONEDIGITDAY: 
		sprintf (result,"%d",date.wDay);
	 	break;
	case TWODIGITDAY: 
		sprintf (result,"%.2d",date.wDay);
		break;
	case THREECHARDAY: 
383 384 385
	        GetLocaleInfoA( LOCALE_USER_DEFAULT, LOCALE_SABBREVDAYNAME1+(date.wDayOfWeek+6)%7,
				result,4);
		/*sprintf (result,"%.3s",days[date.wDayOfWeek]);*/
386
		break;
387 388 389 390
	case FULLDAY:
	        GetLocaleInfoA( LOCALE_USER_DEFAULT,LOCALE_SDAYNAME1+ (date.wDayOfWeek+6)%7,
				buffer,sizeof(buffer));
		strcpy  (result,buffer);
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
		break;
	case ONEDIGIT12HOUR: 
		if (date.wHour>12) 
			sprintf (result,"%d",date.wHour-12);
		else 
			sprintf (result,"%d",date.wHour);
		break;
	case TWODIGIT12HOUR: 
		if (date.wHour>12) 
			sprintf (result,"%.2d",date.wHour-12);
		else 
			sprintf (result,"%.2d",date.wHour);
		break;
	case ONEDIGIT24HOUR: 
		sprintf (result,"%d",date.wHour);
		break;
	case TWODIGIT24HOUR: 
		sprintf (result,"%.2d",date.wHour);
		break;
	case ONEDIGITSECOND: 
		sprintf (result,"%d",date.wSecond);
		break;
	case TWODIGITSECOND: 
		sprintf (result,"%.2d",date.wSecond);
		break;
	case ONEDIGITMINUTE: 
		sprintf (result,"%d",date.wMinute);
		break;
	case TWODIGITMINUTE: 
		sprintf (result,"%.2d",date.wMinute);
		break;
	case ONEDIGITMONTH: 
		sprintf (result,"%d",date.wMonth);
	 	break;
	case TWODIGITMONTH: 
		sprintf (result,"%.2d",date.wMonth);
		break;
	case THREECHARMONTH: 
429 430 431
		GetLocaleInfoA( GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1,
		  buffer,sizeof(buffer));
		sprintf (result,"%.3s",buffer);
432 433
		break;
	case FULLMONTH:   
434 435
		GetLocaleInfoA( GetSystemDefaultLCID(),LOCALE_SMONTHNAME1+date.wMonth -1,
		  result,sizeof(result));
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
		break;
	case ONELETTERAMPM:   
		if (date.wHour<12) 
			strcpy (result,"A");
		else 
			strcpy (result,"P");
		break;
	case TWOLETTERAMPM:   
		if (date.wHour<12) 
			strcpy (result,"AM");
		else 
			strcpy (result,"PM");
		break;
	case FORMATCALLBACK:   
		FIXME ("Not implemented\n");
		strcpy (result,"xxx");
		break;
	case ONEDIGITYEAR: 
		sprintf (result,"%d",date.wYear-10* (int) floor(date.wYear/10));
	 	break;
	case TWODIGITYEAR: 
		sprintf (result,"%.2d",date.wYear-100* (int) floor(date.wYear/100));
		break;
	case FULLYEAR:   
		sprintf (result,"%d",date.wYear);
		break;
    }
	
	TRACE ("arg%d=%x->[%s]\n",count,infoPtr->fieldspec[count],result);
}

467

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
static void 
DATETIME_IncreaseField (DATETIME_INFO *infoPtr, int number)
{
 SYSTEMTIME *date = &infoPtr->date;
 int spec;

 TRACE ("%d\n",number);
 if ((number>infoPtr->nrFields) || (number<0)) return;

 spec=infoPtr->fieldspec[number];
 if ((spec & DTHT_DATEFIELD)==0) return;
		
 switch (spec) {
	case ONEDIGITDAY: 
	case TWODIGITDAY: 
	case THREECHARDAY: 
	case FULLDAY:
		date->wDay++;
486 487
		if (date->wDay>MONTHCAL_MonthLength(date->wMonth,date->wYear))
		  date->wDay=1;	
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
		break;
	case ONEDIGIT12HOUR: 
	case TWODIGIT12HOUR: 
	case ONEDIGIT24HOUR: 
	case TWODIGIT24HOUR: 
		date->wHour++;
		if (date->wHour>23) date->wHour=0;
		break;
	case ONEDIGITSECOND: 
	case TWODIGITSECOND: 
		date->wSecond++;
		if (date->wSecond>59) date->wSecond=0;
		break;
	case ONEDIGITMINUTE: 
	case TWODIGITMINUTE: 
		date->wMinute++;
		if (date->wMinute>59) date->wMinute=0;
		break;
	case ONEDIGITMONTH: 
	case TWODIGITMONTH: 
	case THREECHARMONTH: 
	case FULLMONTH:   
		date->wMonth++;
		if (date->wMonth>12) date->wMonth=1;
512 513
		if (date->wDay>MONTHCAL_MonthLength(date->wMonth,date->wYear)) 
			date->wDay=MONTHCAL_MonthLength(date->wMonth,date->wYear);
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
		break;
	case ONELETTERAMPM:   
	case TWOLETTERAMPM:   
		date->wHour+=12;
		if (date->wHour>23) date->wHour-=24;
		break;
	case FORMATCALLBACK:   
		FIXME ("Not implemented\n");
		break;
	case ONEDIGITYEAR: 
	case TWODIGITYEAR: 
	case FULLYEAR:   
		date->wYear++;
		break;
	}

}

532

533 534 535 536 537 538 539 540 541
static void 
DATETIME_DecreaseField (DATETIME_INFO *infoPtr, int number)
{
 SYSTEMTIME *date = & infoPtr->date;
 int spec;

 TRACE ("%d\n",number);
 if ((number>infoPtr->nrFields) || (number<0)) return;

542
 spec = infoPtr->fieldspec[number];
543 544 545 546 547 548 549 550 551 552
 if ((spec & DTHT_DATEFIELD)==0) return;
		
 TRACE ("%x\n",spec);

 switch (spec) {
	case ONEDIGITDAY: 
	case TWODIGITDAY: 
	case THREECHARDAY: 
	case FULLDAY:
		date->wDay--;
553 554
		if (date->wDay<1) 
		  date->wDay=MONTHCAL_MonthLength(date->wMonth,date->wYear);
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586
		break;
	case ONEDIGIT12HOUR: 
	case TWODIGIT12HOUR: 
	case ONEDIGIT24HOUR: 
	case TWODIGIT24HOUR: 
		if (date->wHour) 
			date->wHour--;
		else
			date->wHour=23;
		break;
	case ONEDIGITSECOND: 
	case TWODIGITSECOND: 
		if (date->wHour) 
			date->wSecond--;
		else
			date->wHour=59;
		break;
	case ONEDIGITMINUTE: 
	case TWODIGITMINUTE: 
		if (date->wMinute) 
			date->wMinute--;
		else
			date->wMinute=59;
		break;
	case ONEDIGITMONTH: 
	case TWODIGITMONTH: 
	case THREECHARMONTH: 
	case FULLMONTH:   
		if (date->wMonth>1) 
			date->wMonth--;
		else
			date->wMonth=12;
587 588
		if (date->wDay>MONTHCAL_MonthLength(date->wMonth,date->wYear)) 
			date->wDay=MONTHCAL_MonthLength(date->wMonth,date->wYear);
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618
		break;
	case ONELETTERAMPM:   
	case TWOLETTERAMPM:   
		if (date->wHour<12) 
			date->wHour+=12;
		else
			date->wHour-=12;
		break;
	case FORMATCALLBACK:   
		FIXME ("Not implemented\n");
		break;
	case ONEDIGITYEAR: 
	case TWODIGITYEAR: 
	case FULLYEAR:   
		date->wYear--;
		break;
	}

}


static void 
DATETIME_ResetFieldDown (DATETIME_INFO *infoPtr, int number)
{
 SYSTEMTIME *date = &infoPtr->date;
 int spec;

 TRACE ("%d\n",number);
 if ((number>infoPtr->nrFields) || (number<0)) return;

619
 spec = infoPtr->fieldspec[number];
620 621 622 623 624 625 626 627
 if ((spec & DTHT_DATEFIELD)==0) return;
		

 switch (spec) {
	case ONEDIGITDAY: 
	case TWODIGITDAY: 
	case THREECHARDAY: 
	case FULLDAY:
628
		date->wDay = 1;
629 630 631 632 633 634 635
		break;
	case ONEDIGIT12HOUR: 
	case TWODIGIT12HOUR: 
	case ONEDIGIT24HOUR: 
	case TWODIGIT24HOUR: 
	case ONELETTERAMPM:   
	case TWOLETTERAMPM:   
636
		date->wHour = 0;
637 638 639
		break;
	case ONEDIGITSECOND: 
	case TWODIGITSECOND: 
640
		date->wSecond = 0;
641 642 643
		break;
	case ONEDIGITMINUTE: 
	case TWODIGITMINUTE: 
644
		date->wMinute = 0;
645 646 647 648 649
		break;
	case ONEDIGITMONTH: 
	case TWODIGITMONTH: 
	case THREECHARMONTH: 
	case FULLMONTH:   
650
		date->wMonth = 1;
651 652 653 654 655
	case FORMATCALLBACK:   
		FIXME ("Not implemented\n");
		break;
	case ONEDIGITYEAR: 
	case TWODIGITYEAR: 
656 657 658 659 660
        /* FYI: On 1752/9/14 the calendar changed and England and the 
         * American colonies changed to the Gregorian calendar. This change 
         * involved having September 14th follow September 2nd. So no date 
         * algorithm works before that date.
         */
661
	case FULLYEAR:   
662 663 664 665 666 667
		date->wSecond = 0;
		date->wMinute = 0;
		date->wHour = 0;
		date->wDay = 14;		/* overactive ms-programmers..*/
		date->wMonth = 9;
		date->wYear = 1752;
668 669 670 671 672
		break;
	}

}

673

674 675 676 677 678 679
static void 
DATETIME_ResetFieldUp (DATETIME_INFO *infoPtr, int number)
{
 SYSTEMTIME *date = & infoPtr->date;
 int spec;

680
 TRACE("%d \n",number);
681 682 683 684 685 686 687 688 689 690
 if ((number>infoPtr->nrFields) || (number<0)) return;

 spec=infoPtr->fieldspec[number];
 if ((spec & DTHT_DATEFIELD)==0) return;
		
 switch (spec) {
	case ONEDIGITDAY: 
	case TWODIGITDAY: 
	case THREECHARDAY: 
	case FULLDAY:
691
		date->wDay=MONTHCAL_MonthLength(date->wMonth,date->wYear);
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
		break;
	case ONEDIGIT12HOUR: 
	case TWODIGIT12HOUR: 
	case ONEDIGIT24HOUR: 
	case TWODIGIT24HOUR: 
	case ONELETTERAMPM:   
	case TWOLETTERAMPM:   
		date->wHour=23;
		break;
	case ONEDIGITSECOND: 
	case TWODIGITSECOND: 
		date->wSecond=59;
		break;
	case ONEDIGITMINUTE: 
	case TWODIGITMINUTE: 
		date->wMinute=59;
		break;
	case ONEDIGITMONTH: 
	case TWODIGITMONTH: 
	case THREECHARMONTH: 
	case FULLMONTH:   
		date->wMonth=12;
	case FORMATCALLBACK:   
		FIXME ("Not implemented\n");
		break;
	case ONEDIGITYEAR: 
	case TWODIGITYEAR: 
	case FULLYEAR:   
		date->wYear=9999;    /* Y10K problem? naaah. */
		break;
	}

}


727 728 729 730
static void DATETIME_Refresh (HWND hwnd, HDC hdc)

{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
731 732
  int i,prevright;
  RECT *field;
733
  DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
734 735 736 737
  RECT *rcDraw = &infoPtr->rcDraw;
  RECT *rcClient = &infoPtr->rcClient;
  RECT *calbutton = &infoPtr->calbutton;
  RECT *checkbox = &infoPtr->checkbox;
738
  HBRUSH hbr;
739
  SIZE size;
740
  COLORREF oldBk, oldTextColor;
741
  
742
  /* draw control edge */
743
  TRACE("\n");
744 745 746 747
  hbr = CreateSolidBrush(RGB(255, 255, 255));
  FillRect(hdc, rcClient, hbr);
  DrawEdge(hdc, rcClient, EDGE_SUNKEN, BF_RECT);
  DeleteObject(hbr);   
748 749 750
	
  if (infoPtr->dateValid) {
    char txt[80];
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
    HFONT oldFont;
    oldFont = SelectObject (hdc, infoPtr->hFont);

    DATETIME_ReturnTxt (infoPtr, 0, txt);
    GetTextExtentPoint32A (hdc, txt, strlen (txt), &size);
    rcDraw->bottom = size.cy+2;

    if (dwStyle & DTS_SHOWNONE) checkbox->right = 18;

    prevright = checkbox->right;

    for (i=0; i<infoPtr->nrFields; i++) {
      DATETIME_ReturnTxt (infoPtr, i, txt);
      GetTextExtentPoint32A (hdc, txt, strlen (txt), &size);
      field = & infoPtr->fieldRect[i];
      field->left  = prevright;
      field->right = prevright+size.cx;
      field->top   = rcDraw->top;
      field->bottom = rcDraw->bottom;
      prevright = field->right;

      if ((infoPtr->haveFocus) && (i==infoPtr->select)) {
        hbr = CreateSolidBrush (GetSysColor (COLOR_ACTIVECAPTION));
        FillRect(hdc, field, hbr);
        oldBk = SetBkColor (hdc, GetSysColor(COLOR_ACTIVECAPTION));
        oldTextColor = SetTextColor (hdc, GetSysColor(COLOR_WINDOW));
        DeleteObject (hbr);
        DrawTextA ( hdc, txt, strlen(txt), field,
              DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
        SetBkColor (hdc, oldBk);
781
		SetTextColor (hdc, oldTextColor);
782 783 784
      }
      else
        DrawTextA ( hdc, txt, strlen(txt), field,
785
                         DT_RIGHT | DT_VCENTER | DT_SINGLELINE );
786
    }
787

788 789
    SelectObject (hdc, oldFont);
  }
790

791 792 793 794 795
  if (!(dwStyle & DTS_UPDOWN)) {
    DrawFrameControl(hdc, calbutton, DFC_SCROLL,
        DFCS_SCROLLDOWN | (infoPtr->bCalDepressed ? DFCS_PUSHED : 0) |
        (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
  }
796 797
}

798

799 800 801
static LRESULT
DATETIME_HitTest (HWND hwnd, DATETIME_INFO *infoPtr, POINT pt)
{
802
  int i, retval;
803

804 805
  TRACE ("%ld, %ld\n",pt.x,pt.y);

806 807 808 809 810
  retval = DTHT_NONE;
  if (PtInRect (&infoPtr->calbutton, pt))
    {retval = DTHT_MCPOPUP; TRACE("Hit in calbutton(DTHT_MCPOPUP)\n"); goto done; }
  if (PtInRect (&infoPtr->checkbox, pt))
    {retval = DTHT_CHECKBOX; TRACE("Hit in checkbox(DTHT_CHECKBOX)\n"); goto done; }
811

812
  for (i=0; i<infoPtr->nrFields; i++) {
813 814 815 816 817
    if (PtInRect (&infoPtr->fieldRect[i], pt)) {
      retval = i;
      TRACE("Hit in date text in field %d\n", i);           
      break;
    }
818 819 820 821
 }

done:
  return retval;
822 823
}

824

825 826 827
static LRESULT
DATETIME_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
828
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	
829 830
  DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
  int old, new;
831
  POINT pt;
832

833 834
  TRACE ("\n");

835 836 837
  old = infoPtr->select;
  pt.x = (INT)LOWORD(lParam);
  pt.y = (INT)HIWORD(lParam);
838

839
  new = DATETIME_HitTest (hwnd, infoPtr, pt);
840

841 842
  /* FIXME: might be conditions where we don't want to update infoPtr->select */
  infoPtr->select = new;
843

844 845
  if (infoPtr->select != old) {
    infoPtr->haveFocus = DTHT_GOTFOCUS;
846 847
   }

848 849
  if (infoPtr->select == DTHT_MCPOPUP) {
    /* FIXME: button actually is only depressed during dropdown of the */
850
    /* calendar control and when the mouse is over the button window */
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
    infoPtr->bCalDepressed = TRUE;

    /* recalculate the position of the monthcal popup */
    if(dwStyle & DTS_RIGHTALIGN)
      infoPtr->monthcal_pos.x = infoPtr->rcClient.right - ((infoPtr->calbutton.right -
                                infoPtr->calbutton.left) + 145);
    else 
      infoPtr->monthcal_pos.x = 8;

    infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom;
    ClientToScreen (hwnd, &(infoPtr->monthcal_pos));
    SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x,
        infoPtr->monthcal_pos.y, 145, 150, 0);

    if(IsWindowVisible(infoPtr->hMonthCal))
        ShowWindow(infoPtr->hMonthCal, SW_HIDE);
    else
        ShowWindow(infoPtr->hMonthCal, SW_SHOW);

    TRACE ("dt:%x mc:%x mc parent:%x, desktop:%x, mcpp:%x\n",
              hwnd,infoPtr->hMonthCal, 
              GetParent (infoPtr->hMonthCal),
              GetDesktopWindow (),
              GetParent (GetParent (infoPtr->hMonthCal)));
    DATETIME_SendSimpleNotify (hwnd, DTN_DROPDOWN);
  }

  InvalidateRect(hwnd, NULL, FALSE);
879

880 881 882 883 884 885 886 887 888 889 890 891 892
  return 0;
}


static LRESULT
DATETIME_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	

  TRACE("\n");
  
  if(infoPtr->bCalDepressed == TRUE) {
    infoPtr->bCalDepressed = FALSE;
893
    InvalidateRect(hwnd, &(infoPtr->calbutton), TRUE);
894 895 896
  }

  return 0;
897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
}


static LRESULT
DATETIME_Paint (HWND hwnd, WPARAM wParam)
{
    HDC hdc;
    PAINTSTRUCT ps;

    hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
    DATETIME_Refresh (hwnd, hdc);
    if(!wParam)
    EndPaint (hwnd, &ps);
    return 0;
}

913

914 915 916
static LRESULT
DATETIME_ParentNotify (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
917
 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	
918
 LPNMHDR lpnmh = (LPNMHDR) lParam;
919

920 921 922 923
 TRACE ("%x,%lx\n",wParam, lParam);
 TRACE ("Got notification %x from %x\n", lpnmh->code, lpnmh->hwndFrom);
 TRACE ("info: %x %x %x\n",hwnd,infoPtr->hMonthCal,infoPtr->hUpdown);
 return 0;
924 925
}

926

927 928 929 930
static LRESULT
DATETIME_Notify (HWND hwnd, WPARAM wParam, LPARAM lParam)

{
931
 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	
932
 LPNMHDR lpnmh = (LPNMHDR) lParam;
933

934 935 936 937
 TRACE ("%x,%lx\n",wParam, lParam);
 TRACE ("Got notification %x from %x\n", lpnmh->code, lpnmh->hwndFrom);
 TRACE ("info: %x %x %x\n",hwnd,infoPtr->hMonthCal,infoPtr->hUpdown);
 return 0;
938 939
}

940 941 942 943 944 945 946 947 948

static LRESULT 
DATETIME_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
 int FieldNum,wrap=0;

 TRACE("%x %lx %x\n",wParam, lParam, infoPtr->select);

949
 FieldNum = infoPtr->select & DTHT_DATEFIELD;
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979

 if (!(infoPtr->haveFocus)) return 0;
 if ((FieldNum==0) && (infoPtr->select)) return 0;

 if (infoPtr->select & FORMATCALLMASK) {
	FIXME ("Callbacks not implemented yet\n");
 }

 switch (wParam) {
	case VK_ADD:
    	case VK_UP: 
		DATETIME_IncreaseField (infoPtr,FieldNum);
		DATETIME_SendDateTimeChangeNotify (hwnd);
		break;
	case VK_SUBTRACT:
	case VK_DOWN:
		DATETIME_DecreaseField (infoPtr,FieldNum);
		DATETIME_SendDateTimeChangeNotify (hwnd);
		break;
	case VK_HOME:
		DATETIME_ResetFieldDown (infoPtr,FieldNum);
		DATETIME_SendDateTimeChangeNotify (hwnd);
		break;
	case VK_END:
		DATETIME_ResetFieldUp(infoPtr,FieldNum);
		DATETIME_SendDateTimeChangeNotify (hwnd);
		break;
	case VK_LEFT: 
		do {
			if (infoPtr->select==0) {
980
				infoPtr->select = infoPtr->nrFields - 1;
981 982 983 984 985 986 987 988 989 990
				wrap++;
			} else 
			infoPtr->select--;
		}
		while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2));
		break;
	case VK_RIGHT:	
		do {
			infoPtr->select++;
			if (infoPtr->select==infoPtr->nrFields) {
991
				infoPtr->select = 0;
992 993 994 995 996 997 998
				wrap++;
			}
			}
		while ((infoPtr->fieldspec[infoPtr->select] & DT_STRING) && (wrap<2));
		break;
	}

999
  InvalidateRect(hwnd, NULL, FALSE);
1000 1001 1002 1003 1004

  return 0;
}


1005 1006 1007 1008 1009 1010 1011
static LRESULT
DATETIME_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	

    TRACE ("\n");

1012 1013 1014 1015
    if (infoPtr->haveFocus) {
	DATETIME_SendSimpleNotify (hwnd, NM_KILLFOCUS);
	infoPtr->haveFocus = 0;
    }
1016

1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
    InvalidateRect (hwnd, NULL, TRUE);

    return 0;
}


static LRESULT
DATETIME_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	

    TRACE ("\n");

1030 1031
    if (infoPtr->haveFocus==0) {
	DATETIME_SendSimpleNotify (hwnd, NM_SETFOCUS);	
1032
	infoPtr->haveFocus = DTHT_GOTFOCUS;
1033
    }
1034 1035

    InvalidateRect(hwnd, NULL, FALSE);
1036 1037 1038 1039 1040

    return 0;
}


1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
static BOOL
DATETIME_SendDateTimeChangeNotify (HWND hwnd)

{
 DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);	
 NMDATETIMECHANGE dtdtc;

 TRACE ("\n");
 dtdtc.nmhdr.hwndFrom = hwnd;
 dtdtc.nmhdr.idFrom   = GetWindowLongA( hwnd, GWL_ID);
 dtdtc.nmhdr.code     = DTN_DATETIMECHANGE;

 if ((GetWindowLongA (hwnd, GWL_STYLE) & DTS_SHOWNONE))
1054
   dtdtc.dwFlags = GDT_NONE;
1055
 else
1056
   dtdtc.dwFlags = GDT_VALID;
1057 1058 1059 1060 1061 1062 1063

 MONTHCAL_CopyTime (&infoPtr->date, &dtdtc.st);
 return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
                              (WPARAM)dtdtc.nmhdr.idFrom, (LPARAM)&dtdtc);
}


1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
static BOOL
DATETIME_SendSimpleNotify (HWND hwnd, UINT code)
{
    NMHDR nmhdr;

    TRACE("%x\n",code);
    nmhdr.hwndFrom = hwnd;
    nmhdr.idFrom   = GetWindowLongA( hwnd, GWL_ID);
    nmhdr.code     = code;

    return (BOOL) SendMessageA (GetParent (hwnd), WM_NOTIFY,
1075
                                (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1076
}
1077

1078 1079 1080 1081 1082
static LRESULT
DATETIME_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr(hwnd);
  DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
1083

1084 1085 1086
  /* set size */
  infoPtr->rcClient.bottom = HIWORD(lParam);
  infoPtr->rcClient.right = LOWORD(lParam);
1087

1088
  TRACE("Height=%d, Width=%d\n", infoPtr->rcClient.bottom, infoPtr->rcClient.right);
1089

1090 1091
  /* use DrawEdge to adjust the size of rcEdge to get rcDraw */
  memcpy((&infoPtr->rcDraw), (&infoPtr->rcClient), sizeof(infoPtr->rcDraw));
1092

1093
  DrawEdge((HDC)NULL, &(infoPtr->rcDraw), EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1094

1095
  /* set the size of the button that drops the calendar down */
1096 1097 1098 1099 1100
  /* FIXME: account for style that allows button on left side */
  infoPtr->calbutton.top   = infoPtr->rcDraw.top;
  infoPtr->calbutton.bottom= infoPtr->rcDraw.bottom;
  infoPtr->calbutton.left  = infoPtr->rcDraw.right-15;
  infoPtr->calbutton.right = infoPtr->rcDraw.right;
1101

1102 1103 1104 1105 1106 1107
  /* set enable/disable button size for show none style being enabled */
  /* FIXME: these dimensions are completely incorrect */
  infoPtr->checkbox.top = infoPtr->rcDraw.top;
  infoPtr->checkbox.bottom = infoPtr->rcDraw.bottom;
  infoPtr->checkbox.left = infoPtr->rcDraw.left;
  infoPtr->checkbox.right = infoPtr->rcDraw.left + 10;
1108

1109 1110 1111 1112 1113 1114
  /* update the position of the monthcal control */
  if(dwStyle & DTS_RIGHTALIGN)
    infoPtr->monthcal_pos.x = infoPtr->rcClient.right - ((infoPtr->calbutton.right -
                                infoPtr->calbutton.left) + 145);
  else 
    infoPtr->monthcal_pos.x = 8;
1115

1116 1117 1118 1119 1120
  infoPtr->monthcal_pos.y = infoPtr->rcClient.bottom;
  ClientToScreen (hwnd, &(infoPtr->monthcal_pos));
  SetWindowPos(infoPtr->hMonthCal, 0, infoPtr->monthcal_pos.x,
    infoPtr->monthcal_pos.y,
    145, 150, 0);
1121

1122
  InvalidateRect(hwnd, NULL, FALSE);
1123

1124 1125
  return 0;
}
1126

1127

1128 1129 1130 1131 1132
static LRESULT
DATETIME_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
  DATETIME_INFO *infoPtr;
  DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1133

1134
  /* allocate memory for info structure */
1135
  TRACE("%04x %08lx\n",wParam,lParam);
1136 1137 1138
  infoPtr = (DATETIME_INFO *)COMCTL32_Alloc (sizeof(DATETIME_INFO));
  if (infoPtr == NULL) {
    ERR("could not allocate info memory!\n");
1139
    return 0;
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
  }

  SetWindowLongA (hwnd, 0, (DWORD)infoPtr);

  if (dwStyle & DTS_SHOWNONE) {
    infoPtr->hwndCheckbut=CreateWindowExA (0,"button", 0, 
         WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 
         2,2,13,13,
         hwnd, 
         0, GetWindowLongA  (hwnd, GWL_HINSTANCE), 0);
         SendMessageA (infoPtr->hwndCheckbut, BM_SETCHECK, 1, 0);
  }

  if (dwStyle & DTS_UPDOWN) {
    infoPtr->hUpdown=CreateUpDownControl (
        WS_CHILD | WS_BORDER | WS_VISIBLE,
        120,1,20,20,
        hwnd,1,0,0,
        UD_MAXVAL, UD_MINVAL, 0);
  }

  infoPtr->fieldspec = (int *) COMCTL32_Alloc (32*sizeof(int));
  infoPtr->fieldRect = (RECT *) COMCTL32_Alloc (32*sizeof(RECT));
  infoPtr->buflen = (int *) COMCTL32_Alloc (32*sizeof(int));
  infoPtr->nrFieldsAllocated = 32;

  DATETIME_SetFormat (hwnd, 0, 0);

  /* create the monthcal control */
    infoPtr->hMonthCal = CreateWindowExA (0,"SysMonthCal32", 0, 
	WS_BORDER | WS_POPUP | WS_CLIPSIBLINGS,
	0, 0, 0, 0,
	GetParent(hwnd), 
	0, 0, 0);

  /* initialize info structure */
  GetSystemTime (&infoPtr->date);
  infoPtr->dateValid = TRUE;
  infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT);
  return 0;
1180 1181 1182 1183
}


static LRESULT
1184
DATETIME_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
1185
{
1186
    DATETIME_INFO *infoPtr = DATETIME_GetInfoPtr (hwnd);
1187
	
1188
    TRACE("\n");
1189
    COMCTL32_Free (infoPtr);
1190
    SetWindowLongA( hwnd, 0, 0 );
1191 1192 1193 1194
    return 0;
}


1195
static LRESULT WINAPI
1196
DATETIME_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1197
{
1198 1199 1200
    if (!DATETIME_GetInfoPtr(hwnd) && (uMsg != WM_CREATE))
	return DefWindowProcA( hwnd, uMsg, wParam, lParam );
    
1201 1202 1203
    switch (uMsg)
    {

1204
    case DTM_GETSYSTEMTIME:
1205
        return DATETIME_GetSystemTime (hwnd, wParam, lParam);
1206 1207

    case DTM_SETSYSTEMTIME:
1208
	return DATETIME_SetSystemTime (hwnd, wParam, lParam);
1209 1210

    case DTM_GETRANGE:
1211
        return DATETIME_GetRange(hwnd, lParam);
1212 1213

    case DTM_SETRANGE:
1214
        return DATETIME_SetRange(hwnd, wParam, lParam);
1215

1216
    case DTM_SETFORMATA:
1217
        return DATETIME_SetFormat (hwnd, wParam, lParam);
1218

1219
    case DTM_SETFORMATW:
1220
        return DATETIME_SetFormatW (hwnd, wParam, lParam);
1221 1222

    case DTM_SETMCCOLOR:
1223
        return DATETIME_SetMonthCalColor (hwnd, wParam, lParam);
1224 1225

    case DTM_GETMCCOLOR:
1226
        return DATETIME_GetMonthCalColor (hwnd, wParam);
1227 1228

    case DTM_GETMONTHCAL:
1229
        return DATETIME_GetMonthCal (hwnd);
1230 1231

    case DTM_SETMCFONT:
1232
        return DATETIME_SetMonthCalFont (hwnd, wParam, lParam);
1233 1234

    case DTM_GETMCFONT:
1235 1236
        return DATETIME_GetMonthCalFont (hwnd);

1237 1238 1239 1240 1241
    case WM_PARENTNOTIFY:
	return DATETIME_ParentNotify (hwnd, wParam, lParam);

    case WM_NOTIFY:
	return DATETIME_Notify (hwnd, wParam, lParam);
1242

1243 1244
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS | DLGC_WANTCHARS;
1245 1246 1247 1248

    case WM_PAINT:
        return DATETIME_Paint (hwnd, wParam);

1249 1250 1251
    case WM_KEYDOWN:
        return DATETIME_KeyDown (hwnd, wParam, lParam);

1252 1253 1254 1255 1256 1257
    case WM_KILLFOCUS:
        return DATETIME_KillFocus (hwnd, wParam, lParam);

    case WM_SETFOCUS:
        return DATETIME_SetFocus (hwnd, wParam, lParam);

1258 1259 1260
    case WM_SIZE:
        return DATETIME_Size (hwnd, wParam, lParam);

1261 1262
    case WM_LBUTTONDOWN:
        return DATETIME_LButtonDown (hwnd, wParam, lParam);
1263

1264 1265 1266
    case WM_LBUTTONUP:
        return DATETIME_LButtonUp (hwnd, wParam, lParam);

1267 1268
    case WM_CREATE:
	return DATETIME_Create (hwnd, wParam, lParam);
1269

1270 1271
    case WM_DESTROY:
	return DATETIME_Destroy (hwnd, wParam, lParam);
1272

1273 1274
    default:
	if (uMsg >= WM_USER)
1275
		ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1276
		     uMsg, wParam, lParam);
1277
	return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1278 1279 1280 1281 1282 1283
    }
    return 0;
}


VOID
1284
DATETIME_Register (void)
1285
{
1286
    WNDCLASSA wndClass;
1287

1288
    TRACE("\n");
1289
    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1290
    wndClass.style         = CS_GLOBALCLASS;
1291
    wndClass.lpfnWndProc   = (WNDPROC)DATETIME_WindowProc;
1292 1293
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(DATETIME_INFO *);
1294 1295 1296
    wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
    wndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wndClass.lpszClassName = DATETIMEPICK_CLASSA;
1297
 
1298
    RegisterClassA (&wndClass);
1299 1300 1301 1302
}


VOID
1303
DATETIME_Unregister (void)
1304
{
1305
    TRACE("\n");
1306
    UnregisterClassA (DATETIMEPICK_CLASSA, (HINSTANCE)NULL);
1307
}