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

Last change on this file since 295 was 295, checked in by cbratschi, 26 years ago

wine-990704 updates, TBCUSTOMIZE implemented

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