4 * Copyright 1997 Dimitrie O. Paun
7 * - subclass the buddy window (in UPDOWN_SetBuddy) to process the
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>)
15 * Not much. The following have not been tested at all:
17 * - listbox as buddy window
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
29 * I do not like the arrows yet, I'll work more on them later on.
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 */
54 #define FLAG_INCR 0x01
55 #define FLAG_DECR 0x02
56 #define FLAG_MOUSEIN 0x04
57 #define FLAG_CLICKED (FLAG_INCR | FLAG_DECR)
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 /***********************************************************************
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
);
82 return (infoPtr
->MaxVal
<= val
) && (val
<= infoPtr
->MinVal
);
85 /***********************************************************************
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);
107 infoPtr
->CurVal
+= delta
;
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 */
128 rect
->left
= len
/2+1;
133 len
= rect
->bottom
- rect
->top
; /* compute the height */
135 rect
->bottom
= len
/2;
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.
148 UPDOWN_GetArrowFromPoint (HWND hwnd
, RECT
*rect
, POINT pt
)
150 UPDOWN_GetArrowRect (hwnd
, rect
, TRUE
);
151 if(PtInRect(rect
, pt
))
154 UPDOWN_GetArrowRect (hwnd
, rect
, FALSE
);
159 /***********************************************************************
160 * UPDOWN_GetThousandSep
161 * Returns the thousand sep. If an error occurs, it returns ','.
163 static char UPDOWN_GetThousandSep()
167 if(GetLocaleInfoA(LOCALE_USER_DEFAULT
, LOCALE_STHOUSAND
,
168 sep
, sizeof(sep
)) != 1)
174 /***********************************************************************
176 * Tries to read the pos from the buddy window and if it succeeds,
177 * it stores it in the control's CurVal
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
;
188 if (!IsWindow(infoPtr
->Buddy
))
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);
198 /* we have a regular window, so will get the text */
199 if (!GetWindowTextA(infoPtr
->Buddy
, txt
, sizeof(txt
)))
202 sep
= UPDOWN_GetThousandSep();
204 /* now get rid of the separators */
205 for(src
= dst
= txt
; *src
; src
++)
210 /* try to convert the number and validate it */
211 newVal
= strtol(txt
, &src
, infoPtr
->Base
);
212 if(*src
|| !UPDOWN_InBounds (hwnd
, newVal
))
215 TRACE(updown
, "new value(%d) read from buddy (old=%d)\n",
216 newVal
, infoPtr
->CurVal
);
219 infoPtr
->CurVal
= newVal
;
224 /***********************************************************************
226 * Tries to set the pos to the buddy window based on current pos
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
);
237 if (!IsWindow(infoPtr
->Buddy
))
240 TRACE(updown
, "set new value(%d) to buddy.\n",
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
;
256 lstrcpynA (dst
, src
, len
%3 + 1); /* need to include the null */
260 for(len
=0; *src
; len
++){
265 *dst
= 0; /* null terminate it */
266 strcpy(txt1
, txt2
); /* move it to the proper place */
268 SetWindowTextA(infoPtr
->Buddy
, txt1
);
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
);
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).
313 static void UPDOWN_Refresh (HWND 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).
329 static void UPDOWN_Paint (HWND hwnd
)
334 hdc
= BeginPaint (hwnd
, &ps
);
335 UPDOWN_Draw (hwnd
, hdc
);
336 EndPaint (hwnd
, &ps
);
339 /***********************************************************************
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
))
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
)))
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 */
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
);
404 /***********************************************************************
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
;
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
))
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
;
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
))
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
),
463 /***********************************************************************
466 * Returns TRUE if it is enabled as well as its buddy (if any)
469 static BOOL
UPDOWN_IsEnabled (HWND hwnd
)
471 UPDOWN_INFO
*infoPtr
= UPDOWN_GetInfoPtr (hwnd
);
473 if(GetWindowLongA (hwnd
, GWL_STYLE
) & WS_DISABLED
)
475 return IsWindowEnabled(infoPtr
->Buddy
);
478 /***********************************************************************
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
))
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 */
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
);
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
)
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
))
544 /* Set up the correct flags */
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 */
558 /* and startup the first timer */
559 SetTimer(hwnd
, TIMERID1
, INITIAL_DELAY
, 0);
563 /* If we are not in the 'clicked' mode, then nothing to do */
564 if(!(infoPtr
->Flags
& FLAG_CLICKED
))
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
);
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
;
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
);
590 ERR(updown
, "Impossible case!\n");
595 /***********************************************************************
598 LRESULT WINAPI
UpDownWindowProc(HWND hwnd
, UINT message
, WPARAM wParam
,
601 UPDOWN_INFO
*infoPtr
= UPDOWN_GetInfoPtr (hwnd
);
602 DWORD dwStyle
= GetWindowLongA (hwnd
, GWL_STYLE
);
608 /* get rid of border, if any */
609 SetWindowLongA (hwnd
, GWL_STYLE
, dwStyle
& ~WS_BORDER
);
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
);
631 if(infoPtr
->AccelVect
)
632 COMCTL32_Free (infoPtr
->AccelVect
);
634 COMCTL32_Free (infoPtr
);
636 TRACE(updown
, "UpDown Ctrl destruction, hwnd=%04x\n", hwnd
);
640 if (dwStyle
& WS_DISABLED
)
641 UPDOWN_CancelMode (hwnd
);
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){
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);
677 UPDOWN_CancelMode (hwnd
);
681 if(!UPDOWN_CancelMode(hwnd
))
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));
691 if(UPDOWN_IsEnabled(hwnd
)){
693 CONV_POINT16TO32( (POINT16
*)&lParam
, &pt
);
694 UPDOWN_HandleMouseEvent (hwnd
, message
, pt
);
699 if((dwStyle
& UDS_ARROWKEYS
) && UPDOWN_IsEnabled(hwnd
)){
703 UPDOWN_GetBuddyInt (hwnd
);
704 UPDOWN_DoAction (hwnd
, 1, wParam
==VK_UP
);
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
);
721 temp
= MIN(infoPtr
->AccelCount
, wParam
);
722 memcpy((void *)lParam
, infoPtr
->AccelVect
, temp
*sizeof(UDACCEL
));
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;
734 infoPtr
->AccelVect
= COMCTL32_Alloc (wParam
*sizeof(UDACCEL
));
735 if(infoPtr
->AccelVect
==0)
737 memcpy(infoPtr
->AccelVect
, (void*)lParam
, wParam
*sizeof(UDACCEL
));
741 if (wParam
|| lParam
)
742 UNKNOWN_PARAM(UDM_GETBASE
, wParam
, lParam
);
743 return infoPtr
->Base
;
746 TRACE(updown
, "UpDown Ctrl new base(%d), hwnd=%04x\n",
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 */
758 if (wParam
|| lParam
)
759 UNKNOWN_PARAM(UDM_GETBUDDY
, wParam
, lParam
);
760 return infoPtr
->Buddy
;
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
);
773 if (wParam
|| lParam
)
774 UNKNOWN_PARAM(UDM_GETPOS
, wParam
, lParam
);
775 temp
= UPDOWN_GetBuddyInt (hwnd
);
776 return MAKELONG(infoPtr
->CurVal
, temp
? 0 : 1);
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",
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 */
797 if (wParam
|| lParam
)
798 UNKNOWN_PARAM(UDM_GETRANGE
, wParam
, lParam
);
799 return MAKELONG(infoPtr
->MaxVal
, infoPtr
->MinVal
);
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
);
813 *(LPINT
)wParam
= infoPtr
->MinVal
;
815 *(LPINT
)lParam
= infoPtr
->MaxVal
;
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
);
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
);
838 /***********************************************************************
839 * UPDOWN_Register [Internal]
841 * Registers the updown window class.
845 UPDOWN_Register(void)
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.
871 UPDOWN_Unregister (VOID
)
873 if (GlobalFindAtomA (UPDOWN_CLASSA
))
874 UnregisterClassA (UPDOWN_CLASSA
, (HINSTANCE
)NULL
);