1c2c66affSColin Finck /*
2c2c66affSColin Finck * Updown control
3c2c66affSColin Finck *
4c2c66affSColin Finck * Copyright 1997, 2002 Dimitrie O. Paun
5c2c66affSColin Finck *
6c2c66affSColin Finck * This library is free software; you can redistribute it and/or
7c2c66affSColin Finck * modify it under the terms of the GNU Lesser General Public
8c2c66affSColin Finck * License as published by the Free Software Foundation; either
9c2c66affSColin Finck * version 2.1 of the License, or (at your option) any later version.
10c2c66affSColin Finck *
11c2c66affSColin Finck * This library is distributed in the hope that it will be useful,
12c2c66affSColin Finck * but WITHOUT ANY WARRANTY; without even the implied warranty of
13c2c66affSColin Finck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14c2c66affSColin Finck * Lesser General Public License for more details.
15c2c66affSColin Finck *
16c2c66affSColin Finck * You should have received a copy of the GNU Lesser General Public
17c2c66affSColin Finck * License along with this library; if not, write to the Free Software
18c2c66affSColin Finck * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19c2c66affSColin Finck */
20c2c66affSColin Finck
21*0707475fSJustin Miller #include <assert.h>
22b3fb8555SGiannis Adamopoulos #include <stdlib.h>
23b3fb8555SGiannis Adamopoulos #include <string.h>
24b3fb8555SGiannis Adamopoulos #include <stdarg.h>
25b3fb8555SGiannis Adamopoulos #include <stdio.h>
26b3fb8555SGiannis Adamopoulos
27b3fb8555SGiannis Adamopoulos #include "windef.h"
28b3fb8555SGiannis Adamopoulos #include "winbase.h"
29b3fb8555SGiannis Adamopoulos #include "wingdi.h"
30b3fb8555SGiannis Adamopoulos #include "winuser.h"
31b3fb8555SGiannis Adamopoulos #include "winnls.h"
32b3fb8555SGiannis Adamopoulos #include "commctrl.h"
33c2c66affSColin Finck #include "comctl32.h"
34b3fb8555SGiannis Adamopoulos #include "uxtheme.h"
35b3fb8555SGiannis Adamopoulos #include "vssym32.h"
36b3fb8555SGiannis Adamopoulos #include "wine/heap.h"
37b3fb8555SGiannis Adamopoulos #include "wine/debug.h"
38c2c66affSColin Finck
39c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(updown);
40c2c66affSColin Finck
41c2c66affSColin Finck typedef struct
42c2c66affSColin Finck {
43c2c66affSColin Finck HWND Self; /* Handle to this up-down control */
44c2c66affSColin Finck HWND Notify; /* Handle to the parent window */
45c2c66affSColin Finck DWORD dwStyle; /* The GWL_STYLE for this window */
46c2c66affSColin Finck UINT AccelCount; /* Number of elements in AccelVect */
47c2c66affSColin Finck UDACCEL* AccelVect; /* Vector containing AccelCount elements */
48c2c66affSColin Finck INT AccelIndex; /* Current accel index, -1 if not accel'ing */
49c2c66affSColin Finck INT Base; /* Base to display nr in the buddy window */
50c2c66affSColin Finck INT CurVal; /* Current up-down value */
51c2c66affSColin Finck INT MinVal; /* Minimum up-down value */
52c2c66affSColin Finck INT MaxVal; /* Maximum up-down value */
53c2c66affSColin Finck HWND Buddy; /* Handle to the buddy window */
54c2c66affSColin Finck INT BuddyType; /* Remembers the buddy type BUDDY_TYPE_* */
55c2c66affSColin Finck INT Flags; /* Internal Flags FLAG_* */
56c2c66affSColin Finck BOOL UnicodeFormat; /* Marks the use of Unicode internally */
57c2c66affSColin Finck } UPDOWN_INFO;
58c2c66affSColin Finck
59c2c66affSColin Finck /* Control configuration constants */
60c2c66affSColin Finck
61c2c66affSColin Finck #define INITIAL_DELAY 500 /* initial timer until auto-inc kicks in */
62c2c66affSColin Finck #define AUTOPRESS_DELAY 250 /* time to keep arrow pressed on KEY_DOWN */
63c2c66affSColin Finck #define REPEAT_DELAY 50 /* delay between auto-increments */
64c2c66affSColin Finck
65c2c66affSColin Finck #define DEFAULT_WIDTH 16 /* default width of the ctrl */
66c2c66affSColin Finck #define DEFAULT_XSEP 0 /* default separation between buddy and ctrl */
67c2c66affSColin Finck #define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */
68c2c66affSColin Finck #define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */
69c2c66affSColin Finck #define DEFAULT_BUDDYBORDER 2 /* Width/height of the buddy border */
70c2c66affSColin Finck #define DEFAULT_BUDDYSPACER 2 /* Spacer between the buddy and the ctrl */
71c2c66affSColin Finck #define DEFAULT_BUDDYBORDER_THEMED 1 /* buddy border when theming is enabled */
72c2c66affSColin Finck #define DEFAULT_BUDDYSPACER_THEMED 0 /* buddy spacer when theming is enabled */
73c2c66affSColin Finck
74c2c66affSColin Finck /* Work constants */
75c2c66affSColin Finck
76c2c66affSColin Finck #define FLAG_INCR 0x01
77c2c66affSColin Finck #define FLAG_DECR 0x02
78c2c66affSColin Finck #define FLAG_MOUSEIN 0x04
79c2c66affSColin Finck #define FLAG_PRESSED 0x08
80c2c66affSColin Finck #define FLAG_BUDDYINT 0x10 /* UDS_SETBUDDYINT was set on creation */
81c2c66affSColin Finck #define FLAG_ARROW (FLAG_INCR | FLAG_DECR)
82c2c66affSColin Finck
83c2c66affSColin Finck #define BUDDY_TYPE_UNKNOWN 0
84c2c66affSColin Finck #define BUDDY_TYPE_LISTBOX 1
85c2c66affSColin Finck #define BUDDY_TYPE_EDIT 2
86c2c66affSColin Finck
87c2c66affSColin Finck #define TIMER_AUTOREPEAT 1
88c2c66affSColin Finck #define TIMER_ACCEL 2
89c2c66affSColin Finck #define TIMER_AUTOPRESS 3
90c2c66affSColin Finck
91c2c66affSColin Finck #define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongPtrW (hwnd,0))
92c2c66affSColin Finck
93c2c66affSColin Finck /* id used for SetWindowSubclass */
94c2c66affSColin Finck #define BUDDY_SUBCLASSID 1
95c2c66affSColin Finck
96c2c66affSColin Finck static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action);
97c2c66affSColin Finck
98c2c66affSColin Finck /***********************************************************************
99c2c66affSColin Finck * UPDOWN_IsBuddyEdit
100c2c66affSColin Finck * Tests if our buddy is an edit control.
101c2c66affSColin Finck */
UPDOWN_IsBuddyEdit(const UPDOWN_INFO * infoPtr)102c2c66affSColin Finck static inline BOOL UPDOWN_IsBuddyEdit(const UPDOWN_INFO *infoPtr)
103c2c66affSColin Finck {
104c2c66affSColin Finck return infoPtr->BuddyType == BUDDY_TYPE_EDIT;
105c2c66affSColin Finck }
106c2c66affSColin Finck
107c2c66affSColin Finck /***********************************************************************
108c2c66affSColin Finck * UPDOWN_IsBuddyListbox
109c2c66affSColin Finck * Tests if our buddy is a listbox control.
110c2c66affSColin Finck */
UPDOWN_IsBuddyListbox(const UPDOWN_INFO * infoPtr)111c2c66affSColin Finck static inline BOOL UPDOWN_IsBuddyListbox(const UPDOWN_INFO *infoPtr)
112c2c66affSColin Finck {
113c2c66affSColin Finck return infoPtr->BuddyType == BUDDY_TYPE_LISTBOX;
114c2c66affSColin Finck }
115c2c66affSColin Finck
116c2c66affSColin Finck /***********************************************************************
117c2c66affSColin Finck * UPDOWN_InBounds
118c2c66affSColin Finck * Tests if a given value 'val' is between the Min&Max limits
119c2c66affSColin Finck */
UPDOWN_InBounds(const UPDOWN_INFO * infoPtr,int val)120c2c66affSColin Finck static BOOL UPDOWN_InBounds(const UPDOWN_INFO *infoPtr, int val)
121c2c66affSColin Finck {
122c2c66affSColin Finck if(infoPtr->MaxVal > infoPtr->MinVal)
123c2c66affSColin Finck return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal);
124c2c66affSColin Finck else
125c2c66affSColin Finck return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal);
126c2c66affSColin Finck }
127c2c66affSColin Finck
128c2c66affSColin Finck /***********************************************************************
129c2c66affSColin Finck * UPDOWN_OffsetVal
130c2c66affSColin Finck * Change the current value by delta.
131c2c66affSColin Finck * It returns TRUE is the value was changed successfully, or FALSE
132c2c66affSColin Finck * if the value was not changed, as it would go out of bounds.
133c2c66affSColin Finck */
UPDOWN_OffsetVal(UPDOWN_INFO * infoPtr,int delta)134c2c66affSColin Finck static BOOL UPDOWN_OffsetVal(UPDOWN_INFO *infoPtr, int delta)
135c2c66affSColin Finck {
136c2c66affSColin Finck /* check if we can do the modification first */
137c2c66affSColin Finck if(!UPDOWN_InBounds (infoPtr, infoPtr->CurVal+delta)) {
138c2c66affSColin Finck if (infoPtr->dwStyle & UDS_WRAP) {
139c2c66affSColin Finck delta += (delta < 0 ? -1 : 1) *
140c2c66affSColin Finck (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) *
141c2c66affSColin Finck (infoPtr->MinVal - infoPtr->MaxVal) +
142c2c66affSColin Finck (delta < 0 ? 1 : -1);
143c2c66affSColin Finck } else if ((infoPtr->MaxVal > infoPtr->MinVal && infoPtr->CurVal+delta > infoPtr->MaxVal)
144c2c66affSColin Finck || (infoPtr->MaxVal < infoPtr->MinVal && infoPtr->CurVal+delta < infoPtr->MaxVal)) {
145c2c66affSColin Finck delta = infoPtr->MaxVal - infoPtr->CurVal;
146c2c66affSColin Finck } else {
147c2c66affSColin Finck delta = infoPtr->MinVal - infoPtr->CurVal;
148c2c66affSColin Finck }
149c2c66affSColin Finck }
150c2c66affSColin Finck
151c2c66affSColin Finck infoPtr->CurVal += delta;
152c2c66affSColin Finck return delta != 0;
153c2c66affSColin Finck }
154c2c66affSColin Finck
155c2c66affSColin Finck /***********************************************************************
156c2c66affSColin Finck * UPDOWN_HasBuddyBorder
157c2c66affSColin Finck *
158c2c66affSColin Finck * When we have a buddy set and that we are aligned on our buddy, we
159c2c66affSColin Finck * want to draw a sunken edge to make like we are part of that control.
160c2c66affSColin Finck */
UPDOWN_HasBuddyBorder(const UPDOWN_INFO * infoPtr)161c2c66affSColin Finck static BOOL UPDOWN_HasBuddyBorder(const UPDOWN_INFO *infoPtr)
162c2c66affSColin Finck {
163c2c66affSColin Finck return ( ((infoPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) &&
164c2c66affSColin Finck UPDOWN_IsBuddyEdit(infoPtr) );
165c2c66affSColin Finck }
166c2c66affSColin Finck
167c2c66affSColin Finck /***********************************************************************
168c2c66affSColin Finck * UPDOWN_GetArrowRect
169c2c66affSColin Finck * wndPtr - pointer to the up-down wnd
170c2c66affSColin Finck * rect - will hold the rectangle
171c2c66affSColin Finck * arrow - FLAG_INCR to get the "increment" rect (up or right)
172c2c66affSColin Finck * FLAG_DECR to get the "decrement" rect (down or left)
173c2c66affSColin Finck */
UPDOWN_GetArrowRect(const UPDOWN_INFO * infoPtr,RECT * rect,unsigned int arrow)174*0707475fSJustin Miller static void UPDOWN_GetArrowRect (const UPDOWN_INFO* infoPtr, RECT *rect, unsigned int arrow)
175c2c66affSColin Finck {
176c2c66affSColin Finck HTHEME theme = GetWindowTheme (infoPtr->Self);
177c2c66affSColin Finck const int border = theme ? DEFAULT_BUDDYBORDER_THEMED : DEFAULT_BUDDYBORDER;
178c2c66affSColin Finck const int spacer = theme ? DEFAULT_BUDDYSPACER_THEMED : DEFAULT_BUDDYSPACER;
179*0707475fSJustin Miller int size;
180*0707475fSJustin Miller
181*0707475fSJustin Miller assert(arrow && (arrow & (FLAG_INCR | FLAG_DECR)) != (FLAG_INCR | FLAG_DECR));
182*0707475fSJustin Miller
183c2c66affSColin Finck GetClientRect (infoPtr->Self, rect);
184c2c66affSColin Finck
185c2c66affSColin Finck /*
186c2c66affSColin Finck * Make sure we calculate the rectangle to fit even if we draw the
187c2c66affSColin Finck * border.
188c2c66affSColin Finck */
189c2c66affSColin Finck if (UPDOWN_HasBuddyBorder(infoPtr)) {
190c2c66affSColin Finck if (infoPtr->dwStyle & UDS_ALIGNLEFT)
191c2c66affSColin Finck rect->left += border;
192c2c66affSColin Finck else
193c2c66affSColin Finck rect->right -= border;
194c2c66affSColin Finck
195c2c66affSColin Finck InflateRect(rect, 0, -border);
196c2c66affSColin Finck }
197c2c66affSColin Finck
198c2c66affSColin Finck /* now figure out if we need a space away from the buddy */
199c2c66affSColin Finck if (IsWindow(infoPtr->Buddy) ) {
200c2c66affSColin Finck if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= spacer;
201c2c66affSColin Finck else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) rect->left += spacer;
202c2c66affSColin Finck }
203c2c66affSColin Finck
204c2c66affSColin Finck /*
205c2c66affSColin Finck * We're calculating the midpoint to figure-out where the
206*0707475fSJustin Miller * separation between the buttons will lay.
207c2c66affSColin Finck */
208c2c66affSColin Finck if (infoPtr->dwStyle & UDS_HORZ) {
209*0707475fSJustin Miller size = (rect->right - rect->left) / 2;
210c2c66affSColin Finck if (arrow & FLAG_INCR)
211*0707475fSJustin Miller rect->left = rect->right - size;
212*0707475fSJustin Miller else if (arrow & FLAG_DECR)
213*0707475fSJustin Miller rect->right = rect->left + size;
214c2c66affSColin Finck } else {
215*0707475fSJustin Miller size = (rect->bottom - rect->top) / 2;
216c2c66affSColin Finck if (arrow & FLAG_INCR)
217*0707475fSJustin Miller rect->bottom = rect->top + size;
218*0707475fSJustin Miller else if (arrow & FLAG_DECR)
219*0707475fSJustin Miller rect->top = rect->bottom - size;
220c2c66affSColin Finck }
221c2c66affSColin Finck }
222c2c66affSColin Finck
223c2c66affSColin Finck /***********************************************************************
224c2c66affSColin Finck * UPDOWN_GetArrowFromPoint
225c2c66affSColin Finck * Returns the rectagle (for the up or down arrow) that contains pt.
226c2c66affSColin Finck * If it returns the up rect, it returns FLAG_INCR.
227c2c66affSColin Finck * If it returns the down rect, it returns FLAG_DECR.
228c2c66affSColin Finck */
UPDOWN_GetArrowFromPoint(const UPDOWN_INFO * infoPtr,RECT * rect,POINT pt)229c2c66affSColin Finck static INT UPDOWN_GetArrowFromPoint (const UPDOWN_INFO *infoPtr, RECT *rect, POINT pt)
230c2c66affSColin Finck {
231c2c66affSColin Finck UPDOWN_GetArrowRect (infoPtr, rect, FLAG_INCR);
232c2c66affSColin Finck if(PtInRect(rect, pt)) return FLAG_INCR;
233c2c66affSColin Finck
234c2c66affSColin Finck UPDOWN_GetArrowRect (infoPtr, rect, FLAG_DECR);
235c2c66affSColin Finck if(PtInRect(rect, pt)) return FLAG_DECR;
236c2c66affSColin Finck
237c2c66affSColin Finck return 0;
238c2c66affSColin Finck }
239c2c66affSColin Finck
240c2c66affSColin Finck
241c2c66affSColin Finck /***********************************************************************
242c2c66affSColin Finck * UPDOWN_GetThousandSep
243c2c66affSColin Finck * Returns the thousand sep. If an error occurs, it returns ','.
244c2c66affSColin Finck */
UPDOWN_GetThousandSep(void)245c2c66affSColin Finck static WCHAR UPDOWN_GetThousandSep(void)
246c2c66affSColin Finck {
247c2c66affSColin Finck WCHAR sep[2];
248c2c66affSColin Finck
249c2c66affSColin Finck if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sep, 2) != 1)
250c2c66affSColin Finck sep[0] = ',';
251c2c66affSColin Finck
252c2c66affSColin Finck return sep[0];
253c2c66affSColin Finck }
254c2c66affSColin Finck
255c2c66affSColin Finck /***********************************************************************
256c2c66affSColin Finck * UPDOWN_GetBuddyInt
257c2c66affSColin Finck * Tries to read the pos from the buddy window and if it succeeds,
258c2c66affSColin Finck * it stores it in the control's CurVal
259c2c66affSColin Finck * returns:
260c2c66affSColin Finck * TRUE - if it read the integer from the buddy successfully
261c2c66affSColin Finck * FALSE - if an error occurred
262c2c66affSColin Finck */
UPDOWN_GetBuddyInt(UPDOWN_INFO * infoPtr)263c2c66affSColin Finck static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr)
264c2c66affSColin Finck {
265c2c66affSColin Finck WCHAR txt[20], sep, *src, *dst;
266c2c66affSColin Finck int newVal;
267c2c66affSColin Finck
268c2c66affSColin Finck if (!((infoPtr->Flags & FLAG_BUDDYINT) && IsWindow(infoPtr->Buddy)))
269c2c66affSColin Finck return FALSE;
270c2c66affSColin Finck
271c2c66affSColin Finck /*if the buddy is a list window, we must set curr index */
272c2c66affSColin Finck if (UPDOWN_IsBuddyListbox(infoPtr)) {
273c2c66affSColin Finck newVal = SendMessageW(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0);
274c2c66affSColin Finck if(newVal < 0) return FALSE;
275c2c66affSColin Finck } else {
276c2c66affSColin Finck /* we have a regular window, so will get the text */
277c2c66affSColin Finck /* note that a zero-length string is a legitimate value for 'txt',
278c2c66affSColin Finck * and ought to result in a successful conversion to '0'. */
279b3fb8555SGiannis Adamopoulos if (GetWindowTextW(infoPtr->Buddy, txt, ARRAY_SIZE(txt)) < 0)
280c2c66affSColin Finck return FALSE;
281c2c66affSColin Finck
282c2c66affSColin Finck sep = UPDOWN_GetThousandSep();
283c2c66affSColin Finck
284c2c66affSColin Finck /* now get rid of the separators */
285c2c66affSColin Finck for(src = dst = txt; *src; src++)
286c2c66affSColin Finck if(*src != sep) *dst++ = *src;
287c2c66affSColin Finck *dst = 0;
288c2c66affSColin Finck
289c2c66affSColin Finck /* try to convert the number and validate it */
290*0707475fSJustin Miller newVal = wcstol(txt, &src, infoPtr->Base);
291c2c66affSColin Finck if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE;
292c2c66affSColin Finck }
293c2c66affSColin Finck
294c2c66affSColin Finck TRACE("new value(%d) from buddy (old=%d)\n", newVal, infoPtr->CurVal);
295c2c66affSColin Finck infoPtr->CurVal = newVal;
296c2c66affSColin Finck return TRUE;
297c2c66affSColin Finck }
298c2c66affSColin Finck
299c2c66affSColin Finck
300c2c66affSColin Finck /***********************************************************************
301c2c66affSColin Finck * UPDOWN_SetBuddyInt
302c2c66affSColin Finck * Tries to set the pos to the buddy window based on current pos
303c2c66affSColin Finck * returns:
304c2c66affSColin Finck * TRUE - if it set the caption of the buddy successfully
305c2c66affSColin Finck * FALSE - if an error occurred
306c2c66affSColin Finck */
UPDOWN_SetBuddyInt(const UPDOWN_INFO * infoPtr)307c2c66affSColin Finck static BOOL UPDOWN_SetBuddyInt (const UPDOWN_INFO *infoPtr)
308c2c66affSColin Finck {
309c2c66affSColin Finck static const WCHAR fmt_hex[] = { '0', 'x', '%', '0', '4', 'X', 0 };
310c2c66affSColin Finck static const WCHAR fmt_dec_oct[] = { '%', 'd', '\0' };
311c2c66affSColin Finck const WCHAR *fmt;
312c2c66affSColin Finck WCHAR txt[20], txt_old[20] = { 0 };
313c2c66affSColin Finck int len;
314c2c66affSColin Finck
315c2c66affSColin Finck if (!((infoPtr->Flags & FLAG_BUDDYINT) && IsWindow(infoPtr->Buddy)))
316c2c66affSColin Finck return FALSE;
317c2c66affSColin Finck
318c2c66affSColin Finck TRACE("set new value(%d) to buddy.\n", infoPtr->CurVal);
319c2c66affSColin Finck
320c2c66affSColin Finck /*if the buddy is a list window, we must set curr index */
321c2c66affSColin Finck if (UPDOWN_IsBuddyListbox(infoPtr)) {
322c2c66affSColin Finck return SendMessageW(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0) != LB_ERR;
323c2c66affSColin Finck }
324c2c66affSColin Finck
325c2c66affSColin Finck /* Regular window, so set caption to the number */
326c2c66affSColin Finck fmt = (infoPtr->Base == 16) ? fmt_hex : fmt_dec_oct;
327c2c66affSColin Finck len = wsprintfW(txt, fmt, infoPtr->CurVal);
328c2c66affSColin Finck
329c2c66affSColin Finck
330c2c66affSColin Finck /* Do thousands separation if necessary */
331c2c66affSColin Finck if ((infoPtr->Base == 10) && !(infoPtr->dwStyle & UDS_NOTHOUSANDS) && (len > 3)) {
332b3fb8555SGiannis Adamopoulos WCHAR tmp[ARRAY_SIZE(txt)], *src = tmp, *dst = txt;
333c2c66affSColin Finck WCHAR sep = UPDOWN_GetThousandSep();
334c2c66affSColin Finck int start = len % 3;
335c2c66affSColin Finck
336c2c66affSColin Finck memcpy(tmp, txt, sizeof(txt));
337c2c66affSColin Finck if (start == 0) start = 3;
338c2c66affSColin Finck dst += start;
339c2c66affSColin Finck src += start;
340c2c66affSColin Finck for (len=0; *src; len++) {
341c2c66affSColin Finck if (len % 3 == 0) *dst++ = sep;
342c2c66affSColin Finck *dst++ = *src++;
343c2c66affSColin Finck }
344c2c66affSColin Finck *dst = 0;
345c2c66affSColin Finck }
346c2c66affSColin Finck
347c2c66affSColin Finck /* if nothing changed exit earlier */
348b3fb8555SGiannis Adamopoulos GetWindowTextW(infoPtr->Buddy, txt_old, ARRAY_SIZE(txt_old));
349c2c66affSColin Finck if (lstrcmpiW(txt_old, txt) == 0) return FALSE;
350c2c66affSColin Finck
351c2c66affSColin Finck return SetWindowTextW(infoPtr->Buddy, txt);
352c2c66affSColin Finck }
353c2c66affSColin Finck
354c2c66affSColin Finck /***********************************************************************
355c2c66affSColin Finck * UPDOWN_DrawBuddyBackground
356c2c66affSColin Finck *
357c2c66affSColin Finck * Draw buddy background for visual integration.
358c2c66affSColin Finck */
UPDOWN_DrawBuddyBackground(const UPDOWN_INFO * infoPtr,HDC hdc)359c2c66affSColin Finck static BOOL UPDOWN_DrawBuddyBackground (const UPDOWN_INFO *infoPtr, HDC hdc)
360c2c66affSColin Finck {
361c2c66affSColin Finck RECT br, r;
362c2c66affSColin Finck HTHEME buddyTheme = GetWindowTheme (infoPtr->Buddy);
363c2c66affSColin Finck if (!buddyTheme) return FALSE;
364c2c66affSColin Finck
365c2c66affSColin Finck GetWindowRect (infoPtr->Buddy, &br);
366c2c66affSColin Finck MapWindowPoints (NULL, infoPtr->Self, (POINT*)&br, 2);
367c2c66affSColin Finck GetClientRect (infoPtr->Self, &r);
368c2c66affSColin Finck
369c2c66affSColin Finck if (infoPtr->dwStyle & UDS_ALIGNLEFT)
370c2c66affSColin Finck br.left = r.left;
371c2c66affSColin Finck else if (infoPtr->dwStyle & UDS_ALIGNRIGHT)
372c2c66affSColin Finck br.right = r.right;
373c2c66affSColin Finck /* FIXME: take disabled etc. into account */
374c2c66affSColin Finck DrawThemeBackground (buddyTheme, hdc, 0, 0, &br, NULL);
375c2c66affSColin Finck return TRUE;
376c2c66affSColin Finck }
377c2c66affSColin Finck
378c2c66affSColin Finck /***********************************************************************
379c2c66affSColin Finck * UPDOWN_Draw
380c2c66affSColin Finck *
381c2c66affSColin Finck * Draw the arrows. The background need not be erased.
382c2c66affSColin Finck */
UPDOWN_Draw(const UPDOWN_INFO * infoPtr,HDC hdc)383c2c66affSColin Finck static LRESULT UPDOWN_Draw (const UPDOWN_INFO *infoPtr, HDC hdc)
384c2c66affSColin Finck {
385c2c66affSColin Finck BOOL uPressed, uHot, dPressed, dHot;
386c2c66affSColin Finck RECT rect;
387c2c66affSColin Finck HTHEME theme = GetWindowTheme (infoPtr->Self);
388c2c66affSColin Finck int uPart = 0, uState = 0, dPart = 0, dState = 0;
389c2c66affSColin Finck BOOL needBuddyBg = FALSE;
390c2c66affSColin Finck
391c2c66affSColin Finck uPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR);
392c2c66affSColin Finck uHot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
393c2c66affSColin Finck dPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR);
394c2c66affSColin Finck dHot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
395c2c66affSColin Finck if (theme) {
396c2c66affSColin Finck uPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_UPHORZ : SPNP_UP;
397c2c66affSColin Finck uState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
398c2c66affSColin Finck : (uPressed ? DNS_PRESSED : (uHot ? DNS_HOT : DNS_NORMAL));
399c2c66affSColin Finck dPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_DOWNHORZ : SPNP_DOWN;
400c2c66affSColin Finck dState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
401c2c66affSColin Finck : (dPressed ? DNS_PRESSED : (dHot ? DNS_HOT : DNS_NORMAL));
402c2c66affSColin Finck needBuddyBg = IsWindow (infoPtr->Buddy)
403c2c66affSColin Finck && (IsThemeBackgroundPartiallyTransparent (theme, uPart, uState)
404c2c66affSColin Finck || IsThemeBackgroundPartiallyTransparent (theme, dPart, dState));
405c2c66affSColin Finck }
406c2c66affSColin Finck
407c2c66affSColin Finck /* Draw the common border between ourselves and our buddy */
408c2c66affSColin Finck if (UPDOWN_HasBuddyBorder(infoPtr) || needBuddyBg) {
409c2c66affSColin Finck if (!theme || !UPDOWN_DrawBuddyBackground (infoPtr, hdc)) {
410c2c66affSColin Finck GetClientRect(infoPtr->Self, &rect);
411c2c66affSColin Finck DrawEdge(hdc, &rect, EDGE_SUNKEN,
412c2c66affSColin Finck BF_BOTTOM | BF_TOP |
413c2c66affSColin Finck (infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT));
414c2c66affSColin Finck }
415c2c66affSColin Finck }
416c2c66affSColin Finck
417c2c66affSColin Finck /* Draw the incr button */
418c2c66affSColin Finck UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR);
419c2c66affSColin Finck if (theme) {
420c2c66affSColin Finck DrawThemeBackground(theme, hdc, uPart, uState, &rect, NULL);
421c2c66affSColin Finck } else {
422c2c66affSColin Finck DrawFrameControl(hdc, &rect, DFC_SCROLL,
423c2c66affSColin Finck (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) |
424c2c66affSColin Finck ((infoPtr->dwStyle & UDS_HOTTRACK) && uHot ? DFCS_HOT : 0) |
425c2c66affSColin Finck (uPressed ? DFCS_PUSHED : 0) |
426c2c66affSColin Finck (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
427c2c66affSColin Finck }
428c2c66affSColin Finck
429c2c66affSColin Finck /* Draw the decr button */
430c2c66affSColin Finck UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR);
431c2c66affSColin Finck if (theme) {
432c2c66affSColin Finck DrawThemeBackground(theme, hdc, dPart, dState, &rect, NULL);
433c2c66affSColin Finck } else {
434c2c66affSColin Finck DrawFrameControl(hdc, &rect, DFC_SCROLL,
435c2c66affSColin Finck (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) |
436c2c66affSColin Finck ((infoPtr->dwStyle & UDS_HOTTRACK) && dHot ? DFCS_HOT : 0) |
437c2c66affSColin Finck (dPressed ? DFCS_PUSHED : 0) |
438c2c66affSColin Finck (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
439c2c66affSColin Finck }
440c2c66affSColin Finck
441c2c66affSColin Finck return 0;
442c2c66affSColin Finck }
443c2c66affSColin Finck
444c2c66affSColin Finck /***********************************************************************
445c2c66affSColin Finck * UPDOWN_Paint
446c2c66affSColin Finck *
447c2c66affSColin Finck * Asynchronous drawing (must ONLY be used in WM_PAINT).
448c2c66affSColin Finck * Calls UPDOWN_Draw.
449c2c66affSColin Finck */
UPDOWN_Paint(const UPDOWN_INFO * infoPtr,HDC hdc)450c2c66affSColin Finck static LRESULT UPDOWN_Paint (const UPDOWN_INFO *infoPtr, HDC hdc)
451c2c66affSColin Finck {
452c2c66affSColin Finck PAINTSTRUCT ps;
453c2c66affSColin Finck if (hdc) return UPDOWN_Draw (infoPtr, hdc);
454c2c66affSColin Finck hdc = BeginPaint (infoPtr->Self, &ps);
455c2c66affSColin Finck UPDOWN_Draw (infoPtr, hdc);
456c2c66affSColin Finck EndPaint (infoPtr->Self, &ps);
457c2c66affSColin Finck return 0;
458c2c66affSColin Finck }
459c2c66affSColin Finck
460c2c66affSColin Finck /***********************************************************************
461c2c66affSColin Finck * UPDOWN_KeyPressed
462c2c66affSColin Finck *
463c2c66affSColin Finck * Handle key presses (up & down) when we have to do so
464c2c66affSColin Finck */
UPDOWN_KeyPressed(UPDOWN_INFO * infoPtr,int key)465c2c66affSColin Finck static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key)
466c2c66affSColin Finck {
467c2c66affSColin Finck int arrow, accel;
468c2c66affSColin Finck
469c2c66affSColin Finck if (key == VK_UP) arrow = FLAG_INCR;
470c2c66affSColin Finck else if (key == VK_DOWN) arrow = FLAG_DECR;
471c2c66affSColin Finck else return 1;
472c2c66affSColin Finck
473c2c66affSColin Finck UPDOWN_GetBuddyInt (infoPtr);
474c2c66affSColin Finck infoPtr->Flags &= ~FLAG_ARROW;
475c2c66affSColin Finck infoPtr->Flags |= FLAG_PRESSED | arrow;
476c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
477c2c66affSColin Finck SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0);
478c2c66affSColin Finck accel = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1;
479c2c66affSColin Finck UPDOWN_DoAction (infoPtr, accel, arrow);
480c2c66affSColin Finck return 0;
481c2c66affSColin Finck }
482c2c66affSColin Finck
UPDOWN_GetPos(UPDOWN_INFO * infoPtr,BOOL * err)483c2c66affSColin Finck static int UPDOWN_GetPos(UPDOWN_INFO *infoPtr, BOOL *err)
484c2c66affSColin Finck {
485c2c66affSColin Finck BOOL succ = UPDOWN_GetBuddyInt(infoPtr);
486c2c66affSColin Finck int val = infoPtr->CurVal;
487c2c66affSColin Finck
488c2c66affSColin Finck if(!UPDOWN_InBounds(infoPtr, val)) {
489c2c66affSColin Finck if((infoPtr->MinVal < infoPtr->MaxVal && val < infoPtr->MinVal)
490c2c66affSColin Finck || (infoPtr->MinVal > infoPtr->MaxVal && val > infoPtr->MinVal))
491c2c66affSColin Finck val = infoPtr->MinVal;
492c2c66affSColin Finck else
493c2c66affSColin Finck val = infoPtr->MaxVal;
494c2c66affSColin Finck
495c2c66affSColin Finck succ = FALSE;
496c2c66affSColin Finck }
497c2c66affSColin Finck
498c2c66affSColin Finck if(err) *err = !succ;
499c2c66affSColin Finck return val;
500c2c66affSColin Finck }
501c2c66affSColin Finck
UPDOWN_SetPos(UPDOWN_INFO * infoPtr,int pos)502c2c66affSColin Finck static int UPDOWN_SetPos(UPDOWN_INFO *infoPtr, int pos)
503c2c66affSColin Finck {
504c2c66affSColin Finck int ret = infoPtr->CurVal;
505c2c66affSColin Finck
506c2c66affSColin Finck if(!UPDOWN_InBounds(infoPtr, pos)) {
507c2c66affSColin Finck if((infoPtr->MinVal < infoPtr->MaxVal && pos < infoPtr->MinVal)
508c2c66affSColin Finck || (infoPtr->MinVal > infoPtr->MaxVal && pos > infoPtr->MinVal))
509c2c66affSColin Finck pos = infoPtr->MinVal;
510c2c66affSColin Finck else
511c2c66affSColin Finck pos = infoPtr->MaxVal;
512c2c66affSColin Finck }
513c2c66affSColin Finck
514c2c66affSColin Finck infoPtr->CurVal = pos;
515c2c66affSColin Finck UPDOWN_SetBuddyInt(infoPtr);
516c2c66affSColin Finck
517c2c66affSColin Finck if(!UPDOWN_InBounds(infoPtr, ret)) {
518c2c66affSColin Finck if((infoPtr->MinVal < infoPtr->MaxVal && ret < infoPtr->MinVal)
519c2c66affSColin Finck || (infoPtr->MinVal > infoPtr->MaxVal && ret > infoPtr->MinVal))
520c2c66affSColin Finck ret = infoPtr->MinVal;
521c2c66affSColin Finck else
522c2c66affSColin Finck ret = infoPtr->MaxVal;
523c2c66affSColin Finck }
524c2c66affSColin Finck return ret;
525c2c66affSColin Finck }
526c2c66affSColin Finck
527c2c66affSColin Finck
528c2c66affSColin Finck /***********************************************************************
529c2c66affSColin Finck * UPDOWN_SetRange
530c2c66affSColin Finck *
531c2c66affSColin Finck * Handle UDM_SETRANGE, UDM_SETRANGE32
532c2c66affSColin Finck *
533c2c66affSColin Finck * FIXME: handle Max == Min properly:
534c2c66affSColin Finck * - arrows should be disabled (without WS_DISABLED set),
535c2c66affSColin Finck * visually they can't be pressed and don't respond;
536c2c66affSColin Finck * - all input messages should still pass in.
537c2c66affSColin Finck */
UPDOWN_SetRange(UPDOWN_INFO * infoPtr,INT Max,INT Min)538c2c66affSColin Finck static LRESULT UPDOWN_SetRange(UPDOWN_INFO *infoPtr, INT Max, INT Min)
539c2c66affSColin Finck {
540c2c66affSColin Finck infoPtr->MaxVal = Max;
541c2c66affSColin Finck infoPtr->MinVal = Min;
542c2c66affSColin Finck
543c2c66affSColin Finck TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n",
544c2c66affSColin Finck infoPtr->MinVal, infoPtr->MaxVal, infoPtr->Self);
545c2c66affSColin Finck
546c2c66affSColin Finck return 0;
547c2c66affSColin Finck }
548c2c66affSColin Finck
549c2c66affSColin Finck /***********************************************************************
550c2c66affSColin Finck * UPDOWN_MouseWheel
551c2c66affSColin Finck *
552c2c66affSColin Finck * Handle mouse wheel scrolling
553c2c66affSColin Finck */
UPDOWN_MouseWheel(UPDOWN_INFO * infoPtr,WPARAM wParam)554c2c66affSColin Finck static LRESULT UPDOWN_MouseWheel(UPDOWN_INFO *infoPtr, WPARAM wParam)
555c2c66affSColin Finck {
556c2c66affSColin Finck int iWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
557c2c66affSColin Finck
558c2c66affSColin Finck if (wParam & (MK_SHIFT | MK_CONTROL))
559c2c66affSColin Finck return 0;
560c2c66affSColin Finck
561c2c66affSColin Finck if (iWheelDelta != 0)
562c2c66affSColin Finck {
563c2c66affSColin Finck UPDOWN_GetBuddyInt(infoPtr);
564c2c66affSColin Finck UPDOWN_DoAction(infoPtr, abs(iWheelDelta), iWheelDelta > 0 ? FLAG_INCR : FLAG_DECR);
565c2c66affSColin Finck }
566c2c66affSColin Finck
567c2c66affSColin Finck return 1;
568c2c66affSColin Finck }
569c2c66affSColin Finck
570c2c66affSColin Finck
571c2c66affSColin Finck /***********************************************************************
572c2c66affSColin Finck * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy
573c2c66affSColin Finck * control.
574c2c66affSColin Finck */
575c2c66affSColin Finck static LRESULT CALLBACK
UPDOWN_Buddy_SubclassProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam,UINT_PTR uId,DWORD_PTR ref_data)576c2c66affSColin Finck UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
577c2c66affSColin Finck UINT_PTR uId, DWORD_PTR ref_data)
578c2c66affSColin Finck {
579c2c66affSColin Finck UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr((HWND)ref_data);
580c2c66affSColin Finck
581c2c66affSColin Finck TRACE("hwnd=%p, uMsg=%04x, wParam=%08lx, lParam=%08lx\n",
582c2c66affSColin Finck hwnd, uMsg, wParam, lParam);
583c2c66affSColin Finck
584c2c66affSColin Finck switch(uMsg)
585c2c66affSColin Finck {
586c2c66affSColin Finck case WM_KEYDOWN:
587b3fb8555SGiannis Adamopoulos if (infoPtr)
588b3fb8555SGiannis Adamopoulos {
589c2c66affSColin Finck UPDOWN_KeyPressed(infoPtr, (int)wParam);
590b3fb8555SGiannis Adamopoulos if (wParam == VK_UP || wParam == VK_DOWN)
591b3fb8555SGiannis Adamopoulos return 0;
592b3fb8555SGiannis Adamopoulos }
593c2c66affSColin Finck break;
594c2c66affSColin Finck
595c2c66affSColin Finck case WM_MOUSEWHEEL:
596b3fb8555SGiannis Adamopoulos if (infoPtr)
597c2c66affSColin Finck UPDOWN_MouseWheel(infoPtr, (int)wParam);
598c2c66affSColin Finck break;
599c2c66affSColin Finck
600b3fb8555SGiannis Adamopoulos case WM_NCDESTROY:
601b3fb8555SGiannis Adamopoulos RemoveWindowSubclass(hwnd, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID);
602b3fb8555SGiannis Adamopoulos break;
603c2c66affSColin Finck default:
604c2c66affSColin Finck break;
605c2c66affSColin Finck }
606c2c66affSColin Finck
607c2c66affSColin Finck return DefSubclassProc(hwnd, uMsg, wParam, lParam);
608c2c66affSColin Finck }
609c2c66affSColin Finck
UPDOWN_ResetSubclass(UPDOWN_INFO * infoPtr)610b3fb8555SGiannis Adamopoulos static void UPDOWN_ResetSubclass (UPDOWN_INFO *infoPtr)
611b3fb8555SGiannis Adamopoulos {
612b3fb8555SGiannis Adamopoulos SetWindowSubclass(infoPtr->Buddy, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID, 0);
613b3fb8555SGiannis Adamopoulos }
614b3fb8555SGiannis Adamopoulos
615c2c66affSColin Finck /***********************************************************************
616c2c66affSColin Finck * UPDOWN_SetBuddy
617c2c66affSColin Finck *
618c2c66affSColin Finck * Sets bud as a new Buddy.
619c2c66affSColin Finck * Then, it should subclass the buddy
620c2c66affSColin Finck * If window has the UDS_ARROWKEYS, it subclasses the buddy window to
621c2c66affSColin Finck * process the UP/DOWN arrow keys.
622c2c66affSColin Finck * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style
623c2c66affSColin Finck * the size/pos of the buddy and the control are adjusted accordingly.
624c2c66affSColin Finck */
UPDOWN_SetBuddy(UPDOWN_INFO * infoPtr,HWND bud)625c2c66affSColin Finck static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud)
626c2c66affSColin Finck {
627c2c66affSColin Finck RECT budRect; /* new coord for the buddy */
628c2c66affSColin Finck int x, width; /* new x position and width for the up-down */
629c2c66affSColin Finck WCHAR buddyClass[40];
630edd99e8cSAmine Khaldi HWND old_buddy;
631c2c66affSColin Finck
632c2c66affSColin Finck TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud);
633c2c66affSColin Finck
634edd99e8cSAmine Khaldi old_buddy = infoPtr->Buddy;
635c2c66affSColin Finck
636b3fb8555SGiannis Adamopoulos UPDOWN_ResetSubclass (infoPtr);
637b3fb8555SGiannis Adamopoulos
638c2c66affSColin Finck if (!IsWindow(bud)) bud = NULL;
639c2c66affSColin Finck
640c2c66affSColin Finck /* Store buddy window handle */
641c2c66affSColin Finck infoPtr->Buddy = bud;
642c2c66affSColin Finck
643c2c66affSColin Finck if(bud) {
644c2c66affSColin Finck /* Store buddy window class type */
645c2c66affSColin Finck infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN;
646b3fb8555SGiannis Adamopoulos if (GetClassNameW(bud, buddyClass, ARRAY_SIZE(buddyClass))) {
647c2c66affSColin Finck if (lstrcmpiW(buddyClass, WC_EDITW) == 0)
648c2c66affSColin Finck infoPtr->BuddyType = BUDDY_TYPE_EDIT;
649c2c66affSColin Finck else if (lstrcmpiW(buddyClass, WC_LISTBOXW) == 0)
650c2c66affSColin Finck infoPtr->BuddyType = BUDDY_TYPE_LISTBOX;
651c2c66affSColin Finck }
652c2c66affSColin Finck
653c2c66affSColin Finck if (infoPtr->dwStyle & UDS_ARROWKEYS)
654c2c66affSColin Finck SetWindowSubclass(bud, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID,
655c2c66affSColin Finck (DWORD_PTR)infoPtr->Self);
656c2c66affSColin Finck
657c2c66affSColin Finck /* Get the rect of the buddy relative to its parent */
658c2c66affSColin Finck GetWindowRect(infoPtr->Buddy, &budRect);
659c2c66affSColin Finck MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2);
660c2c66affSColin Finck
661c2c66affSColin Finck /* now do the positioning */
662c2c66affSColin Finck if (infoPtr->dwStyle & UDS_ALIGNLEFT) {
663c2c66affSColin Finck x = budRect.left;
664c2c66affSColin Finck budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP;
665c2c66affSColin Finck } else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) {
666c2c66affSColin Finck budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP;
667c2c66affSColin Finck x = budRect.right+DEFAULT_XSEP;
668c2c66affSColin Finck } else {
669c2c66affSColin Finck /* nothing to do */
670edd99e8cSAmine Khaldi return old_buddy;
671c2c66affSColin Finck }
672c2c66affSColin Finck
673c2c66affSColin Finck /* first adjust the buddy to accommodate the up/down */
674c2c66affSColin Finck SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
675c2c66affSColin Finck budRect.right - budRect.left, budRect.bottom - budRect.top,
676c2c66affSColin Finck SWP_NOACTIVATE|SWP_NOZORDER);
677c2c66affSColin Finck
678c2c66affSColin Finck /* now position the up/down */
679c2c66affSColin Finck /* Since the UDS_ALIGN* flags were used, */
680c2c66affSColin Finck /* we will pick the position and size of the window. */
681c2c66affSColin Finck width = DEFAULT_WIDTH;
682c2c66affSColin Finck
683c2c66affSColin Finck /*
684c2c66affSColin Finck * If the updown has a buddy border, it has to overlap with the buddy
685c2c66affSColin Finck * to look as if it is integrated with the buddy control.
686c2c66affSColin Finck * We nudge the control or change its size to overlap.
687c2c66affSColin Finck */
688c2c66affSColin Finck if (UPDOWN_HasBuddyBorder(infoPtr)) {
689c2c66affSColin Finck if(infoPtr->dwStyle & UDS_ALIGNLEFT)
690c2c66affSColin Finck width += DEFAULT_BUDDYBORDER;
691c2c66affSColin Finck else
692c2c66affSColin Finck x -= DEFAULT_BUDDYBORDER;
693c2c66affSColin Finck }
694c2c66affSColin Finck
695c2c66affSColin Finck SetWindowPos(infoPtr->Self, 0, x,
696c2c66affSColin Finck budRect.top - DEFAULT_ADDTOP, width,
697c2c66affSColin Finck budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT,
698c2c66affSColin Finck SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
699edd99e8cSAmine Khaldi } else if (!(infoPtr->dwStyle & UDS_HORZ) && old_buddy != NULL) {
700c2c66affSColin Finck RECT rect;
701c2c66affSColin Finck GetWindowRect(infoPtr->Self, &rect);
702c2c66affSColin Finck MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2);
703c2c66affSColin Finck SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top,
704c2c66affSColin Finck SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
705c2c66affSColin Finck }
706edd99e8cSAmine Khaldi
707edd99e8cSAmine Khaldi return old_buddy;
708c2c66affSColin Finck }
709c2c66affSColin Finck
710c2c66affSColin Finck /***********************************************************************
711c2c66affSColin Finck * UPDOWN_DoAction
712c2c66affSColin Finck *
713c2c66affSColin Finck * This function increments/decrements the CurVal by the
714c2c66affSColin Finck * 'delta' amount according to the 'action' flag which can be a
715c2c66affSColin Finck * combination of FLAG_INCR and FLAG_DECR
716c2c66affSColin Finck * It notifies the parent as required.
717c2c66affSColin Finck * It handles wrapping and non-wrapping correctly.
718c2c66affSColin Finck * It is assumed that delta>0
719c2c66affSColin Finck */
UPDOWN_DoAction(UPDOWN_INFO * infoPtr,int delta,int action)720c2c66affSColin Finck static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action)
721c2c66affSColin Finck {
722c2c66affSColin Finck NM_UPDOWN ni;
723c2c66affSColin Finck
724c2c66affSColin Finck TRACE("%d by %d\n", action, delta);
725c2c66affSColin Finck
726c2c66affSColin Finck /* check if we can do the modification first */
727c2c66affSColin Finck delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
728c2c66affSColin Finck if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0;
729c2c66affSColin Finck
730c2c66affSColin Finck TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta);
731c2c66affSColin Finck
732c2c66affSColin Finck /* We must notify parent now to obtain permission */
733c2c66affSColin Finck ni.iPos = infoPtr->CurVal;
734c2c66affSColin Finck ni.iDelta = delta;
735c2c66affSColin Finck ni.hdr.hwndFrom = infoPtr->Self;
736c2c66affSColin Finck ni.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
737c2c66affSColin Finck ni.hdr.code = UDN_DELTAPOS;
738c2c66affSColin Finck if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, ni.hdr.idFrom, (LPARAM)&ni)) {
739c2c66affSColin Finck /* Parent said: OK to adjust */
740c2c66affSColin Finck
741c2c66affSColin Finck /* Now adjust value with (maybe new) delta */
742c2c66affSColin Finck if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) {
743c2c66affSColin Finck TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta);
744c2c66affSColin Finck
745c2c66affSColin Finck /* Now take care about our buddy */
746c2c66affSColin Finck UPDOWN_SetBuddyInt (infoPtr);
747c2c66affSColin Finck }
748c2c66affSColin Finck }
749c2c66affSColin Finck
750c2c66affSColin Finck /* Also, notify it. This message is sent in any case. */
751c2c66affSColin Finck SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
752c2c66affSColin Finck MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self);
753c2c66affSColin Finck }
754c2c66affSColin Finck
755c2c66affSColin Finck /***********************************************************************
756c2c66affSColin Finck * UPDOWN_IsEnabled
757c2c66affSColin Finck *
758c2c66affSColin Finck * Returns TRUE if it is enabled as well as its buddy (if any)
759c2c66affSColin Finck * FALSE otherwise
760c2c66affSColin Finck */
UPDOWN_IsEnabled(const UPDOWN_INFO * infoPtr)761c2c66affSColin Finck static BOOL UPDOWN_IsEnabled (const UPDOWN_INFO *infoPtr)
762c2c66affSColin Finck {
763c2c66affSColin Finck if (!IsWindowEnabled(infoPtr->Self))
764c2c66affSColin Finck return FALSE;
765c2c66affSColin Finck if(infoPtr->Buddy)
766c2c66affSColin Finck return IsWindowEnabled(infoPtr->Buddy);
767c2c66affSColin Finck return TRUE;
768c2c66affSColin Finck }
769c2c66affSColin Finck
770c2c66affSColin Finck /***********************************************************************
771c2c66affSColin Finck * UPDOWN_CancelMode
772c2c66affSColin Finck *
773c2c66affSColin Finck * Deletes any timers, releases the mouse and does redraw if necessary.
774c2c66affSColin Finck * If the control is not in "capture" mode, it does nothing.
775c2c66affSColin Finck * If the control was not in cancel mode, it returns FALSE.
776c2c66affSColin Finck * If the control was in cancel mode, it returns TRUE.
777c2c66affSColin Finck */
UPDOWN_CancelMode(UPDOWN_INFO * infoPtr)778c2c66affSColin Finck static BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr)
779c2c66affSColin Finck {
780c2c66affSColin Finck if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE;
781c2c66affSColin Finck
782c2c66affSColin Finck KillTimer (infoPtr->Self, TIMER_AUTOREPEAT);
783c2c66affSColin Finck KillTimer (infoPtr->Self, TIMER_ACCEL);
784c2c66affSColin Finck KillTimer (infoPtr->Self, TIMER_AUTOPRESS);
785c2c66affSColin Finck
786841732e4SJoachim Henze if (GetCapture() == infoPtr->Self)
787c2c66affSColin Finck ReleaseCapture();
788c2c66affSColin Finck
789c2c66affSColin Finck infoPtr->Flags &= ~FLAG_PRESSED;
790c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
791c2c66affSColin Finck
792c2c66affSColin Finck return TRUE;
793c2c66affSColin Finck }
794c2c66affSColin Finck
795c2c66affSColin Finck /***********************************************************************
796c2c66affSColin Finck * UPDOWN_HandleMouseEvent
797c2c66affSColin Finck *
798c2c66affSColin Finck * Handle a mouse event for the updown.
799c2c66affSColin Finck * 'pt' is the location of the mouse event in client or
800c2c66affSColin Finck * windows coordinates.
801c2c66affSColin Finck */
UPDOWN_HandleMouseEvent(UPDOWN_INFO * infoPtr,UINT msg,INT x,INT y)802c2c66affSColin Finck static void UPDOWN_HandleMouseEvent (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y)
803c2c66affSColin Finck {
804c2c66affSColin Finck POINT pt = { x, y };
805c2c66affSColin Finck RECT rect;
806c2c66affSColin Finck int temp, arrow;
807c2c66affSColin Finck TRACKMOUSEEVENT tme;
808c2c66affSColin Finck
809c2c66affSColin Finck TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt));
810c2c66affSColin Finck
811c2c66affSColin Finck switch(msg)
812c2c66affSColin Finck {
813c2c66affSColin Finck case WM_LBUTTONDOWN: /* Initialise mouse tracking */
814c2c66affSColin Finck
815c2c66affSColin Finck /* If the buddy is an edit, will set focus to it */
816c2c66affSColin Finck if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy);
817c2c66affSColin Finck
818c2c66affSColin Finck /* Now see which one is the 'active' arrow */
819c2c66affSColin Finck arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
820c2c66affSColin Finck
821c2c66affSColin Finck /* Update the flags if we are in/out */
822c2c66affSColin Finck infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
823c2c66affSColin Finck if (arrow)
824c2c66affSColin Finck infoPtr->Flags |= FLAG_MOUSEIN | arrow;
825c2c66affSColin Finck else
826c2c66affSColin Finck if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
827c2c66affSColin Finck
828c2c66affSColin Finck if (infoPtr->Flags & FLAG_ARROW) {
829c2c66affSColin Finck
830c2c66affSColin Finck /* Update the CurVal if necessary */
831c2c66affSColin Finck UPDOWN_GetBuddyInt (infoPtr);
832c2c66affSColin Finck
833c2c66affSColin Finck /* Set up the correct flags */
834c2c66affSColin Finck infoPtr->Flags |= FLAG_PRESSED;
835c2c66affSColin Finck
836c2c66affSColin Finck /* repaint the control */
837c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
838c2c66affSColin Finck
839c2c66affSColin Finck /* process the click */
840c2c66affSColin Finck temp = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1;
841c2c66affSColin Finck UPDOWN_DoAction (infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
842c2c66affSColin Finck
843c2c66affSColin Finck /* now capture all mouse messages */
844c2c66affSColin Finck SetCapture (infoPtr->Self);
845c2c66affSColin Finck
846c2c66affSColin Finck /* and startup the first timer */
847c2c66affSColin Finck SetTimer(infoPtr->Self, TIMER_AUTOREPEAT, INITIAL_DELAY, 0);
848c2c66affSColin Finck }
849c2c66affSColin Finck break;
850c2c66affSColin Finck
851c2c66affSColin Finck case WM_MOUSEMOVE:
852c2c66affSColin Finck /* save the flags to see if any got modified */
853c2c66affSColin Finck temp = infoPtr->Flags;
854c2c66affSColin Finck
855c2c66affSColin Finck /* Now see which one is the 'active' arrow */
856c2c66affSColin Finck arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
857c2c66affSColin Finck
858c2c66affSColin Finck /* Update the flags if we are in/out */
859c2c66affSColin Finck infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
860c2c66affSColin Finck if(arrow) {
861c2c66affSColin Finck infoPtr->Flags |= FLAG_MOUSEIN | arrow;
862c2c66affSColin Finck } else {
863c2c66affSColin Finck if(infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
864c2c66affSColin Finck }
865c2c66affSColin Finck
866c2c66affSColin Finck /* If state changed, redraw the control */
867c2c66affSColin Finck if(temp != infoPtr->Flags)
868c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
869c2c66affSColin Finck
870c2c66affSColin Finck /* Set up tracking so the mousein flags can be reset when the
871c2c66affSColin Finck * mouse leaves the control */
872c2c66affSColin Finck tme.cbSize = sizeof( tme );
873c2c66affSColin Finck tme.dwFlags = TME_LEAVE;
874c2c66affSColin Finck tme.hwndTrack = infoPtr->Self;
875c2c66affSColin Finck TrackMouseEvent (&tme);
876c2c66affSColin Finck
877c2c66affSColin Finck break;
878c2c66affSColin Finck case WM_MOUSELEAVE:
879c2c66affSColin Finck infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
880c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
881c2c66affSColin Finck break;
882c2c66affSColin Finck
883c2c66affSColin Finck default:
884c2c66affSColin Finck ERR("Impossible case (msg=%x)!\n", msg);
885c2c66affSColin Finck }
886c2c66affSColin Finck
887c2c66affSColin Finck }
888c2c66affSColin Finck
889c2c66affSColin Finck /***********************************************************************
890c2c66affSColin Finck * UpDownWndProc
891c2c66affSColin Finck */
UpDownWindowProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)892c2c66affSColin Finck static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
893c2c66affSColin Finck {
894c2c66affSColin Finck UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
895c2c66affSColin Finck static const WCHAR themeClass[] = {'S','p','i','n',0};
896c2c66affSColin Finck HTHEME theme;
897c2c66affSColin Finck
898c2c66affSColin Finck TRACE("hwnd=%p msg=%04x wparam=%08lx lparam=%08lx\n", hwnd, message, wParam, lParam);
899c2c66affSColin Finck
900c2c66affSColin Finck if (!infoPtr && (message != WM_CREATE))
901c2c66affSColin Finck return DefWindowProcW (hwnd, message, wParam, lParam);
902c2c66affSColin Finck
903c2c66affSColin Finck switch(message)
904c2c66affSColin Finck {
905c2c66affSColin Finck case WM_CREATE:
906c2c66affSColin Finck {
907c2c66affSColin Finck CREATESTRUCTW *pcs = (CREATESTRUCTW*)lParam;
908c2c66affSColin Finck
909b3fb8555SGiannis Adamopoulos infoPtr = heap_alloc_zero(sizeof(*infoPtr));
910c2c66affSColin Finck SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
911c2c66affSColin Finck
912c2c66affSColin Finck /* initialize the info struct */
913c2c66affSColin Finck infoPtr->Self = hwnd;
914c2c66affSColin Finck infoPtr->Notify = pcs->hwndParent;
915c2c66affSColin Finck infoPtr->dwStyle = pcs->style;
916c2c66affSColin Finck infoPtr->AccelCount = 0;
917c2c66affSColin Finck infoPtr->AccelVect = 0;
918c2c66affSColin Finck infoPtr->AccelIndex = -1;
919c2c66affSColin Finck infoPtr->CurVal = 0;
920c2c66affSColin Finck infoPtr->MinVal = 100;
921c2c66affSColin Finck infoPtr->MaxVal = 0;
922c2c66affSColin Finck infoPtr->Base = 10; /* Default to base 10 */
923c2c66affSColin Finck infoPtr->Buddy = 0; /* No buddy window yet */
924c2c66affSColin Finck infoPtr->Flags = (infoPtr->dwStyle & UDS_SETBUDDYINT) ? FLAG_BUDDYINT : 0;
925c2c66affSColin Finck
926c2c66affSColin Finck SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle & ~WS_BORDER);
927c2c66affSColin Finck if (!(infoPtr->dwStyle & UDS_HORZ))
928c2c66affSColin Finck SetWindowPos (hwnd, NULL, 0, 0, DEFAULT_WIDTH, pcs->cy,
929c2c66affSColin Finck SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
930c2c66affSColin Finck
931c2c66affSColin Finck /* Do we pick the buddy win ourselves? */
932c2c66affSColin Finck if (infoPtr->dwStyle & UDS_AUTOBUDDY)
933c2c66affSColin Finck UPDOWN_SetBuddy (infoPtr, GetWindow (hwnd, GW_HWNDPREV));
934c2c66affSColin Finck
935c2c66affSColin Finck OpenThemeData (hwnd, themeClass);
936c2c66affSColin Finck
937c2c66affSColin Finck TRACE("UpDown Ctrl creation, hwnd=%p\n", hwnd);
938c2c66affSColin Finck }
939c2c66affSColin Finck break;
940c2c66affSColin Finck
941c2c66affSColin Finck case WM_DESTROY:
942b3fb8555SGiannis Adamopoulos heap_free (infoPtr->AccelVect);
943b3fb8555SGiannis Adamopoulos UPDOWN_ResetSubclass (infoPtr);
944b3fb8555SGiannis Adamopoulos heap_free (infoPtr);
945c2c66affSColin Finck SetWindowLongPtrW (hwnd, 0, 0);
946c2c66affSColin Finck theme = GetWindowTheme (hwnd);
947c2c66affSColin Finck CloseThemeData (theme);
948c2c66affSColin Finck TRACE("UpDown Ctrl destruction, hwnd=%p\n", hwnd);
949c2c66affSColin Finck break;
950c2c66affSColin Finck
951c2c66affSColin Finck case WM_ENABLE:
952c2c66affSColin Finck if (wParam) {
953c2c66affSColin Finck infoPtr->dwStyle &= ~WS_DISABLED;
954c2c66affSColin Finck } else {
955c2c66affSColin Finck infoPtr->dwStyle |= WS_DISABLED;
956c2c66affSColin Finck UPDOWN_CancelMode (infoPtr);
957c2c66affSColin Finck }
958c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
959c2c66affSColin Finck break;
960c2c66affSColin Finck
961c2c66affSColin Finck case WM_STYLECHANGED:
962c2c66affSColin Finck if (wParam == GWL_STYLE) {
963c2c66affSColin Finck infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew;
964c2c66affSColin Finck InvalidateRect (infoPtr->Self, NULL, FALSE);
965c2c66affSColin Finck }
966c2c66affSColin Finck break;
967c2c66affSColin Finck
968c2c66affSColin Finck case WM_THEMECHANGED:
969c2c66affSColin Finck theme = GetWindowTheme (hwnd);
970c2c66affSColin Finck CloseThemeData (theme);
971c2c66affSColin Finck OpenThemeData (hwnd, themeClass);
972c2c66affSColin Finck InvalidateRect (hwnd, NULL, FALSE);
973c2c66affSColin Finck break;
974c2c66affSColin Finck
975c2c66affSColin Finck case WM_TIMER:
976c2c66affSColin Finck /* is this the auto-press timer? */
977c2c66affSColin Finck if(wParam == TIMER_AUTOPRESS) {
978c2c66affSColin Finck KillTimer(hwnd, TIMER_AUTOPRESS);
979c2c66affSColin Finck infoPtr->Flags &= ~(FLAG_PRESSED | FLAG_ARROW);
980c2c66affSColin Finck InvalidateRect(infoPtr->Self, NULL, FALSE);
981c2c66affSColin Finck }
982c2c66affSColin Finck
983c2c66affSColin Finck /* if initial timer, kill it and start the repeat timer */
984c2c66affSColin Finck if(wParam == TIMER_AUTOREPEAT) {
985c2c66affSColin Finck INT delay;
986c2c66affSColin Finck
987c2c66affSColin Finck KillTimer(hwnd, TIMER_AUTOREPEAT);
988c2c66affSColin Finck /* if no accel info given, used default timer */
989c2c66affSColin Finck if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0) {
990c2c66affSColin Finck infoPtr->AccelIndex = -1;
991c2c66affSColin Finck delay = REPEAT_DELAY;
992c2c66affSColin Finck } else {
993c2c66affSColin Finck infoPtr->AccelIndex = 0; /* otherwise, use it */
994c2c66affSColin Finck delay = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
995c2c66affSColin Finck }
996c2c66affSColin Finck SetTimer(hwnd, TIMER_ACCEL, delay, 0);
997c2c66affSColin Finck }
998c2c66affSColin Finck
999c2c66affSColin Finck /* now, if the mouse is above us, do the thing...*/
1000c2c66affSColin Finck if(infoPtr->Flags & FLAG_MOUSEIN) {
1001c2c66affSColin Finck int temp;
1002c2c66affSColin Finck
1003c2c66affSColin Finck temp = infoPtr->AccelIndex == -1 ? 1 : infoPtr->AccelVect[infoPtr->AccelIndex].nInc;
1004c2c66affSColin Finck UPDOWN_DoAction(infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
1005c2c66affSColin Finck
1006c2c66affSColin Finck if(infoPtr->AccelIndex != -1 && infoPtr->AccelIndex < infoPtr->AccelCount-1) {
1007c2c66affSColin Finck KillTimer(hwnd, TIMER_ACCEL);
1008c2c66affSColin Finck infoPtr->AccelIndex++; /* move to the next accel info */
1009c2c66affSColin Finck temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
1010c2c66affSColin Finck /* make sure we have at least 1ms intervals */
1011c2c66affSColin Finck SetTimer(hwnd, TIMER_ACCEL, temp, 0);
1012c2c66affSColin Finck }
1013c2c66affSColin Finck }
1014c2c66affSColin Finck break;
1015c2c66affSColin Finck
1016c2c66affSColin Finck case WM_CANCELMODE:
1017c2c66affSColin Finck return UPDOWN_CancelMode (infoPtr);
1018c2c66affSColin Finck
1019c2c66affSColin Finck case WM_LBUTTONUP:
1020c2c66affSColin Finck if (GetCapture() != infoPtr->Self) break;
1021c2c66affSColin Finck
1022c2c66affSColin Finck if ( (infoPtr->Flags & FLAG_MOUSEIN) &&
1023c2c66affSColin Finck (infoPtr->Flags & FLAG_ARROW) ) {
1024c2c66affSColin Finck
1025c2c66affSColin Finck SendMessageW( infoPtr->Notify,
1026c2c66affSColin Finck (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
1027c2c66affSColin Finck MAKELONG(SB_ENDSCROLL, infoPtr->CurVal),
1028c2c66affSColin Finck (LPARAM)hwnd);
1029c2c66affSColin Finck if (UPDOWN_IsBuddyEdit(infoPtr))
1030c2c66affSColin Finck SendMessageW(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1));
1031c2c66affSColin Finck }
1032c2c66affSColin Finck UPDOWN_CancelMode(infoPtr);
1033c2c66affSColin Finck break;
1034c2c66affSColin Finck
1035c2c66affSColin Finck case WM_LBUTTONDOWN:
1036c2c66affSColin Finck case WM_MOUSEMOVE:
1037c2c66affSColin Finck case WM_MOUSELEAVE:
1038c2c66affSColin Finck if(UPDOWN_IsEnabled(infoPtr))
1039c2c66affSColin Finck UPDOWN_HandleMouseEvent (infoPtr, message, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
1040c2c66affSColin Finck break;
1041c2c66affSColin Finck
1042c2c66affSColin Finck case WM_MOUSEWHEEL:
1043c2c66affSColin Finck UPDOWN_MouseWheel(infoPtr, wParam);
1044c2c66affSColin Finck break;
1045c2c66affSColin Finck
1046c2c66affSColin Finck case WM_KEYDOWN:
1047c2c66affSColin Finck if((infoPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(infoPtr))
1048c2c66affSColin Finck return UPDOWN_KeyPressed(infoPtr, (int)wParam);
1049c2c66affSColin Finck break;
1050c2c66affSColin Finck
1051c2c66affSColin Finck case WM_PRINTCLIENT:
1052c2c66affSColin Finck case WM_PAINT:
1053c2c66affSColin Finck return UPDOWN_Paint (infoPtr, (HDC)wParam);
1054c2c66affSColin Finck
1055c2c66affSColin Finck case UDM_GETACCEL:
1056c2c66affSColin Finck if (wParam==0 && lParam==0) return infoPtr->AccelCount;
1057c2c66affSColin Finck if (wParam && lParam) {
1058c2c66affSColin Finck int temp = min(infoPtr->AccelCount, wParam);
1059c2c66affSColin Finck memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL));
1060c2c66affSColin Finck return temp;
1061c2c66affSColin Finck }
1062c2c66affSColin Finck return 0;
1063c2c66affSColin Finck
1064c2c66affSColin Finck case UDM_SETACCEL:
1065c2c66affSColin Finck {
1066c2c66affSColin Finck TRACE("UDM_SETACCEL\n");
1067c2c66affSColin Finck
1068c2c66affSColin Finck if(infoPtr->AccelVect) {
1069b3fb8555SGiannis Adamopoulos heap_free (infoPtr->AccelVect);
1070c2c66affSColin Finck infoPtr->AccelCount = 0;
1071c2c66affSColin Finck infoPtr->AccelVect = 0;
1072c2c66affSColin Finck }
1073c2c66affSColin Finck if(wParam==0) return TRUE;
1074b3fb8555SGiannis Adamopoulos infoPtr->AccelVect = heap_alloc(wParam*sizeof(UDACCEL));
1075b3fb8555SGiannis Adamopoulos if(!infoPtr->AccelVect) return FALSE;
1076c2c66affSColin Finck memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL));
1077c2c66affSColin Finck infoPtr->AccelCount = wParam;
1078c2c66affSColin Finck
1079c2c66affSColin Finck if (TRACE_ON(updown))
1080c2c66affSColin Finck {
1081c2c66affSColin Finck UINT i;
1082c2c66affSColin Finck
1083c2c66affSColin Finck for (i = 0; i < wParam; i++)
1084c2c66affSColin Finck TRACE("%u: nSec %u nInc %u\n", i,
1085c2c66affSColin Finck infoPtr->AccelVect[i].nSec, infoPtr->AccelVect[i].nInc);
1086c2c66affSColin Finck }
1087c2c66affSColin Finck
1088c2c66affSColin Finck return TRUE;
1089c2c66affSColin Finck }
1090c2c66affSColin Finck case UDM_GETBASE:
1091c2c66affSColin Finck return infoPtr->Base;
1092c2c66affSColin Finck
1093c2c66affSColin Finck case UDM_SETBASE:
1094c2c66affSColin Finck TRACE("UpDown Ctrl new base(%ld), hwnd=%p\n", wParam, hwnd);
1095c2c66affSColin Finck if (wParam==10 || wParam==16) {
1096c2c66affSColin Finck WPARAM old_base = infoPtr->Base;
1097c2c66affSColin Finck infoPtr->Base = wParam;
1098c2c66affSColin Finck
1099c2c66affSColin Finck if (old_base != infoPtr->Base)
1100c2c66affSColin Finck UPDOWN_SetBuddyInt(infoPtr);
1101c2c66affSColin Finck
1102c2c66affSColin Finck return old_base;
1103c2c66affSColin Finck }
1104c2c66affSColin Finck break;
1105c2c66affSColin Finck
1106c2c66affSColin Finck case UDM_GETBUDDY:
1107c2c66affSColin Finck return (LRESULT)infoPtr->Buddy;
1108c2c66affSColin Finck
1109c2c66affSColin Finck case UDM_SETBUDDY:
1110c2c66affSColin Finck return (LRESULT)UPDOWN_SetBuddy (infoPtr, (HWND)wParam);
1111c2c66affSColin Finck
1112c2c66affSColin Finck case UDM_GETPOS:
1113c2c66affSColin Finck {
1114c2c66affSColin Finck BOOL err;
1115c2c66affSColin Finck int pos;
1116c2c66affSColin Finck
1117c2c66affSColin Finck pos = UPDOWN_GetPos(infoPtr, &err);
1118c2c66affSColin Finck return MAKELONG(pos, err);
1119c2c66affSColin Finck }
1120c2c66affSColin Finck case UDM_SETPOS:
1121c2c66affSColin Finck {
1122c2c66affSColin Finck return UPDOWN_SetPos(infoPtr, (short)LOWORD(lParam));
1123c2c66affSColin Finck }
1124c2c66affSColin Finck case UDM_GETRANGE:
1125c2c66affSColin Finck return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal);
1126c2c66affSColin Finck
1127c2c66affSColin Finck case UDM_SETRANGE:
1128c2c66affSColin Finck /* we must have:
1129c2c66affSColin Finck UD_MINVAL <= Max <= UD_MAXVAL
1130c2c66affSColin Finck UD_MINVAL <= Min <= UD_MAXVAL
1131c2c66affSColin Finck |Max-Min| <= UD_MAXVAL */
1132c2c66affSColin Finck UPDOWN_SetRange(infoPtr, (short)lParam, (short)HIWORD(lParam));
1133c2c66affSColin Finck break;
1134c2c66affSColin Finck
1135c2c66affSColin Finck case UDM_GETRANGE32:
1136c2c66affSColin Finck if (wParam) *(LPINT)wParam = infoPtr->MinVal;
1137c2c66affSColin Finck if (lParam) *(LPINT)lParam = infoPtr->MaxVal;
1138c2c66affSColin Finck break;
1139c2c66affSColin Finck
1140c2c66affSColin Finck case UDM_SETRANGE32:
1141c2c66affSColin Finck UPDOWN_SetRange(infoPtr, (INT)lParam, (INT)wParam);
1142c2c66affSColin Finck break;
1143c2c66affSColin Finck
1144c2c66affSColin Finck case UDM_GETPOS32:
1145c2c66affSColin Finck {
1146c2c66affSColin Finck return UPDOWN_GetPos(infoPtr, (BOOL*)lParam);
1147c2c66affSColin Finck }
1148c2c66affSColin Finck case UDM_SETPOS32:
1149c2c66affSColin Finck {
1150c2c66affSColin Finck return UPDOWN_SetPos(infoPtr, (int)lParam);
1151c2c66affSColin Finck }
1152c2c66affSColin Finck case UDM_GETUNICODEFORMAT:
1153c2c66affSColin Finck /* we lie a bit here, we're always using Unicode internally */
1154c2c66affSColin Finck return infoPtr->UnicodeFormat;
1155c2c66affSColin Finck
1156c2c66affSColin Finck case UDM_SETUNICODEFORMAT:
1157c2c66affSColin Finck {
1158c2c66affSColin Finck /* do we really need to honour this flag? */
1159c2c66affSColin Finck int temp = infoPtr->UnicodeFormat;
1160c2c66affSColin Finck infoPtr->UnicodeFormat = (BOOL)wParam;
1161c2c66affSColin Finck return temp;
1162c2c66affSColin Finck }
1163c2c66affSColin Finck default:
1164c2c66affSColin Finck if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
1165c2c66affSColin Finck ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam);
1166c2c66affSColin Finck return DefWindowProcW (hwnd, message, wParam, lParam);
1167c2c66affSColin Finck }
1168c2c66affSColin Finck
1169c2c66affSColin Finck return 0;
1170c2c66affSColin Finck }
1171c2c66affSColin Finck
1172c2c66affSColin Finck /***********************************************************************
1173c2c66affSColin Finck * UPDOWN_Register [Internal]
1174c2c66affSColin Finck *
1175c2c66affSColin Finck * Registers the updown window class.
1176c2c66affSColin Finck */
UPDOWN_Register(void)1177c2c66affSColin Finck void UPDOWN_Register(void)
1178c2c66affSColin Finck {
1179c2c66affSColin Finck WNDCLASSW wndClass;
1180c2c66affSColin Finck
1181c2c66affSColin Finck ZeroMemory( &wndClass, sizeof( WNDCLASSW ) );
1182c2c66affSColin Finck wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
1183c2c66affSColin Finck wndClass.lpfnWndProc = UpDownWindowProc;
1184c2c66affSColin Finck wndClass.cbClsExtra = 0;
1185c2c66affSColin Finck wndClass.cbWndExtra = sizeof(UPDOWN_INFO*);
1186c2c66affSColin Finck wndClass.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW );
1187c2c66affSColin Finck wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1188c2c66affSColin Finck wndClass.lpszClassName = UPDOWN_CLASSW;
1189c2c66affSColin Finck
1190c2c66affSColin Finck RegisterClassW( &wndClass );
1191c2c66affSColin Finck }
1192c2c66affSColin Finck
1193c2c66affSColin Finck
1194c2c66affSColin Finck /***********************************************************************
1195c2c66affSColin Finck * UPDOWN_Unregister [Internal]
1196c2c66affSColin Finck *
1197c2c66affSColin Finck * Unregisters the updown window class.
1198c2c66affSColin Finck */
UPDOWN_Unregister(void)1199c2c66affSColin Finck void UPDOWN_Unregister (void)
1200c2c66affSColin Finck {
1201c2c66affSColin Finck UnregisterClassW (UPDOWN_CLASSW, NULL);
1202c2c66affSColin Finck }
1203