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