source: trunk/src/comctl32/updown.c@ 94

Last change on this file since 94 was 94, checked in by achimha, 26 years ago

Added CVS tag to many files (comctl32 and headers) .

File size: 25.5 KB
Line 
1/* $Id: updown.c,v 1.3 1999-06-10 16:22:04 achimha Exp $ */
2/*
3 * Updown control
4 *
5 * Copyright 1997 Dimitrie O. Paun
6 * Copyright 1999 Achim Hasenmueller
7 *
8 * TODO:
9 * - subclass the buddy window (in UPDOWN_SetBuddy) to process the
10 * arrow keys
11 * - I am not sure about the default values for the Min, Max, Pos
12 * (in the UPDOWN_INFO the fields: MinVal, MaxVal, CurVal)
13 * - I think I do not handle correctly the WS_BORDER style.
14 * (Should be fixed. <ekohl@abo.rhein-zeitung.de>)
15 *
16 * Testing:
17 * Not much. The following have not been tested at all:
18 * - horizontal arrows
19 * - listbox as buddy window
20 * - acceleration
21 * - base 16
22 * - UDS_ALIGNLEFT, ~UDS_WRAP
23 * (tested - they work)
24 * - integers with thousand separators.
25 * (fixed bugs. <noel@macadamian.com>)
26 *
27 * Even though the above list seems rather large, the control seems to
28 * behave very well so I am confident it does work in most (all) of the
29 * untested cases.
30 * Problems:
31 * I do not like the arrows yet, I'll work more on them later on.
32 */
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <string.h>
37
38#include "winbase.h"
39#include "winuser.h"
40#include "commctrl.h"
41#include "winnls.h"
42#include "updown.h"
43
44/* Control configuration constants */
45
46#define INITIAL_DELAY 500 /* initial timer until auto-increment kicks in */
47#define REPEAT_DELAY 50 /* delay between auto-increments */
48
49#define DEFAULT_WIDTH 14 /* default width of the ctrl */
50#define DEFAULT_XSEP 0 /* default separation between buddy and crtl */
51#define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */
52#define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */
53
54
55/* Work constants */
56
57#define FLAG_INCR 0x01
58#define FLAG_DECR 0x02
59#define FLAG_MOUSEIN 0x04
60#define FLAG_CLICKED (FLAG_INCR | FLAG_DECR)
61
62#define TIMERID1 1
63#define TIMERID2 2
64
65static int accelIndex = -1;
66
67//#define UNKNOWN_PARAM(msg, wParam, lParam) WARN(updown, \
68// "UpDown Ctrl: Unknown parameter(s) for message " #msg \
69// "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
70#define UNKNOWN_PARAM(msg, wParam, lParam)
71
72#define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongA (hwnd,0))
73
74
75/***********************************************************************
76 * UPDOWN_InBounds
77 * Tests if a given value 'val' is between the Min&Max limits
78 */
79static BOOL UPDOWN_InBounds(HWND hwnd, int val)
80{
81 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
82
83 if(infoPtr->MaxVal > infoPtr->MinVal)
84 return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal);
85 else
86 return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal);
87}
88
89/***********************************************************************
90 * UPDOWN_OffsetVal
91 * Tests if we can change the current value by delta. If so, it changes
92 * it and returns TRUE. Else, it leaves it unchanged and returns FALSE.
93 */
94static BOOL UPDOWN_OffsetVal(HWND hwnd, int delta)
95{
96 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
97
98 /* check if we can do the modification first */
99 if(!UPDOWN_InBounds (hwnd, infoPtr->CurVal+delta)){
100 if (GetWindowLongA (hwnd, GWL_STYLE) & UDS_WRAP)
101 {
102 delta += (delta < 0 ? -1 : 1) *
103 (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) *
104 (infoPtr->MinVal - infoPtr->MaxVal) +
105 (delta < 0 ? 1 : -1);
106 }
107 else
108 return FALSE;
109 }
110
111 infoPtr->CurVal += delta;
112 return TRUE;
113}
114
115/***********************************************************************
116 * UPDOWN_GetArrowRect
117 * wndPtr - pointer to the up-down wnd
118 * rect - will hold the rectangle
119 * incr - TRUE get the "increment" rect (up or right)
120 * FALSE get the "decrement" rect (down or left)
121 *
122 */
123static void UPDOWN_GetArrowRect (HWND hwnd, RECT *rect, BOOL incr)
124{
125 int len; /* will hold the width or height */
126
127 GetClientRect (hwnd, rect);
128
129 if (GetWindowLongA (hwnd, GWL_STYLE) & UDS_HORZ) {
130 len = rect->right - rect->left; /* compute the width */
131 if (incr)
132 rect->left = len/2+1;
133 else
134 rect->right = len/2;
135 }
136 else {
137 len = rect->bottom - rect->top; /* compute the height */
138 if (incr)
139 rect->bottom = len/2;
140 else
141 rect->top = len/2+1;
142 }
143}
144
145/***********************************************************************
146 * UPDOWN_GetArrowFromPoint
147 * Returns the rectagle (for the up or down arrow) that contains pt.
148 * If it returns the up rect, it returns TRUE.
149 * If it returns the down rect, it returns FALSE.
150 */
151static BOOL
152UPDOWN_GetArrowFromPoint (HWND hwnd, RECT *rect, POINT pt)
153{
154 UPDOWN_GetArrowRect (hwnd, rect, TRUE);
155 if(PtInRect(rect, pt))
156 return TRUE;
157
158 UPDOWN_GetArrowRect (hwnd, rect, FALSE);
159 return FALSE;
160}
161
162
163/***********************************************************************
164 * UPDOWN_GetThousandSep
165 * Returns the thousand sep. If an error occurs, it returns ','.
166 */
167static char UPDOWN_GetThousandSep()
168{
169 char sep[2];
170
171 if(GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND,
172 sep, sizeof(sep)) != 1)
173 return ',';
174
175 return sep[0];
176}
177
178/***********************************************************************
179 * UPDOWN_GetBuddyInt
180 * Tries to read the pos from the buddy window and if it succeeds,
181 * it stores it in the control's CurVal
182 * returns:
183 * TRUE - if it read the integer from the buddy successfully
184 * FALSE - if an error occured
185 */
186static BOOL UPDOWN_GetBuddyInt (HWND hwnd)
187{
188 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
189 char txt[20], sep, *src, *dst;
190 int newVal;
191
192 if (!IsWindow(infoPtr->Buddy))
193 return FALSE;
194
195 /*if the buddy is a list window, we must set curr index */
196 if (!lstrcmpA (infoPtr->szBuddyClass, "ListBox")){
197 newVal = SendMessageA(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0);
198 if(newVal < 0)
199 return FALSE;
200 }
201 else{
202 /* we have a regular window, so will get the text */
203 if (!GetWindowTextA(infoPtr->Buddy, txt, sizeof(txt)))
204 return FALSE;
205
206 sep = UPDOWN_GetThousandSep();
207
208 /* now get rid of the separators */
209 for(src = dst = txt; *src; src++)
210 if(*src != sep)
211 *dst++ = *src;
212 *dst = 0;
213
214 /* try to convert the number and validate it */
215 newVal = strtol(txt, &src, infoPtr->Base);
216 if(*src || !UPDOWN_InBounds (hwnd, newVal))
217 return FALSE;
218
219// TRACE(updown, "new value(%d) read from buddy (old=%d)\n",
220// newVal, infoPtr->CurVal);
221 }
222
223 infoPtr->CurVal = newVal;
224 return TRUE;
225}
226
227
228/***********************************************************************
229 * UPDOWN_SetBuddyInt
230 * Tries to set the pos to the buddy window based on current pos
231 * returns:
232 * TRUE - if it set the caption of the buddy successfully
233 * FALSE - if an error occured
234 */
235static BOOL UPDOWN_SetBuddyInt (HWND hwnd)
236{
237 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
238 char txt1[20], sep;
239 int len;
240
241 if (!IsWindow(infoPtr->Buddy))
242 return FALSE;
243
244// TRACE(updown, "set new value(%d) to buddy.\n",
245// infoPtr->CurVal);
246
247 /*if the buddy is a list window, we must set curr index */
248 if(!lstrcmpA (infoPtr->szBuddyClass, "ListBox")){
249 SendMessageA(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0);
250 }
251 else{ /* Regular window, so set caption to the number */
252 len = sprintf(txt1, (infoPtr->Base==16) ? "%X" : "%d", infoPtr->CurVal);
253
254 sep = UPDOWN_GetThousandSep();
255
256 /* Do thousands seperation if necessary */
257 if (!(GetWindowLongA (hwnd, GWL_STYLE) & UDS_NOTHOUSANDS) && (len > 3)) {
258 char txt2[20], *src = txt1, *dst = txt2;
259 if(len%3 > 0){
260 lstrcpynA (dst, src, len%3 + 1); /* need to include the null */
261 dst += len%3;
262 src += len%3;
263 }
264 for(len=0; *src; len++){
265 if(len%3==0)
266 *dst++ = sep;
267 *dst++ = *src++;
268 }
269 *dst = 0; /* null terminate it */
270 strcpy(txt1, txt2); /* move it to the proper place */
271 }
272 SetWindowTextA(infoPtr->Buddy, txt1);
273 }
274
275 return TRUE;
276}
277
278/***********************************************************************
279 * UPDOWN_Draw [Internal]
280 *
281 * Draw the arrows. The background need not be erased.
282 */
283static void UPDOWN_Draw (HWND hwnd, HDC hdc)
284{
285 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
286 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
287 BOOL prssed;
288 RECT rect;
289
290 /* Draw the incr button */
291 UPDOWN_GetArrowRect (hwnd, &rect, TRUE);
292 prssed = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
293 DrawFrameControl(hdc, &rect, DFC_SCROLL,
294 (dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLUP) |
295 (prssed ? DFCS_PUSHED : 0) |
296 (dwStyle&WS_DISABLED ? DFCS_INACTIVE : 0) );
297
298 /* Draw the space between the buttons */
299 rect.top = rect.bottom; rect.bottom++;
300 DrawEdge(hdc, &rect, 0, BF_MIDDLE);
301
302 /* Draw the decr button */
303 UPDOWN_GetArrowRect(hwnd, &rect, FALSE);
304 prssed = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
305 DrawFrameControl(hdc, &rect, DFC_SCROLL,
306 (dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLDOWN) |
307 (prssed ? DFCS_PUSHED : 0) |
308 (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
309}
310
311/***********************************************************************
312 * UPDOWN_Refresh [Internal]
313 *
314 * Synchronous drawing (must NOT be used in WM_PAINT).
315 * Calls UPDOWN_Draw.
316 */
317static void UPDOWN_Refresh (HWND hwnd)
318{
319 HDC hdc;
320
321 hdc = GetDC (hwnd);
322 UPDOWN_Draw (hwnd, hdc);
323 ReleaseDC (hwnd, hdc);
324}
325
326
327/***********************************************************************
328 * UPDOWN_Paint [Internal]
329 *
330 * Asynchronous drawing (must ONLY be used in WM_PAINT).
331 * Calls UPDOWN_Draw.
332 */
333static void UPDOWN_Paint (HWND hwnd)
334{
335 PAINTSTRUCT ps;
336 HDC hdc;
337
338 hdc = BeginPaint (hwnd, &ps);
339 UPDOWN_Draw (hwnd, hdc);
340 EndPaint (hwnd, &ps);
341}
342
343/***********************************************************************
344 * UPDOWN_SetBuddy
345 * Tests if 'hwndBud' is a valid window handle. If not, returns FALSE.
346 * Else, sets it as a new Buddy.
347 * Then, it should subclass the buddy
348 * If window has the UDS_ARROWKEYS, it subcalsses the buddy window to
349 * process the UP/DOWN arrow keys.
350 * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style
351 * the size/pos of the buddy and the control are adjusted accordingly.
352 */
353static BOOL UPDOWN_SetBuddy (HWND hwnd, HWND hwndBud)
354{
355 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
356 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
357 RECT budRect; /* new coord for the buddy */
358 int x; /* new x position and width for the up-down */
359
360 *infoPtr->szBuddyClass = '\0';
361
362 /* Is is a valid bud? */
363 if(!IsWindow(hwndBud))
364 return FALSE;
365
366 /* Store buddy window clas name */
367 GetClassNameA (hwndBud, infoPtr->szBuddyClass, 40);
368
369 if(dwStyle & UDS_ARROWKEYS){
370// FIXME(updown, "we need to subclass the buddy to process the arrow keys.\n");
371 }
372
373 /* do we need to do any adjustments? */
374 if(!(dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)))
375 return TRUE;
376
377 infoPtr->Buddy = hwndBud;
378
379 /* Get the rect of the buddy relative to its parent */
380 GetWindowRect(infoPtr->Buddy, &budRect);
381 MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy),
382 (POINT *)(&budRect.left), 2);
383
384 /* now do the positioning */
385 if(dwStyle & UDS_ALIGNRIGHT){
386 budRect.right -= DEFAULT_WIDTH+DEFAULT_XSEP;
387 x = budRect.right+DEFAULT_XSEP;
388 }
389 else{ /* UDS_ALIGNLEFT */
390 x = budRect.left;
391 budRect.left += DEFAULT_WIDTH+DEFAULT_XSEP;
392 }
393
394 /* first adjust the buddy to accomodate the up/down */
395 SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
396 budRect.right - budRect.left, budRect.bottom - budRect.top,
397 SWP_NOACTIVATE|SWP_NOZORDER);
398
399 /* now position the up/down */
400 /* Since the UDS_ALIGN* flags were used, */
401 /* we will pick the position and size of the window. */
402
403 SetWindowPos (hwnd, 0, x, budRect.top-DEFAULT_ADDTOP,DEFAULT_WIDTH,
404 (budRect.bottom-budRect.top)+DEFAULT_ADDTOP+DEFAULT_ADDBOT,
405 SWP_NOACTIVATE|SWP_NOZORDER);
406
407 return TRUE;
408}
409
410/***********************************************************************
411 * UPDOWN_DoAction
412 *
413 * This function increments/decrements the CurVal by the
414 * 'delta' amount according to the 'incr' flag
415 * It notifies the parent as required.
416 * It handles wraping and non-wraping correctly.
417 * It is assumed that delta>0
418 */
419static void UPDOWN_DoAction (HWND hwnd, int delta, BOOL incr)
420{
421 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
422 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
423 int old_val = infoPtr->CurVal;
424 NM_UPDOWN ni;
425
426// TRACE(updown, "%s by %d\n", incr ? "inc" : "dec", delta);
427
428 /* check if we can do the modification first */
429 delta *= (incr ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
430 if(!UPDOWN_OffsetVal (hwnd, delta))
431 return;
432
433 /* so, if we can do the change, recompute delta and restore old value */
434 delta = infoPtr->CurVal - old_val;
435 infoPtr->CurVal = old_val;
436
437 /* We must notify parent now to obtain permission */
438 ni.iPos = infoPtr->CurVal;
439 ni.iDelta = delta;
440 ni.hdr.hwndFrom = hwnd;
441 ni.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
442 ni.hdr.code = UDN_DELTAPOS;
443 if (SendMessageA(GetParent (hwnd), WM_NOTIFY,
444 (WPARAM)ni.hdr.idFrom, (LPARAM)&ni))
445 return; /* we are not allowed to change */
446
447 /* Now adjust value with (maybe new) delta */
448 if (!UPDOWN_OffsetVal (hwnd, ni.iDelta))
449 return;
450
451 /* Now take care about our buddy */
452 if(!IsWindow(infoPtr->Buddy))
453 return; /* Nothing else to do */
454
455
456 if (dwStyle & UDS_SETBUDDYINT)
457 UPDOWN_SetBuddyInt (hwnd);
458
459 /* Also, notify it */
460 /* FIXME: do we need to send the notification only if
461 we do not have the UDS_SETBUDDYINT style set? */
462
463 SendMessageA (GetParent (hwnd),
464 dwStyle & UDS_HORZ ? WM_HSCROLL : WM_VSCROLL,
465 MAKELONG(incr ? SB_LINEUP : SB_LINEDOWN, infoPtr->CurVal),
466 hwnd);
467}
468
469/***********************************************************************
470 * UPDOWN_IsEnabled
471 *
472 * Returns TRUE if it is enabled as well as its buddy (if any)
473 * FALSE otherwise
474 */
475static BOOL UPDOWN_IsEnabled (HWND hwnd)
476{
477 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
478
479 if(GetWindowLongA (hwnd, GWL_STYLE) & WS_DISABLED)
480 return FALSE;
481 return IsWindowEnabled(infoPtr->Buddy);
482}
483
484/***********************************************************************
485 * UPDOWN_CancelMode
486 *
487 * Deletes any timers, releases the mouse and does redraw if necessary.
488 * If the control is not in "capture" mode, it does nothing.
489 * If the control was not in cancel mode, it returns FALSE.
490 * If the control was in cancel mode, it returns TRUE.
491 */
492static BOOL UPDOWN_CancelMode (HWND hwnd)
493{
494 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
495
496 /* if not in 'capture' mode, do nothing */
497 if(!(infoPtr->Flags & FLAG_CLICKED))
498 return FALSE;
499
500 KillTimer (hwnd, TIMERID1); /* kill all possible timers */
501 KillTimer (hwnd, TIMERID2);
502
503 if (GetCapture() == hwnd) /* let the mouse go */
504 ReleaseCapture(); /* if we still have it */
505
506 infoPtr->Flags = 0; /* get rid of any flags */
507 UPDOWN_Refresh (hwnd); /* redraw the control just in case */
508
509 return TRUE;
510}
511
512/***********************************************************************
513 * UPDOWN_HandleMouseEvent
514 *
515 * Handle a mouse event for the updown.
516 * 'pt' is the location of the mouse event in client or
517 * windows coordinates.
518 */
519static void UPDOWN_HandleMouseEvent (HWND hwnd, UINT msg, POINT pt)
520{
521 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
522 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
523 RECT rect;
524 int temp;
525
526 switch(msg)
527 {
528 case WM_LBUTTONDOWN: /* Initialise mouse tracking */
529 /* If we are already in the 'clicked' mode, then nothing to do */
530 if(infoPtr->Flags & FLAG_CLICKED)
531 return;
532
533 /* If the buddy is an edit, will set focus to it */
534 if (!lstrcmpA (infoPtr->szBuddyClass, "Edit"))
535 SetFocus(infoPtr->Buddy);
536
537 /* Now see which one is the 'active' arrow */
538 temp = UPDOWN_GetArrowFromPoint (hwnd, &rect, pt);
539
540 /* Update the CurVal if necessary */
541 if (dwStyle & UDS_SETBUDDYINT)
542 UPDOWN_GetBuddyInt (hwnd);
543
544 /* Before we proceed, see if we can spin... */
545 if(!(dwStyle & UDS_WRAP))
546 if(( temp && infoPtr->CurVal==infoPtr->MaxVal) ||
547 (!temp && infoPtr->CurVal==infoPtr->MinVal))
548 return;
549
550 /* Set up the correct flags */
551 infoPtr->Flags = 0;
552 infoPtr->Flags |= temp ? FLAG_INCR : FLAG_DECR;
553 infoPtr->Flags |= FLAG_MOUSEIN;
554
555 /* repaint the control */
556 UPDOWN_Refresh (hwnd);
557
558 /* process the click */
559 UPDOWN_DoAction (hwnd, 1, infoPtr->Flags & FLAG_INCR);
560
561 /* now capture all mouse messages */
562 SetCapture (hwnd);
563
564 /* and startup the first timer */
565 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
566 break;
567
568 case WM_MOUSEMOVE:
569 /* If we are not in the 'clicked' mode, then nothing to do */
570 if(!(infoPtr->Flags & FLAG_CLICKED))
571 return;
572
573 /* save the flags to see if any got modified */
574 temp = infoPtr->Flags;
575
576 /* Now get the 'active' arrow rectangle */
577 if (infoPtr->Flags & FLAG_INCR)
578 UPDOWN_GetArrowRect (hwnd, &rect, TRUE);
579 else
580 UPDOWN_GetArrowRect (hwnd, &rect, FALSE);
581
582 /* Update the flags if we are in/out */
583 if(PtInRect(&rect, pt))
584 infoPtr->Flags |= FLAG_MOUSEIN;
585 else{
586 infoPtr->Flags &= ~FLAG_MOUSEIN;
587 if(accelIndex != -1) /* if we have accel info */
588 accelIndex = 0; /* reset it */
589 }
590 /* If state changed, redraw the control */
591 if(temp != infoPtr->Flags)
592 UPDOWN_Refresh (hwnd);
593 break;
594
595 default:
596// ERR(updown, "Impossible case!\n");
597 break;
598 }
599
600}
601
602/***********************************************************************
603 * UpDownWndProc
604 */
605LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam,
606 LPARAM lParam)
607{
608 UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
609 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
610 int temp;
611
612 switch(message)
613 {
614 case WM_NCCREATE:
615 /* get rid of border, if any */
616 SetWindowLongA (hwnd, GWL_STYLE, dwStyle & ~WS_BORDER);
617 return TRUE;
618
619 case WM_CREATE:
620 infoPtr = (UPDOWN_INFO*)COMCTL32_Alloc (sizeof(UPDOWN_INFO));
621 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
622
623 /* initialize the info struct */
624 infoPtr->AccelCount=0; infoPtr->AccelVect=0;
625 infoPtr->CurVal=0; infoPtr->MinVal=0; infoPtr->MaxVal=100; /*FIXME*/
626 infoPtr->Base = 10; /* Default to base 10 */
627 infoPtr->Buddy = 0; /* No buddy window yet */
628 infoPtr->Flags = 0; /* And no flags */
629
630 /* Do we pick the buddy win ourselves? */
631 if (dwStyle & UDS_AUTOBUDDY)
632 UPDOWN_SetBuddy (hwnd, GetWindow (hwnd, GW_HWNDPREV));
633
634// TRACE(updown, "UpDown Ctrl creation, hwnd=%04x\n", hwnd);
635 break;
636
637 case WM_DESTROY:
638 if(infoPtr->AccelVect)
639 COMCTL32_Free (infoPtr->AccelVect);
640
641 COMCTL32_Free (infoPtr);
642
643// TRACE(updown, "UpDown Ctrl destruction, hwnd=%04x\n", hwnd);
644 break;
645
646 case WM_ENABLE:
647 if (dwStyle & WS_DISABLED)
648 UPDOWN_CancelMode (hwnd);
649 UPDOWN_Paint (hwnd);
650 break;
651
652 case WM_TIMER:
653 /* if initial timer, kill it and start the repeat timer */
654 if(wParam == TIMERID1){
655 KillTimer(hwnd, TIMERID1);
656 /* if no accel info given, used default timer */
657 if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0){
658 accelIndex = -1;
659 temp = REPEAT_DELAY;
660 }
661 else{
662 accelIndex = 0; /* otherwise, use it */
663 temp = infoPtr->AccelVect[accelIndex].nSec * 1000 + 1;
664 }
665 SetTimer(hwnd, TIMERID2, temp, 0);
666 }
667
668 /* now, if the mouse is above us, do the thing...*/
669 if(infoPtr->Flags & FLAG_MOUSEIN){
670 temp = accelIndex==-1 ? 1 : infoPtr->AccelVect[accelIndex].nInc;
671 UPDOWN_DoAction(hwnd, temp, infoPtr->Flags & FLAG_INCR);
672
673 if(accelIndex!=-1 && accelIndex < infoPtr->AccelCount-1){
674 KillTimer(hwnd, TIMERID2);
675 accelIndex++; /* move to the next accel info */
676 temp = infoPtr->AccelVect[accelIndex].nSec * 1000 + 1;
677 /* make sure we have at least 1ms intervals */
678 SetTimer(hwnd, TIMERID2, temp, 0);
679 }
680 }
681 break;
682
683 case WM_CANCELMODE:
684 UPDOWN_CancelMode (hwnd);
685 break;
686
687 case WM_LBUTTONUP:
688 if(!UPDOWN_CancelMode(hwnd))
689 break;
690 /*If we released the mouse and our buddy is an edit */
691 /* we must select all text in it. */
692 if (!lstrcmpA (infoPtr->szBuddyClass, "Edit"))
693 SendMessageA(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1));
694 break;
695
696 case WM_LBUTTONDOWN:
697 case WM_MOUSEMOVE:
698 if(UPDOWN_IsEnabled(hwnd)){
699 POINT pt;
700 CONV_POINT16TO32( (POINT16 *)&lParam, &pt );
701 UPDOWN_HandleMouseEvent (hwnd, message, pt );
702 }
703 break;
704
705 case WM_KEYDOWN:
706 if((dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(hwnd)){
707 switch(wParam){
708 case VK_UP:
709 case VK_DOWN:
710 UPDOWN_GetBuddyInt (hwnd);
711 UPDOWN_DoAction (hwnd, 1, wParam==VK_UP);
712 break;
713 }
714 }
715 break;
716
717 case WM_PAINT:
718 UPDOWN_Paint (hwnd);
719 break;
720
721 case UDM_GETACCEL:
722 if (wParam==0 && lParam==0) /*if both zero, */
723 return infoPtr->AccelCount; /*just return the accel count*/
724 if (wParam || lParam){
725 UNKNOWN_PARAM(UDM_GETACCEL, wParam, lParam);
726 return 0;
727 }
728 temp = MIN(infoPtr->AccelCount, wParam);
729 memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL));
730 return temp;
731
732 case UDM_SETACCEL:
733// TRACE(updown, "UpDown Ctrl new accel info, hwnd=%04x\n", hwnd);
734 if(infoPtr->AccelVect){
735 COMCTL32_Free (infoPtr->AccelVect);
736 infoPtr->AccelCount = 0;
737 infoPtr->AccelVect = 0;
738 }
739 if(wParam==0)
740 return TRUE;
741 infoPtr->AccelVect = COMCTL32_Alloc (wParam*sizeof(UDACCEL));
742 if(infoPtr->AccelVect==0)
743 return FALSE;
744 memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL));
745 return TRUE;
746
747 case UDM_GETBASE:
748 if (wParam || lParam)
749 UNKNOWN_PARAM(UDM_GETBASE, wParam, lParam);
750 return infoPtr->Base;
751
752 case UDM_SETBASE:
753// TRACE(updown, "UpDown Ctrl new base(%d), hwnd=%04x\n",
754// wParam, hwnd);
755 if ( !(wParam==10 || wParam==16) || lParam)
756 UNKNOWN_PARAM(UDM_SETBASE, wParam, lParam);
757 if (wParam==10 || wParam==16){
758 temp = infoPtr->Base;
759 infoPtr->Base = wParam;
760 return temp; /* return the prev base */
761 }
762 break;
763
764 case UDM_GETBUDDY:
765 if (wParam || lParam)
766 UNKNOWN_PARAM(UDM_GETBUDDY, wParam, lParam);
767 return infoPtr->Buddy;
768
769 case UDM_SETBUDDY:
770 if (lParam)
771 UNKNOWN_PARAM(UDM_SETBUDDY, wParam, lParam);
772 temp = infoPtr->Buddy;
773 infoPtr->Buddy = wParam;
774 UPDOWN_SetBuddy (hwnd, wParam);
775// TRACE(updown, "UpDown Ctrl new buddy(%04x), hwnd=%04x\n",
776// infoPtr->Buddy, hwnd);
777 return temp;
778
779 case UDM_GETPOS:
780 if (wParam || lParam)
781 UNKNOWN_PARAM(UDM_GETPOS, wParam, lParam);
782 temp = UPDOWN_GetBuddyInt (hwnd);
783 return MAKELONG(infoPtr->CurVal, temp ? 0 : 1);
784
785 case UDM_SETPOS:
786 if (wParam || HIWORD(lParam))
787 UNKNOWN_PARAM(UDM_GETPOS, wParam, lParam);
788 temp = SLOWORD(lParam);
789// TRACE(updown, "UpDown Ctrl new value(%d), hwnd=%04x\n",
790// temp, hwnd);
791 if(!UPDOWN_InBounds(hwnd, temp)){
792 if(temp < infoPtr->MinVal)
793 temp = infoPtr->MinVal;
794 if(temp > infoPtr->MaxVal)
795 temp = infoPtr->MaxVal;
796 }
797 wParam = infoPtr->CurVal; /* save prev value */
798 infoPtr->CurVal = temp; /* set the new value */
799 if(dwStyle & UDS_SETBUDDYINT)
800 UPDOWN_SetBuddyInt (hwnd);
801 return wParam; /* return prev value */
802
803 case UDM_GETRANGE:
804 if (wParam || lParam)
805 UNKNOWN_PARAM(UDM_GETRANGE, wParam, lParam);
806 return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal);
807
808 case UDM_SETRANGE:
809 if (wParam)
810 UNKNOWN_PARAM(UDM_SETRANGE, wParam, lParam); /* we must have: */
811 infoPtr->MaxVal = SLOWORD(lParam); /* UD_MINVAL <= Max <= UD_MAXVAL */
812 infoPtr->MinVal = SHIWORD(lParam); /* UD_MINVAL <= Min <= UD_MAXVAL */
813 /* |Max-Min| <= UD_MAXVAL */
814// TRACE(updown, "UpDown Ctrl new range(%d to %d), hwnd=%04x\n",
815// infoPtr->MinVal, infoPtr->MaxVal, hwnd);
816 break;
817
818 case UDM_GETRANGE32:
819 if (wParam)
820 *(LPINT)wParam = infoPtr->MinVal;
821 if (lParam)
822 *(LPINT)lParam = infoPtr->MaxVal;
823 break;
824
825 case UDM_SETRANGE32:
826 infoPtr->MinVal = (INT)wParam;
827 infoPtr->MaxVal = (INT)lParam;
828 if (infoPtr->MaxVal <= infoPtr->MinVal)
829 infoPtr->MaxVal = infoPtr->MinVal + 1;
830// TRACE(updown, "UpDown Ctrl new range(%d to %d), hwnd=%04x\n",
831// infoPtr->MinVal, infoPtr->MaxVal, hwnd);
832 break;
833
834 default:
835 if (message >= WM_USER)
836// ERR (updown, "unknown msg %04x wp=%04x lp=%08lx\n",
837// message, wParam, lParam);
838 return DefWindowProcA (hwnd, message, wParam, lParam);
839 }
840
841 return 0;
842}
843
844
845/***********************************************************************
846 * UPDOWN_Register [Internal]
847 *
848 * Registers the updown window class.
849 */
850
851VOID
852UPDOWN_Register(void)
853{
854 WNDCLASSA wndClass;
855
856 if( GlobalFindAtomA( UPDOWN_CLASSA ) ) return;
857
858 ZeroMemory( &wndClass, sizeof( WNDCLASSA ) );
859 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW;
860 wndClass.lpfnWndProc = (WNDPROC)UpDownWindowProc;
861 wndClass.cbClsExtra = 0;
862 wndClass.cbWndExtra = sizeof(UPDOWN_INFO*);
863 wndClass.hCursor = LoadCursorA( 0, IDC_ARROWA );
864 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
865 wndClass.lpszClassName = UPDOWN_CLASSA;
866
867 RegisterClassA( &wndClass );
868}
869
870
871/***********************************************************************
872 * UPDOWN_Unregister [Internal]
873 *
874 * Unregisters the updown window class.
875 */
876
877VOID
878UPDOWN_Unregister (VOID)
879{
880 if (GlobalFindAtomA (UPDOWN_CLASSA))
881 UnregisterClassA (UPDOWN_CLASSA, (HINSTANCE)NULL);
882}
883
Note: See TracBrowser for help on using the repository browser.