-/*
+/*
* Updown control
*
- * Copyright 1997 Dimitrie O. Paun
+ * Copyright 1997, 2002 Dimitrie O. Paun
*
- * TODO:
- * - I think I do not handle correctly the WS_BORDER style.
- * (Should be fixed. <ekohl@abo.rhein-zeitung.de>)
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
- * Testing:
- * Not much. The following have not been tested at all:
- * - horizontal arrows
- * - listbox as buddy window
- * - acceleration
- * - base 16
- * - integers with thousand separators.
- * (fixed bugs. <noel@macadamian.com>)
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * Even though the above list seems rather large, the control seems to
- * behave very well so I am confident it does work in most (all) of the
- * untested cases.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ * NOTE
+ *
+ * This code was audited for completeness against the documented features
+ * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
+ *
+ * Unless otherwise noted, we believe this code to be complete, as per
+ * the specification mentioned above.
+ * If you discover missing features, or bugs, please note them below.
+ *
*/
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include <stdio.h>
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
-#include "commctrl.h"
#include "winnls.h"
-#include "debugtools.h"
-
-DEFAULT_DEBUG_CHANNEL(updown);
+#include "commctrl.h"
+#include "comctl32.h"
+#include "uxtheme.h"
+#include "tmschema.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
-#define UPDOWN_BUDDYCLASSNAMELEN 40
+WINE_DEFAULT_DEBUG_CHANNEL(updown);
typedef struct
{
- UINT AccelCount; /* Number of elements in AccelVect */
- UDACCEL* AccelVect; /* Vector containing AccelCount elements */
- INT Base; /* Base to display nr in the buddy window */
- INT CurVal; /* Current up-down value */
- INT MinVal; /* Minimum up-down value */
- INT MaxVal; /* Maximum up-down value */
- HWND Buddy; /* Handle to the buddy window */
- CHAR szBuddyClass[UPDOWN_BUDDYCLASSNAMELEN]; /* Buddy window class name */
- INT Flags; /* Internal Flags FLAG_* */
+ HWND Self; /* Handle to this up-down control */
+ HWND Notify; /* Handle to the parent window */
+ DWORD dwStyle; /* The GWL_STYLE for this window */
+ UINT AccelCount; /* Number of elements in AccelVect */
+ UDACCEL* AccelVect; /* Vector containing AccelCount elements */
+ INT AccelIndex; /* Current accel index, -1 if not accel'ing */
+ INT Base; /* Base to display nr in the buddy window */
+ INT CurVal; /* Current up-down value */
+ INT MinVal; /* Minimum up-down value */
+ INT MaxVal; /* Maximum up-down value */
+ HWND Buddy; /* Handle to the buddy window */
+ INT BuddyType; /* Remembers the buddy type BUDDY_TYPE_* */
+ INT Flags; /* Internal Flags FLAG_* */
+ BOOL UnicodeFormat; /* Marks the use of Unicode internally */
} UPDOWN_INFO;
/* Control configuration constants */
-#define INITIAL_DELAY 500 /* initial timer until auto-increment kicks in */
-#define REPEAT_DELAY 50 /* delay between auto-increments */
-
-#define DEFAULT_WIDTH 14 /* default width of the ctrl */
-#define DEFAULT_XSEP 0 /* default separation between buddy and crtl */
-#define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */
-#define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */
-#define DEFAULT_BUDDYBORDER 2 /* Width/height of the buddy border */
+#define INITIAL_DELAY 500 /* initial timer until auto-inc kicks in */
+#define AUTOPRESS_DELAY 250 /* time to keep arrow pressed on KEY_DOWN */
+#define REPEAT_DELAY 50 /* delay between auto-increments */
+#define DEFAULT_WIDTH 14 /* default width of the ctrl */
+#define DEFAULT_XSEP 0 /* default separation between buddy and ctrl */
+#define DEFAULT_ADDTOP 0 /* amount to extend above the buddy window */
+#define DEFAULT_ADDBOT 0 /* amount to extend below the buddy window */
+#define DEFAULT_BUDDYBORDER 2 /* Width/height of the buddy border */
+#define DEFAULT_BUDDYSPACER 2 /* Spacer between the buddy and the ctrl */
+#define DEFAULT_BUDDYBORDER_THEMED 1 /* buddy border when theming is enabled */
+#define DEFAULT_BUDDYSPACER_THEMED 0 /* buddy spacer when theming is enabled */
/* Work constants */
-#define FLAG_INCR 0x01
-#define FLAG_DECR 0x02
-#define FLAG_MOUSEIN 0x04
-#define FLAG_CLICKED (FLAG_INCR | FLAG_DECR)
+#define FLAG_INCR 0x01
+#define FLAG_DECR 0x02
+#define FLAG_MOUSEIN 0x04
+#define FLAG_PRESSED 0x08
+#define FLAG_ARROW (FLAG_INCR | FLAG_DECR)
-#define TIMERID1 1
-#define TIMERID2 2
-#define BUDDY_UPDOWN_HWND "buddyUpDownHWND"
-#define BUDDY_SUPERCLASS_WNDPROC "buddySupperClassWndProc"
+#define BUDDY_TYPE_UNKNOWN 0
+#define BUDDY_TYPE_LISTBOX 1
+#define BUDDY_TYPE_EDIT 2
-static int accelIndex = -1;
+#define TIMER_AUTOREPEAT 1
+#define TIMER_ACCEL 2
+#define TIMER_AUTOPRESS 3
-#define UNKNOWN_PARAM(msg, wParam, lParam) WARN(\
- "Unknown parameter(s) for message " #msg \
- "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam);
+#define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongPtrW (hwnd,0))
+#define COUNT_OF(a) (sizeof(a)/sizeof(a[0]))
-#define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongA (hwnd,0))
+static const WCHAR BUDDY_UPDOWN_HWND[] = { 'b', 'u', 'd', 'd', 'y', 'U', 'p', 'D', 'o', 'w', 'n', 'H', 'W', 'N', 'D', 0 };
+static const WCHAR BUDDY_SUPERCLASS_WNDPROC[] = { 'b', 'u', 'd', 'd', 'y', 'S', 'u', 'p', 'p', 'e', 'r',
+ 'C', 'l', 'a', 's', 's', 'W', 'n', 'd', 'P', 'r', 'o', 'c', 0 };
+static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action);
-static LRESULT CALLBACK
-UPDOWN_Buddy_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+/***********************************************************************
+ * UPDOWN_IsBuddyEdit
+ * Tests if our buddy is an edit control.
+ */
+static inline BOOL UPDOWN_IsBuddyEdit(const UPDOWN_INFO *infoPtr)
+{
+ return infoPtr->BuddyType == BUDDY_TYPE_EDIT;
+}
+
+/***********************************************************************
+ * UPDOWN_IsBuddyListbox
+ * Tests if our buddy is a listbox control.
+ */
+static inline BOOL UPDOWN_IsBuddyListbox(const UPDOWN_INFO *infoPtr)
+{
+ return infoPtr->BuddyType == BUDDY_TYPE_LISTBOX;
+}
/***********************************************************************
* UPDOWN_InBounds
* Tests if a given value 'val' is between the Min&Max limits
*/
-static BOOL UPDOWN_InBounds(HWND hwnd, int val)
+static BOOL UPDOWN_InBounds(const UPDOWN_INFO *infoPtr, int val)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
-
- if(infoPtr->MaxVal > infoPtr->MinVal)
- return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal);
- else
- return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal);
+ if(infoPtr->MaxVal > infoPtr->MinVal)
+ return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal);
+ else
+ return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal);
}
/***********************************************************************
* UPDOWN_OffsetVal
- * Tests if we can change the current value by delta. If so, it changes
- * it and returns TRUE. Else, it leaves it unchanged and returns FALSE.
+ * Change the current value by delta.
+ * It returns TRUE is the value was changed successfully, or FALSE
+ * if the value was not changed, as it would go out of bounds.
*/
-static BOOL UPDOWN_OffsetVal(HWND hwnd, int delta)
+static BOOL UPDOWN_OffsetVal(UPDOWN_INFO *infoPtr, int delta)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
-
- /* check if we can do the modification first */
- if(!UPDOWN_InBounds (hwnd, infoPtr->CurVal+delta)){
- if (GetWindowLongA (hwnd, GWL_STYLE) & UDS_WRAP)
- {
- delta += (delta < 0 ? -1 : 1) *
- (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) *
- (infoPtr->MinVal - infoPtr->MaxVal) +
- (delta < 0 ? 1 : -1);
+ /* check if we can do the modification first */
+ if(!UPDOWN_InBounds (infoPtr, infoPtr->CurVal+delta)) {
+ if (infoPtr->dwStyle & UDS_WRAP) {
+ delta += (delta < 0 ? -1 : 1) *
+ (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) *
+ (infoPtr->MinVal - infoPtr->MaxVal) +
+ (delta < 0 ? 1 : -1);
+ } else return FALSE;
}
- else
- return FALSE;
- }
- infoPtr->CurVal += delta;
- return TRUE;
+ infoPtr->CurVal += delta;
+ return TRUE;
}
/***********************************************************************
- * UPDOWN_HasBuddyBorder [Internal]
+ * UPDOWN_HasBuddyBorder
*
* When we have a buddy set and that we are aligned on our buddy, we
* want to draw a sunken edge to make like we are part of that control.
*/
-static BOOL UPDOWN_HasBuddyBorder(HWND hwnd)
-{
- UPDOWN_INFO* infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
-
- return ( ((dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) &&
- (SendMessageA(hwnd, UDM_GETBUDDY, 0, 0) != 0) &&
- (lstrcmpiA(infoPtr->szBuddyClass, "EDIT") == 0 ) );
+static BOOL UPDOWN_HasBuddyBorder(const UPDOWN_INFO *infoPtr)
+{
+ return ( ((infoPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) &&
+ UPDOWN_IsBuddyEdit(infoPtr) );
}
/***********************************************************************
* UPDOWN_GetArrowRect
* wndPtr - pointer to the up-down wnd
* rect - will hold the rectangle
- * incr - TRUE get the "increment" rect (up or right)
- * FALSE get the "decrement" rect (down or left)
- *
+ * arrow - FLAG_INCR to get the "increment" rect (up or right)
+ * FLAG_DECR to get the "decrement" rect (down or left)
+ * If both flags are present, the envelope is returned.
*/
-static void UPDOWN_GetArrowRect (HWND hwnd, RECT *rect, BOOL incr)
+static void UPDOWN_GetArrowRect (const UPDOWN_INFO* infoPtr, RECT *rect, int arrow)
{
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- int len; /* will hold the width or height */
-
- GetClientRect (hwnd, rect);
-
- /*
- * Make sure we calculate the rectangle to fit even if we draw the
- * border.
- */
- if (UPDOWN_HasBuddyBorder(hwnd))
- {
- if (dwStyle & UDS_ALIGNLEFT)
- rect->left+=DEFAULT_BUDDYBORDER;
- else
- rect->right-=DEFAULT_BUDDYBORDER;
-
- InflateRect(rect, 0, -DEFAULT_BUDDYBORDER);
- }
-
- /*
- * We're calculating the midpoint to figure-out where the
- * separation between the buttons will lay. We make sure that we
- * round the uneven numbers by adding 1.
- */
- if (dwStyle & UDS_HORZ) {
- len = rect->right - rect->left + 1; /* compute the width */
- if (incr)
- rect->left = rect->left + len/2;
- else
- rect->right = rect->left + len/2;
- }
- else {
- len = rect->bottom - rect->top + 1; /* compute the height */
- if (incr)
- rect->bottom = rect->top + len/2;
- else
- rect->top = rect->top + len/2;
- }
+ HTHEME theme = GetWindowTheme (infoPtr->Self);
+ const int border = theme ? DEFAULT_BUDDYBORDER_THEMED : DEFAULT_BUDDYBORDER;
+ const int spacer = theme ? DEFAULT_BUDDYSPACER_THEMED : DEFAULT_BUDDYSPACER;
+ GetClientRect (infoPtr->Self, rect);
+
+ /*
+ * Make sure we calculate the rectangle to fit even if we draw the
+ * border.
+ */
+ if (UPDOWN_HasBuddyBorder(infoPtr)) {
+ if (infoPtr->dwStyle & UDS_ALIGNLEFT)
+ rect->left += border;
+ else
+ rect->right -= border;
+
+ InflateRect(rect, 0, -border);
+ }
+
+ /* now figure out if we need a space away from the buddy */
+ if (IsWindow(infoPtr->Buddy) ) {
+ if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= spacer;
+ else rect->left += spacer;
+ }
+
+ /*
+ * We're calculating the midpoint to figure-out where the
+ * separation between the buttons will lay. We make sure that we
+ * round the uneven numbers by adding 1.
+ */
+ if (infoPtr->dwStyle & UDS_HORZ) {
+ int len = rect->right - rect->left + 1; /* compute the width */
+ if (arrow & FLAG_INCR)
+ rect->left = rect->left + len/2;
+ if (arrow & FLAG_DECR)
+ rect->right = rect->left + len/2 - (theme ? 0 : 1);
+ } else {
+ int len = rect->bottom - rect->top + 1; /* compute the height */
+ if (arrow & FLAG_INCR)
+ rect->bottom = rect->top + len/2 - (theme ? 0 : 1);
+ if (arrow & FLAG_DECR)
+ rect->top = rect->top + len/2;
+ }
}
/***********************************************************************
* UPDOWN_GetArrowFromPoint
* Returns the rectagle (for the up or down arrow) that contains pt.
- * If it returns the up rect, it returns TRUE.
- * If it returns the down rect, it returns FALSE.
+ * If it returns the up rect, it returns FLAG_INCR.
+ * If it returns the down rect, it returns FLAG_DECR.
*/
-static BOOL
-UPDOWN_GetArrowFromPoint (HWND hwnd, RECT *rect, POINT pt)
+static INT UPDOWN_GetArrowFromPoint (const UPDOWN_INFO *infoPtr, RECT *rect, POINT pt)
{
- UPDOWN_GetArrowRect (hwnd, rect, TRUE);
- if(PtInRect(rect, pt))
- return TRUE;
+ UPDOWN_GetArrowRect (infoPtr, rect, FLAG_INCR);
+ if(PtInRect(rect, pt)) return FLAG_INCR;
+
+ UPDOWN_GetArrowRect (infoPtr, rect, FLAG_DECR);
+ if(PtInRect(rect, pt)) return FLAG_DECR;
- UPDOWN_GetArrowRect (hwnd, rect, FALSE);
- return FALSE;
+ return 0;
}
* UPDOWN_GetThousandSep
* Returns the thousand sep. If an error occurs, it returns ','.
*/
-static char UPDOWN_GetThousandSep()
+static WCHAR UPDOWN_GetThousandSep(void)
{
- char sep[2];
+ WCHAR sep[2];
- if(GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND,
- sep, sizeof(sep)) != 1)
- return ',';
+ if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sep, 2) != 1)
+ sep[0] = ',';
- return sep[0];
+ return sep[0];
}
/***********************************************************************
* it stores it in the control's CurVal
* returns:
* TRUE - if it read the integer from the buddy successfully
- * FALSE - if an error occured
+ * FALSE - if an error occurred
*/
-static BOOL UPDOWN_GetBuddyInt (HWND hwnd)
+static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- char txt[20], sep, *src, *dst;
- int newVal;
-
- if (!IsWindow(infoPtr->Buddy))
- return FALSE;
-
- /*if the buddy is a list window, we must set curr index */
- if (!lstrcmpA (infoPtr->szBuddyClass, "ListBox")){
- newVal = SendMessageA(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0);
- if(newVal < 0)
- return FALSE;
- }
- else{
- /* we have a regular window, so will get the text */
- if (!GetWindowTextA(infoPtr->Buddy, txt, sizeof(txt)))
- return FALSE;
-
- sep = UPDOWN_GetThousandSep();
-
- /* now get rid of the separators */
- for(src = dst = txt; *src; src++)
- if(*src != sep)
- *dst++ = *src;
- *dst = 0;
-
- /* try to convert the number and validate it */
- newVal = strtol(txt, &src, infoPtr->Base);
- if(*src || !UPDOWN_InBounds (hwnd, newVal))
- return FALSE;
-
- TRACE("new value(%d) read from buddy (old=%d)\n",
- newVal, infoPtr->CurVal);
- }
-
- infoPtr->CurVal = newVal;
- return TRUE;
+ WCHAR txt[20], sep, *src, *dst;
+ int newVal;
+
+ if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy)))
+ return FALSE;
+
+ /*if the buddy is a list window, we must set curr index */
+ if (UPDOWN_IsBuddyListbox(infoPtr)) {
+ newVal = SendMessageW(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0);
+ if(newVal < 0) return FALSE;
+ } else {
+ /* we have a regular window, so will get the text */
+ /* note that a zero-length string is a legitimate value for 'txt',
+ * and ought to result in a successful conversion to '0'. */
+ if (GetWindowTextW(infoPtr->Buddy, txt, COUNT_OF(txt)) < 0)
+ return FALSE;
+
+ sep = UPDOWN_GetThousandSep();
+
+ /* now get rid of the separators */
+ for(src = dst = txt; *src; src++)
+ if(*src != sep) *dst++ = *src;
+ *dst = 0;
+
+ /* try to convert the number and validate it */
+ newVal = strtolW(txt, &src, infoPtr->Base);
+ if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE;
+ }
+
+ TRACE("new value(%d) from buddy (old=%d)\n", newVal, infoPtr->CurVal);
+ infoPtr->CurVal = newVal;
+ return TRUE;
}
* Tries to set the pos to the buddy window based on current pos
* returns:
* TRUE - if it set the caption of the buddy successfully
- * FALSE - if an error occured
+ * FALSE - if an error occurred
*/
-static BOOL UPDOWN_SetBuddyInt (HWND hwnd)
+static BOOL UPDOWN_SetBuddyInt (const UPDOWN_INFO *infoPtr)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- char txt1[20], sep;
- int len;
-
- if (!IsWindow(infoPtr->Buddy))
- return FALSE;
-
- TRACE("set new value(%d) to buddy.\n",
- infoPtr->CurVal);
-
- /*if the buddy is a list window, we must set curr index */
- if(!lstrcmpA (infoPtr->szBuddyClass, "ListBox")){
- SendMessageA(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0);
- }
- else{ /* Regular window, so set caption to the number */
- len = sprintf(txt1, (infoPtr->Base==16) ? "%X" : "%d", infoPtr->CurVal);
-
- sep = UPDOWN_GetThousandSep();
-
- /* Do thousands seperation if necessary */
- if (!(GetWindowLongA (hwnd, GWL_STYLE) & UDS_NOTHOUSANDS) && (len > 3)) {
- char txt2[20], *src = txt1, *dst = txt2;
- if(len%3 > 0){
- lstrcpynA (dst, src, len%3 + 1); /* need to include the null */
- dst += len%3;
- src += len%3;
- }
- for(len=0; *src; len++){
- if(len%3==0)
- *dst++ = sep;
- *dst++ = *src++;
- }
- *dst = 0; /* null terminate it */
- strcpy(txt1, txt2); /* move it to the proper place */
+ WCHAR fmt[3] = { '%', 'd', '\0' };
+ WCHAR txt[20];
+ int len;
+
+ if (!((infoPtr->dwStyle & UDS_SETBUDDYINT) && IsWindow(infoPtr->Buddy)))
+ return FALSE;
+
+ TRACE("set new value(%d) to buddy.\n", infoPtr->CurVal);
+
+ /*if the buddy is a list window, we must set curr index */
+ if (UPDOWN_IsBuddyListbox(infoPtr)) {
+ return SendMessageW(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0) != LB_ERR;
}
- SetWindowTextA(infoPtr->Buddy, txt1);
- }
- return TRUE;
-}
+ /* Regular window, so set caption to the number */
+ if (infoPtr->Base == 16) fmt[1] = 'X';
+ len = wsprintfW(txt, fmt, infoPtr->CurVal);
+
+
+ /* Do thousands separation if necessary */
+ if (!(infoPtr->dwStyle & UDS_NOTHOUSANDS) && (len > 3)) {
+ WCHAR tmp[COUNT_OF(txt)], *src = tmp, *dst = txt;
+ WCHAR sep = UPDOWN_GetThousandSep();
+ int start = len % 3;
+
+ memcpy(tmp, txt, sizeof(txt));
+ if (start == 0) start = 3;
+ dst += start;
+ src += start;
+ for (len=0; *src; len++) {
+ if (len % 3 == 0) *dst++ = sep;
+ *dst++ = *src++;
+ }
+ *dst = 0;
+ }
+
+ return SetWindowTextW(infoPtr->Buddy, txt);
+}
/***********************************************************************
- * UPDOWN_DrawBuddyBorder [Internal]
+ * UPDOWN_DrawBuddyBackground
*
- * When we have a buddy set and that we are aligned on our buddy, we
- * want to draw a sunken edge to make like we are part of that control.
+ * Draw buddy background for visual integration.
*/
-static void UPDOWN_DrawBuddyBorder (HWND hwnd, HDC hdc)
+static BOOL UPDOWN_DrawBuddyBackground (const UPDOWN_INFO *infoPtr, HDC hdc)
{
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- RECT clientRect;
-
- GetClientRect(hwnd, &clientRect);
-
- if (dwStyle & UDS_ALIGNLEFT)
- DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_BOTTOM | BF_LEFT | BF_TOP);
- else
- DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_BOTTOM | BF_RIGHT | BF_TOP);
+ RECT br;
+ HTHEME buddyTheme = GetWindowTheme (infoPtr->Buddy);
+ if (!buddyTheme) return FALSE;
+
+ GetClientRect (infoPtr->Buddy, &br);
+ MapWindowPoints (infoPtr->Buddy, infoPtr->Self, (POINT*)&br, 2);
+ /* FIXME: take disabled etc. into account */
+ DrawThemeBackground (buddyTheme, hdc, 0, 0, &br, NULL);
+ return TRUE;
}
/***********************************************************************
- * UPDOWN_Draw [Internal]
+ * UPDOWN_Draw
*
* Draw the arrows. The background need not be erased.
*/
-static void UPDOWN_Draw (HWND hwnd, HDC hdc)
+static LRESULT UPDOWN_Draw (const UPDOWN_INFO *infoPtr, HDC hdc)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- BOOL prssed;
- RECT rect;
-
- /*
- * Draw the common border between ourselves and our buddy.
- */
- if (UPDOWN_HasBuddyBorder(hwnd))
- UPDOWN_DrawBuddyBorder(hwnd, hdc);
-
- /* Draw the incr button */
- UPDOWN_GetArrowRect (hwnd, &rect, TRUE);
- prssed = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
- DrawFrameControl(hdc, &rect, DFC_SCROLL,
- (dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) |
- (prssed ? DFCS_PUSHED : 0) |
- (dwStyle&WS_DISABLED ? DFCS_INACTIVE : 0) );
-
- /* Draw the space between the buttons */
- rect.top = rect.bottom; rect.bottom++;
- DrawEdge(hdc, &rect, 0, BF_MIDDLE);
-
- /* Draw the decr button */
- UPDOWN_GetArrowRect(hwnd, &rect, FALSE);
- prssed = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
- DrawFrameControl(hdc, &rect, DFC_SCROLL,
- (dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) |
- (prssed ? DFCS_PUSHED : 0) |
- (dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
+ BOOL uPressed, uHot, dPressed, dHot;
+ RECT rect;
+ HTHEME theme = GetWindowTheme (infoPtr->Self);
+ int uPart = 0, uState = 0, dPart = 0, dState = 0;
+ BOOL needBuddyBg = FALSE;
+
+ uPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR);
+ uHot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
+ dPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR);
+ dHot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
+ if (theme) {
+ uPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_UPHORZ : SPNP_UP;
+ uState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
+ : (uPressed ? DNS_PRESSED : (uHot ? DNS_HOT : DNS_NORMAL));
+ dPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_DOWNHORZ : SPNP_DOWN;
+ dState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
+ : (dPressed ? DNS_PRESSED : (dHot ? DNS_HOT : DNS_NORMAL));
+ needBuddyBg = IsWindow (infoPtr->Buddy)
+ && (IsThemeBackgroundPartiallyTransparent (theme, uPart, uState)
+ || IsThemeBackgroundPartiallyTransparent (theme, dPart, dState));
+ }
+
+ /* Draw the common border between ourselves and our buddy */
+ if (UPDOWN_HasBuddyBorder(infoPtr) || needBuddyBg) {
+ if (!theme || !UPDOWN_DrawBuddyBackground (infoPtr, hdc)) {
+ GetClientRect(infoPtr->Self, &rect);
+ DrawEdge(hdc, &rect, EDGE_SUNKEN,
+ BF_BOTTOM | BF_TOP |
+ (infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT));
+ }
+ }
+
+ /* Draw the incr button */
+ UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR);
+ if (theme) {
+ DrawThemeBackground(theme, hdc, uPart, uState, &rect, NULL);
+ } else {
+ DrawFrameControl(hdc, &rect, DFC_SCROLL,
+ (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) |
+ ((infoPtr->dwStyle & UDS_HOTTRACK) && uHot ? DFCS_HOT : 0) |
+ (uPressed ? DFCS_PUSHED : 0) |
+ (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
+ }
+
+ /* Draw the decr button */
+ UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR);
+ if (theme) {
+ DrawThemeBackground(theme, hdc, dPart, dState, &rect, NULL);
+ } else {
+ DrawFrameControl(hdc, &rect, DFC_SCROLL,
+ (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) |
+ ((infoPtr->dwStyle & UDS_HOTTRACK) && dHot ? DFCS_HOT : 0) |
+ (dPressed ? DFCS_PUSHED : 0) |
+ (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
+ }
+
+ return 0;
}
/***********************************************************************
- * UPDOWN_Refresh [Internal]
+ * UPDOWN_Paint
*
- * Synchronous drawing (must NOT be used in WM_PAINT).
+ * Asynchronous drawing (must ONLY be used in WM_PAINT).
* Calls UPDOWN_Draw.
*/
-static void UPDOWN_Refresh (HWND hwnd)
+static LRESULT UPDOWN_Paint (const UPDOWN_INFO *infoPtr, HDC hdc)
{
- HDC hdc;
-
- hdc = GetDC (hwnd);
- UPDOWN_Draw (hwnd, hdc);
- ReleaseDC (hwnd, hdc);
+ PAINTSTRUCT ps;
+ if (hdc) return UPDOWN_Draw (infoPtr, hdc);
+ hdc = BeginPaint (infoPtr->Self, &ps);
+ UPDOWN_Draw (infoPtr, hdc);
+ EndPaint (infoPtr->Self, &ps);
+ return 0;
}
+/***********************************************************************
+ * UPDOWN_KeyPressed
+ *
+ * Handle key presses (up & down) when we have to do so
+ */
+static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key)
+{
+ int arrow;
+
+ if (key == VK_UP) arrow = FLAG_INCR;
+ else if (key == VK_DOWN) arrow = FLAG_DECR;
+ else return 1;
+
+ UPDOWN_GetBuddyInt (infoPtr);
+ infoPtr->Flags &= ~FLAG_ARROW;
+ infoPtr->Flags |= FLAG_PRESSED | arrow;
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+ SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0);
+ UPDOWN_DoAction (infoPtr, 1, arrow);
+ return 0;
+}
/***********************************************************************
- * UPDOWN_Paint [Internal]
+ * UPDOWN_MouseWheel
*
- * Asynchronous drawing (must ONLY be used in WM_PAINT).
- * Calls UPDOWN_Draw.
+ * Handle mouse wheel scrolling
*/
-static void UPDOWN_Paint (HWND hwnd, HDC passedDC)
+static LRESULT UPDOWN_MouseWheel(UPDOWN_INFO *infoPtr, WPARAM wParam)
{
- PAINTSTRUCT ps;
- HDC hdc = passedDC;
+ int iWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
+
+ if (wParam & (MK_SHIFT | MK_CONTROL))
+ return 0;
- if (passedDC == 0)
- hdc = BeginPaint (hwnd, &ps);
-
- UPDOWN_Draw (hwnd, hdc);
+ if (iWheelDelta != 0)
+ {
+ UPDOWN_GetBuddyInt(infoPtr);
+ UPDOWN_DoAction(infoPtr, abs(iWheelDelta), iWheelDelta > 0 ? FLAG_INCR : FLAG_DECR);
+ }
- if (passedDC == 0)
- EndPaint (hwnd, &ps);
+ return 1;
+}
+
+
+/***********************************************************************
+ * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy
+ * control.
+ */
+static LRESULT CALLBACK
+UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC superClassWndProc = (WNDPROC)GetPropW(hwnd, BUDDY_SUPERCLASS_WNDPROC);
+
+ TRACE("hwnd=%p, wndProc=%p, uMsg=%04x, wParam=%08lx, lParam=%08lx\n",
+ hwnd, superClassWndProc, uMsg, wParam, lParam);
+
+ if (uMsg == WM_KEYDOWN) {
+ HWND upDownHwnd = GetPropW(hwnd, BUDDY_UPDOWN_HWND);
+
+ UPDOWN_KeyPressed(UPDOWN_GetInfoPtr(upDownHwnd), (int)wParam);
+ }
+ else if (uMsg == WM_MOUSEWHEEL) {
+ HWND upDownHwnd = GetPropW(hwnd, BUDDY_UPDOWN_HWND);
+
+ UPDOWN_MouseWheel(UPDOWN_GetInfoPtr(upDownHwnd), (int)wParam);
+ }
+
+ return CallWindowProcW( superClassWndProc, hwnd, uMsg, wParam, lParam);
}
/***********************************************************************
* UPDOWN_SetBuddy
- * Tests if 'hwndBud' is a valid window handle. If not, returns FALSE.
- * Else, sets it as a new Buddy.
- * Then, it should subclass the buddy
+ *
+ * Sets bud as a new Buddy.
+ * Then, it should subclass the buddy
* If window has the UDS_ARROWKEYS, it subcalsses the buddy window to
* process the UP/DOWN arrow keys.
* If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style
* the size/pos of the buddy and the control are adjusted accordingly.
*/
-static BOOL UPDOWN_SetBuddy (HWND hwnd, HWND hwndBud)
+static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud)
{
- UPDOWN_INFO* infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- RECT budRect; /* new coord for the buddy */
- int x,width; /* new x position and width for the up-down */
- WNDPROC baseWndProc, currWndProc;
-
- /* Is it a valid bud? */
- if(!IsWindow(hwndBud))
- return FALSE;
-
- /* there is already a body assigned */
- if ( infoPtr->Buddy )
- RemovePropA(infoPtr->Buddy, BUDDY_UPDOWN_HWND);
-
- /* Store buddy window handle */
- infoPtr->Buddy = hwndBud;
-
- /* keep upDown ctrl hwnd in a buddy property */
- SetPropA( hwndBud, BUDDY_UPDOWN_HWND, hwnd);
-
- /* Store buddy window clas name */
- memset(infoPtr->szBuddyClass, 0, UPDOWN_BUDDYCLASSNAMELEN);
- GetClassNameA (hwndBud, infoPtr->szBuddyClass, UPDOWN_BUDDYCLASSNAMELEN-1);
-
- if(dwStyle & UDS_ARROWKEYS){
- /* Note that I don't clear the BUDDY_SUPERCLASS_WNDPROC property
- when we reset the upDown ctrl buddy to another buddy because it is not
- good to break the window proc chain. */
-
- currWndProc = (WNDPROC) GetWindowLongA(hwndBud, GWL_WNDPROC);
- if (currWndProc != UPDOWN_Buddy_SubclassProc)
- {
- // replace the buddy's WndProc with ours
- baseWndProc = (WNDPROC)SetWindowLongA(hwndBud, GWL_WNDPROC,
- (LPARAM)UPDOWN_Buddy_SubclassProc);
- // and save the base class' WndProc
- SetPropA(hwndBud, BUDDY_SUPERCLASS_WNDPROC, (HANDLE)baseWndProc);
- }
- // else
- // its already been subclassed, don't overwrite BUDDY_SUPERCLASS_WNDPROC
- }
-
- /* Get the rect of the buddy relative to its parent */
- GetWindowRect(infoPtr->Buddy, &budRect);
- MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy),
- (POINT *)(&budRect.left), 2);
-
- /* now do the positioning */
- if (dwStyle & UDS_ALIGNLEFT) {
- x = budRect.left;
- budRect.left += DEFAULT_WIDTH+DEFAULT_XSEP;
- }
- else if (dwStyle & UDS_ALIGNRIGHT){
- budRect.right -= DEFAULT_WIDTH+DEFAULT_XSEP;
- x = budRect.right+DEFAULT_XSEP;
- }
- else {
- x = budRect.right+DEFAULT_XSEP;
- }
-
- /* first adjust the buddy to accomodate the up/down */
- SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
- budRect.right - budRect.left, budRect.bottom - budRect.top,
- SWP_NOACTIVATE|SWP_NOZORDER);
-
- /* now position the up/down */
- /* Since the UDS_ALIGN* flags were used, */
- /* we will pick the position and size of the window. */
- width = DEFAULT_WIDTH;
-
- /*
- * If the updown has a buddy border, it has to overlap with the buddy
- * to look as if it is integrated with the buddy control.
- * We nudge the control or change it size to overlap.
- */
- if (UPDOWN_HasBuddyBorder(hwnd))
- {
- if(dwStyle & UDS_ALIGNLEFT)
- width+=DEFAULT_BUDDYBORDER;
- else
- x-=DEFAULT_BUDDYBORDER;
- }
+ static const WCHAR editW[] = { 'E', 'd', 'i', 't', 0 };
+ static const WCHAR listboxW[] = { 'L', 'i', 's', 't', 'b', 'o', 'x', 0 };
+ RECT budRect; /* new coord for the buddy */
+ int x, width; /* new x position and width for the up-down */
+ WNDPROC baseWndProc;
+ WCHAR buddyClass[40];
+ HWND ret;
+
+ TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud);
+
+ ret = infoPtr->Buddy;
- SetWindowPos (hwnd, infoPtr->Buddy,
- x, budRect.top-DEFAULT_ADDTOP,
- width, (budRect.bottom-budRect.top)+DEFAULT_ADDTOP+DEFAULT_ADDBOT,
- SWP_NOACTIVATE);
+ /* there is already a body assigned */
+ if (infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND);
- return TRUE;
-}
+ if(!IsWindow(bud))
+ bud = 0;
+
+ /* Store buddy window handle */
+ infoPtr->Buddy = bud;
+
+ if(bud) {
+
+ /* keep upDown ctrl hwnd in a buddy property */
+ SetPropW( bud, BUDDY_UPDOWN_HWND, infoPtr->Self);
+
+ /* Store buddy window class type */
+ infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN;
+ if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) {
+ if (lstrcmpiW(buddyClass, editW) == 0)
+ infoPtr->BuddyType = BUDDY_TYPE_EDIT;
+ else if (lstrcmpiW(buddyClass, listboxW) == 0)
+ infoPtr->BuddyType = BUDDY_TYPE_LISTBOX;
+ }
+
+ if(infoPtr->dwStyle & UDS_ARROWKEYS){
+ /* Note that I don't clear the BUDDY_SUPERCLASS_WNDPROC property
+ when we reset the upDown ctrl buddy to another buddy because it is not
+ good to break the window proc chain. */
+ if (!GetPropW(bud, BUDDY_SUPERCLASS_WNDPROC)) {
+ baseWndProc = (WNDPROC)SetWindowLongPtrW(bud, GWLP_WNDPROC, (LPARAM)UPDOWN_Buddy_SubclassProc);
+ SetPropW(bud, BUDDY_SUPERCLASS_WNDPROC, (HANDLE)baseWndProc);
+ }
+ }
+
+ /* Get the rect of the buddy relative to its parent */
+ GetWindowRect(infoPtr->Buddy, &budRect);
+ MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2);
+
+ /* now do the positioning */
+ if (infoPtr->dwStyle & UDS_ALIGNLEFT) {
+ x = budRect.left;
+ budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP;
+ } else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) {
+ budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP;
+ x = budRect.right+DEFAULT_XSEP;
+ } else {
+ /* nothing to do */
+ return ret;
+ }
+
+ /* first adjust the buddy to accommodate the up/down */
+ SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
+ budRect.right - budRect.left, budRect.bottom - budRect.top,
+ SWP_NOACTIVATE|SWP_NOZORDER);
+
+ /* now position the up/down */
+ /* Since the UDS_ALIGN* flags were used, */
+ /* we will pick the position and size of the window. */
+ width = DEFAULT_WIDTH;
+
+ /*
+ * If the updown has a buddy border, it has to overlap with the buddy
+ * to look as if it is integrated with the buddy control.
+ * We nudge the control or change its size to overlap.
+ */
+ if (UPDOWN_HasBuddyBorder(infoPtr)) {
+ if(infoPtr->dwStyle & UDS_ALIGNLEFT)
+ width += DEFAULT_BUDDYBORDER;
+ else
+ x -= DEFAULT_BUDDYBORDER;
+ }
+
+ SetWindowPos(infoPtr->Self, 0, x,
+ budRect.top - DEFAULT_ADDTOP, width,
+ budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT,
+ SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
+ } else {
+ RECT rect;
+ GetWindowRect(infoPtr->Self, &rect);
+ MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2);
+ SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top,
+ SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
+ }
+ return ret;
+}
/***********************************************************************
* UPDOWN_DoAction
*
- * This function increments/decrements the CurVal by the
- * 'delta' amount according to the 'incr' flag
+ * This function increments/decrements the CurVal by the
+ * 'delta' amount according to the 'action' flag which can be a
+ * combination of FLAG_INCR and FLAG_DECR
* It notifies the parent as required.
* It handles wraping and non-wraping correctly.
* It is assumed that delta>0
*/
-static void UPDOWN_DoAction (HWND hwnd, int delta, BOOL incr)
+static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- NM_UPDOWN ni;
-
- TRACE("%s by %d\n", incr ? "inc" : "dec", delta);
-
- /* check if we can do the modification first */
- delta *= (incr ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
-
- /* We must notify parent now to obtain permission */
- ni.iPos = infoPtr->CurVal;
- ni.iDelta = delta;
- ni.hdr.hwndFrom = hwnd;
- ni.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
- ni.hdr.code = UDN_DELTAPOS;
- if (!SendMessageA(GetParent (hwnd), WM_NOTIFY,
- (WPARAM)ni.hdr.idFrom, (LPARAM)&ni))
- {
- /* Parent said: OK to adjust */
-
- /* Now adjust value with (maybe new) delta */
- if (UPDOWN_OffsetVal (hwnd, ni.iDelta))
- {
- /* Now take care about our buddy */
- if(infoPtr->Buddy && IsWindow(infoPtr->Buddy)
- && (dwStyle & UDS_SETBUDDYINT) )
- UPDOWN_SetBuddyInt (hwnd);
- }
- }
-
- /* Also, notify it. This message is sent in any case. */
- SendMessageA (GetParent (hwnd),
- dwStyle & UDS_HORZ ? WM_HSCROLL : WM_VSCROLL,
- MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), hwnd);
+ NM_UPDOWN ni;
+
+ TRACE("%d by %d\n", action, delta);
+
+ /* check if we can do the modification first */
+ delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
+ if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0;
+
+ TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta);
+
+ /* We must notify parent now to obtain permission */
+ ni.iPos = infoPtr->CurVal;
+ ni.iDelta = delta;
+ ni.hdr.hwndFrom = infoPtr->Self;
+ ni.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
+ ni.hdr.code = UDN_DELTAPOS;
+ if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, ni.hdr.idFrom, (LPARAM)&ni)) {
+ /* Parent said: OK to adjust */
+
+ /* Now adjust value with (maybe new) delta */
+ if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) {
+ TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta);
+
+ /* Now take care about our buddy */
+ UPDOWN_SetBuddyInt (infoPtr);
+ }
+ }
+
+ /* Also, notify it. This message is sent in any case. */
+ SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
+ MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self);
}
/***********************************************************************
* Returns TRUE if it is enabled as well as its buddy (if any)
* FALSE otherwise
*/
-static BOOL UPDOWN_IsEnabled (HWND hwnd)
+static BOOL UPDOWN_IsEnabled (const UPDOWN_INFO *infoPtr)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
-
- if(GetWindowLongA (hwnd, GWL_STYLE) & WS_DISABLED)
- return FALSE;
- if(infoPtr->Buddy)
- return IsWindowEnabled(infoPtr->Buddy);
- return TRUE;
+ if (!IsWindowEnabled(infoPtr->Self))
+ return FALSE;
+ if(infoPtr->Buddy)
+ return IsWindowEnabled(infoPtr->Buddy);
+ return TRUE;
}
/***********************************************************************
*
* Deletes any timers, releases the mouse and does redraw if necessary.
* If the control is not in "capture" mode, it does nothing.
- * If the control was not in cancel mode, it returns FALSE.
+ * If the control was not in cancel mode, it returns FALSE.
* If the control was in cancel mode, it returns TRUE.
*/
-static BOOL UPDOWN_CancelMode (HWND hwnd)
+static BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
-
- /* if not in 'capture' mode, do nothing */
- if(!(infoPtr->Flags & FLAG_CLICKED))
- return FALSE;
-
- KillTimer (hwnd, TIMERID1); /* kill all possible timers */
- KillTimer (hwnd, TIMERID2);
-
- if (GetCapture() == hwnd) /* let the mouse go */
- ReleaseCapture(); /* if we still have it */
-
- infoPtr->Flags = 0; /* get rid of any flags */
- UPDOWN_Refresh (hwnd); /* redraw the control just in case */
-
- return TRUE;
+ if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE;
+
+ KillTimer (infoPtr->Self, TIMER_AUTOREPEAT);
+ KillTimer (infoPtr->Self, TIMER_ACCEL);
+ KillTimer (infoPtr->Self, TIMER_AUTOPRESS);
+
+ if (GetCapture() == infoPtr->Self) {
+ NMHDR hdr;
+ hdr.hwndFrom = infoPtr->Self;
+ hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
+ hdr.code = NM_RELEASEDCAPTURE;
+ SendMessageW(infoPtr->Notify, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
+ ReleaseCapture();
+ }
+
+ infoPtr->Flags &= ~FLAG_PRESSED;
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+
+ return TRUE;
}
/***********************************************************************
*
* Handle a mouse event for the updown.
* 'pt' is the location of the mouse event in client or
- * windows coordinates.
+ * windows coordinates.
*/
-static void UPDOWN_HandleMouseEvent (HWND hwnd, UINT msg, POINT pt)
+static void UPDOWN_HandleMouseEvent (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- RECT rect;
- int temp;
+ POINT pt = { x, y };
+ RECT rect;
+ int temp, arrow;
+ TRACKMOUSEEVENT tme;
+
+ TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt));
- switch(msg)
+ switch(msg)
{
- case WM_LBUTTONDOWN: /* Initialise mouse tracking */
- /* If we are already in the 'clicked' mode, then nothing to do */
- if(infoPtr->Flags & FLAG_CLICKED)
- return;
-
- /* If the buddy is an edit, will set focus to it */
- if (!lstrcmpA (infoPtr->szBuddyClass, "Edit"))
- SetFocus(infoPtr->Buddy);
-
- /* Now see which one is the 'active' arrow */
- temp = UPDOWN_GetArrowFromPoint (hwnd, &rect, pt);
-
- /* Update the CurVal if necessary */
- if (dwStyle & UDS_SETBUDDYINT)
- UPDOWN_GetBuddyInt (hwnd);
-
- /* Set up the correct flags */
- infoPtr->Flags = 0;
- infoPtr->Flags |= temp ? FLAG_INCR : FLAG_DECR;
- infoPtr->Flags |= FLAG_MOUSEIN;
-
- /* repaint the control */
- UPDOWN_Refresh (hwnd);
-
- /* process the click */
- UPDOWN_DoAction (hwnd, 1, infoPtr->Flags & FLAG_INCR);
-
- /* now capture all mouse messages */
- SetCapture (hwnd);
-
- /* and startup the first timer */
- SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
- break;
-
- case WM_MOUSEMOVE:
- /* If we are not in the 'clicked' mode, then nothing to do */
- if(!(infoPtr->Flags & FLAG_CLICKED))
- return;
-
- /* save the flags to see if any got modified */
- temp = infoPtr->Flags;
-
- /* Now get the 'active' arrow rectangle */
- if (infoPtr->Flags & FLAG_INCR)
- UPDOWN_GetArrowRect (hwnd, &rect, TRUE);
- else
- UPDOWN_GetArrowRect (hwnd, &rect, FALSE);
-
- /* Update the flags if we are in/out */
- if(PtInRect(&rect, pt))
- infoPtr->Flags |= FLAG_MOUSEIN;
- else{
- infoPtr->Flags &= ~FLAG_MOUSEIN;
- if(accelIndex != -1) /* if we have accel info */
- accelIndex = 0; /* reset it */
- }
- /* If state changed, redraw the control */
- if(temp != infoPtr->Flags)
- UPDOWN_Refresh (hwnd);
- break;
-
- default:
- ERR("Impossible case!\n");
+ case WM_LBUTTONDOWN: /* Initialise mouse tracking */
+
+ /* If the buddy is an edit, will set focus to it */
+ if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy);
+
+ /* Now see which one is the 'active' arrow */
+ arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
+
+ /* Update the flags if we are in/out */
+ infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
+ if (arrow)
+ infoPtr->Flags |= FLAG_MOUSEIN | arrow;
+ else
+ if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
+
+ if (infoPtr->Flags & FLAG_ARROW) {
+
+ /* Update the CurVal if necessary */
+ UPDOWN_GetBuddyInt (infoPtr);
+
+ /* Set up the correct flags */
+ infoPtr->Flags |= FLAG_PRESSED;
+
+ /* repaint the control */
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+
+ /* process the click */
+ temp = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1;
+ UPDOWN_DoAction (infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
+
+ /* now capture all mouse messages */
+ SetCapture (infoPtr->Self);
+
+ /* and startup the first timer */
+ SetTimer(infoPtr->Self, TIMER_AUTOREPEAT, INITIAL_DELAY, 0);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ /* save the flags to see if any got modified */
+ temp = infoPtr->Flags;
+
+ /* Now see which one is the 'active' arrow */
+ arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
+
+ /* Update the flags if we are in/out */
+ infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
+ if(arrow) {
+ infoPtr->Flags |= FLAG_MOUSEIN | arrow;
+ } else {
+ if(infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
+ }
+
+ /* If state changed, redraw the control */
+ if(temp != infoPtr->Flags)
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+
+ /* Set up tracking so the mousein flags can be reset when the
+ * mouse leaves the control */
+ tme.cbSize = sizeof( tme );
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = infoPtr->Self;
+ TrackMouseEvent (&tme);
+
+ break;
+ case WM_MOUSELEAVE:
+ infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+ break;
+
+ default:
+ ERR("Impossible case (msg=%x)!\n", msg);
}
}
/***********************************************************************
* UpDownWndProc
*/
-static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam,
- LPARAM lParam)
+static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
- DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
- int temp;
- if (!infoPtr && (message != WM_CREATE) && (message != WM_NCCREATE))
- return DefWindowProcA (hwnd, message, wParam, lParam);
- switch(message)
+ UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
+ static const WCHAR themeClass[] = {'S','p','i','n',0};
+ HTHEME theme;
+
+ TRACE("hwnd=%p msg=%04x wparam=%08lx lparam=%08lx\n", hwnd, message, wParam, lParam);
+
+ if (!infoPtr && (message != WM_CREATE))
+ return DefWindowProcW (hwnd, message, wParam, lParam);
+
+ switch(message)
{
- case WM_NCCREATE:
- /* get rid of border, if any */
- SetWindowLongA (hwnd, GWL_STYLE, dwStyle & ~WS_BORDER);
- return TRUE;
-
- case WM_CREATE:
- infoPtr = (UPDOWN_INFO*)COMCTL32_Alloc (sizeof(UPDOWN_INFO));
- SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
-
- /* initialize the info struct */
- infoPtr->AccelCount=0; infoPtr->AccelVect=0;
- infoPtr->CurVal=0; infoPtr->MinVal=0; infoPtr->MaxVal=9999;
- infoPtr->Base = 10; /* Default to base 10 */
- infoPtr->Buddy = 0; /* No buddy window yet */
- infoPtr->Flags = 0; /* And no flags */
-
- /* Do we pick the buddy win ourselves? */
- if (dwStyle & UDS_AUTOBUDDY)
- UPDOWN_SetBuddy (hwnd, GetWindow (hwnd, GW_HWNDPREV));
-
- TRACE("UpDown Ctrl creation, hwnd=%04x\n", hwnd);
- break;
-
- case WM_DESTROY:
- if(infoPtr->AccelVect)
- COMCTL32_Free (infoPtr->AccelVect);
-
- if ( IsWindow(infoPtr->Buddy) ) /* Cleanup */
- RemovePropA(infoPtr->Buddy, BUDDY_UPDOWN_HWND);
-
- COMCTL32_Free (infoPtr);
- SetWindowLongA (hwnd, 0, 0);
- TRACE("UpDown Ctrl destruction, hwnd=%04x\n", hwnd);
- break;
-
- case WM_ENABLE:
- if (dwStyle & WS_DISABLED)
- UPDOWN_CancelMode (hwnd);
-
- UPDOWN_Refresh (hwnd);
- break;
-
- case WM_TIMER:
- /* if initial timer, kill it and start the repeat timer */
- if(wParam == TIMERID1){
- KillTimer(hwnd, TIMERID1);
- /* if no accel info given, used default timer */
- if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0){
- accelIndex = -1;
- temp = REPEAT_DELAY;
- }
- else{
- accelIndex = 0; /* otherwise, use it */
- temp = infoPtr->AccelVect[accelIndex].nSec * 1000 + 1;
- }
- SetTimer(hwnd, TIMERID2, temp, 0);
- }
-
- /* now, if the mouse is above us, do the thing...*/
- if(infoPtr->Flags & FLAG_MOUSEIN){
- temp = accelIndex==-1 ? 1 : infoPtr->AccelVect[accelIndex].nInc;
- UPDOWN_DoAction(hwnd, temp, infoPtr->Flags & FLAG_INCR);
-
- if(accelIndex!=-1 && accelIndex < infoPtr->AccelCount-1){
- KillTimer(hwnd, TIMERID2);
- accelIndex++; /* move to the next accel info */
- temp = infoPtr->AccelVect[accelIndex].nSec * 1000 + 1;
- /* make sure we have at least 1ms intervals */
- SetTimer(hwnd, TIMERID2, temp, 0);
- }
- }
- break;
-
- case WM_CANCELMODE:
- UPDOWN_CancelMode (hwnd);
- break;
-
- case WM_LBUTTONUP:
- if(!UPDOWN_CancelMode(hwnd))
- break;
-
- SendMessageA(GetParent(hwnd), dwStyle & UDS_HORZ ? WM_HSCROLL : WM_VSCROLL,
- MAKELONG(SB_ENDSCROLL, infoPtr->CurVal), hwnd);
-
- /*If we released the mouse and our buddy is an edit */
- /* we must select all text in it. */
- if (!lstrcmpA (infoPtr->szBuddyClass, "Edit"))
- SendMessageA(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1));
- break;
-
- case WM_LBUTTONDOWN:
- case WM_MOUSEMOVE:
- if(UPDOWN_IsEnabled(hwnd)){
- POINT pt;
- pt.x = SLOWORD(lParam);
- pt.y = SHIWORD(lParam);
- UPDOWN_HandleMouseEvent (hwnd, message, pt );
- }
- break;
-
- case WM_KEYDOWN:
- if((dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(hwnd)){
- switch(wParam){
- case VK_UP:
- case VK_DOWN:
- UPDOWN_GetBuddyInt (hwnd);
- /* FIXME: Paint the according button pressed for some time, like win95 does*/
- UPDOWN_DoAction (hwnd, 1, wParam==VK_UP);
- break;
+ case WM_CREATE:
+ infoPtr = (UPDOWN_INFO*)Alloc (sizeof(UPDOWN_INFO));
+ SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
+
+ /* initialize the info struct */
+ infoPtr->Self = hwnd;
+ infoPtr->Notify = ((LPCREATESTRUCTW)lParam)->hwndParent;
+ infoPtr->dwStyle = ((LPCREATESTRUCTW)lParam)->style;
+ infoPtr->AccelCount = 0;
+ infoPtr->AccelVect = 0;
+ infoPtr->AccelIndex = -1;
+ infoPtr->CurVal = 0;
+ infoPtr->MinVal = 100;
+ infoPtr->MaxVal = 0;
+ infoPtr->Base = 10; /* Default to base 10 */
+ infoPtr->Buddy = 0; /* No buddy window yet */
+ infoPtr->Flags = 0; /* And no flags */
+
+ SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle & ~WS_BORDER);
+
+ /* Do we pick the buddy win ourselves? */
+ if (infoPtr->dwStyle & UDS_AUTOBUDDY)
+ UPDOWN_SetBuddy (infoPtr, GetWindow (hwnd, GW_HWNDPREV));
+
+ OpenThemeData (hwnd, themeClass);
+
+ TRACE("UpDown Ctrl creation, hwnd=%p\n", hwnd);
+ break;
+
+ case WM_DESTROY:
+ Free (infoPtr->AccelVect);
+
+ if(infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND);
+
+ Free (infoPtr);
+ SetWindowLongPtrW (hwnd, 0, 0);
+ theme = GetWindowTheme (hwnd);
+ CloseThemeData (theme);
+ TRACE("UpDown Ctrl destruction, hwnd=%p\n", hwnd);
+ break;
+
+ case WM_ENABLE:
+ if (wParam) {
+ infoPtr->dwStyle &= ~WS_DISABLED;
+ } else {
+ infoPtr->dwStyle |= WS_DISABLED;
+ UPDOWN_CancelMode (infoPtr);
+ }
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+ break;
+
+ case WM_STYLECHANGED:
+ if (wParam == GWL_STYLE) {
+ infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew;
+ InvalidateRect (infoPtr->Self, NULL, FALSE);
+ }
+ break;
+
+ case WM_THEMECHANGED:
+ theme = GetWindowTheme (hwnd);
+ CloseThemeData (theme);
+ OpenThemeData (hwnd, themeClass);
+ InvalidateRect (hwnd, NULL, FALSE);
+ break;
+
+ case WM_TIMER:
+ /* is this the auto-press timer? */
+ if(wParam == TIMER_AUTOPRESS) {
+ KillTimer(hwnd, TIMER_AUTOPRESS);
+ infoPtr->Flags &= ~(FLAG_PRESSED | FLAG_ARROW);
+ InvalidateRect(infoPtr->Self, NULL, FALSE);
+ }
+
+ /* if initial timer, kill it and start the repeat timer */
+ if(wParam == TIMER_AUTOREPEAT) {
+ int temp;
+
+ KillTimer(hwnd, TIMER_AUTOREPEAT);
+ /* if no accel info given, used default timer */
+ if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0) {
+ infoPtr->AccelIndex = -1;
+ temp = REPEAT_DELAY;
+ } else {
+ infoPtr->AccelIndex = 0; /* otherwise, use it */
+ temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
+ }
+ SetTimer(hwnd, TIMER_ACCEL, temp, 0);
+ }
+
+ /* now, if the mouse is above us, do the thing...*/
+ if(infoPtr->Flags & FLAG_MOUSEIN) {
+ int temp;
+
+ temp = infoPtr->AccelIndex == -1 ? 1 : infoPtr->AccelVect[infoPtr->AccelIndex].nInc;
+ UPDOWN_DoAction(infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
+
+ if(infoPtr->AccelIndex != -1 && infoPtr->AccelIndex < infoPtr->AccelCount-1) {
+ KillTimer(hwnd, TIMER_ACCEL);
+ infoPtr->AccelIndex++; /* move to the next accel info */
+ temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
+ /* make sure we have at least 1ms intervals */
+ SetTimer(hwnd, TIMER_ACCEL, temp, 0);
+ }
+ }
+ break;
+
+ case WM_CANCELMODE:
+ return UPDOWN_CancelMode (infoPtr);
+
+ case WM_LBUTTONUP:
+ if (GetCapture() != infoPtr->Self) break;
+
+ if ( (infoPtr->Flags & FLAG_MOUSEIN) &&
+ (infoPtr->Flags & FLAG_ARROW) ) {
+
+ SendMessageW( infoPtr->Notify,
+ (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
+ MAKELONG(SB_ENDSCROLL, infoPtr->CurVal),
+ (LPARAM)hwnd);
+ if (UPDOWN_IsBuddyEdit(infoPtr))
+ SendMessageW(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1));
+ }
+ UPDOWN_CancelMode(infoPtr);
+ break;
+
+ case WM_LBUTTONDOWN:
+ case WM_MOUSEMOVE:
+ case WM_MOUSELEAVE:
+ if(UPDOWN_IsEnabled(infoPtr))
+ UPDOWN_HandleMouseEvent (infoPtr, message, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
+ break;
+
+ case WM_MOUSEWHEEL:
+ UPDOWN_MouseWheel(infoPtr, wParam);
+ break;
+
+ case WM_KEYDOWN:
+ if((infoPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(infoPtr))
+ return UPDOWN_KeyPressed(infoPtr, (int)wParam);
+ break;
+
+ case WM_PRINTCLIENT:
+ case WM_PAINT:
+ return UPDOWN_Paint (infoPtr, (HDC)wParam);
+
+ case UDM_GETACCEL:
+ if (wParam==0 && lParam==0) return infoPtr->AccelCount;
+ if (wParam && lParam) {
+ int temp = min(infoPtr->AccelCount, wParam);
+ memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL));
+ return temp;
+ }
+ return 0;
+
+ case UDM_SETACCEL:
+ {
+ unsigned temp;
+
+ TRACE("UDM_SETACCEL\n");
+
+ if(infoPtr->AccelVect) {
+ Free (infoPtr->AccelVect);
+ infoPtr->AccelCount = 0;
+ infoPtr->AccelVect = 0;
+ }
+ if(wParam==0) return TRUE;
+ infoPtr->AccelVect = Alloc (wParam*sizeof(UDACCEL));
+ if(infoPtr->AccelVect == 0) return FALSE;
+ memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL));
+ infoPtr->AccelCount = wParam;
+
+ for (temp = 0; temp < wParam; temp++)
+ TRACE("%d: nSec %u nInc %u\n", temp, infoPtr->AccelVect[temp].nSec, infoPtr->AccelVect[temp].nInc);
+
+ return TRUE;
}
- }
- break;
-
- case WM_PAINT:
- UPDOWN_Paint (hwnd, (HDC)wParam);
- break;
-
- case UDM_GETACCEL:
- if (wParam==0 && lParam==0) /*if both zero, */
- return infoPtr->AccelCount; /*just return the accel count*/
- if (wParam || lParam){
- UNKNOWN_PARAM(UDM_GETACCEL, wParam, lParam);
- return 0;
- }
- temp = min(infoPtr->AccelCount, wParam);
- memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL));
- return temp;
-
- case UDM_SETACCEL:
- TRACE("UpDown Ctrl new accel info, hwnd=%04x\n", hwnd);
- if(infoPtr->AccelVect){
- COMCTL32_Free (infoPtr->AccelVect);
- infoPtr->AccelCount = 0;
- infoPtr->AccelVect = 0;
- }
- if(wParam==0)
- return TRUE;
- infoPtr->AccelVect = COMCTL32_Alloc (wParam*sizeof(UDACCEL));
- if(infoPtr->AccelVect==0)
- return FALSE;
- memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL));
- return TRUE;
-
- case UDM_GETBASE:
- if (wParam || lParam)
- UNKNOWN_PARAM(UDM_GETBASE, wParam, lParam);
- return infoPtr->Base;
-
- case UDM_SETBASE:
- TRACE("UpDown Ctrl new base(%d), hwnd=%04x\n",
- wParam, hwnd);
- if ( !(wParam==10 || wParam==16) || lParam)
- UNKNOWN_PARAM(UDM_SETBASE, wParam, lParam);
- if (wParam==10 || wParam==16){
- temp = infoPtr->Base;
- infoPtr->Base = wParam;
- return temp; /* return the prev base */
- }
- break;
-
- case UDM_GETBUDDY:
- if (wParam || lParam)
- UNKNOWN_PARAM(UDM_GETBUDDY, wParam, lParam);
- return infoPtr->Buddy;
-
- case UDM_SETBUDDY:
- if (lParam)
- UNKNOWN_PARAM(UDM_SETBUDDY, wParam, lParam);
- temp = infoPtr->Buddy;
- UPDOWN_SetBuddy (hwnd, wParam);
- TRACE("UpDown Ctrl new buddy(%04x), hwnd=%04x\n",
- infoPtr->Buddy, hwnd);
- return temp;
-
- case UDM_GETPOS:
- if (wParam || lParam)
- UNKNOWN_PARAM(UDM_GETPOS, wParam, lParam);
- temp = UPDOWN_GetBuddyInt (hwnd);
- return MAKELONG(infoPtr->CurVal, temp ? 0 : 1);
-
- case UDM_SETPOS:
- if (wParam || HIWORD(lParam))
- UNKNOWN_PARAM(UDM_GETPOS, wParam, lParam);
- temp = SLOWORD(lParam);
- TRACE("UpDown Ctrl new value(%d), hwnd=%04x\n",
- temp, hwnd);
- if(!UPDOWN_InBounds(hwnd, temp)){
- if(temp < infoPtr->MinVal)
- temp = infoPtr->MinVal;
- if(temp > infoPtr->MaxVal)
- temp = infoPtr->MaxVal;
- }
- wParam = infoPtr->CurVal; /* save prev value */
- infoPtr->CurVal = temp; /* set the new value */
- if(dwStyle & UDS_SETBUDDYINT)
- UPDOWN_SetBuddyInt (hwnd);
- return wParam; /* return prev value */
-
- case UDM_GETRANGE:
- if (wParam || lParam)
- UNKNOWN_PARAM(UDM_GETRANGE, wParam, lParam);
- return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal);
-
- case UDM_SETRANGE:
- if (wParam)
- UNKNOWN_PARAM(UDM_SETRANGE, wParam, lParam); /* we must have: */
- infoPtr->MaxVal = SLOWORD(lParam); /* UD_MINVAL <= Max <= UD_MAXVAL */
- infoPtr->MinVal = SHIWORD(lParam); /* UD_MINVAL <= Min <= UD_MAXVAL */
- /* |Max-Min| <= UD_MAXVAL */
- TRACE("UpDown Ctrl new range(%d to %d), hwnd=%04x\n",
- infoPtr->MinVal, infoPtr->MaxVal, hwnd);
- break;
-
- case UDM_GETRANGE32:
- if (wParam)
- *(LPINT)wParam = infoPtr->MinVal;
- if (lParam)
- *(LPINT)lParam = infoPtr->MaxVal;
- break;
-
- case UDM_SETRANGE32:
- infoPtr->MinVal = (INT)wParam;
- infoPtr->MaxVal = (INT)lParam;
- if (infoPtr->MaxVal <= infoPtr->MinVal)
- infoPtr->MaxVal = infoPtr->MinVal + 1;
- TRACE("UpDown Ctrl new range(%d to %d), hwnd=%04x\n",
- infoPtr->MinVal, infoPtr->MaxVal, hwnd);
- break;
-
- case UDM_GETPOS32:
- if ((LPBOOL)lParam != NULL)
- *((LPBOOL)lParam) = TRUE;
- return infoPtr->CurVal;
-
- case UDM_SETPOS32:
- if(!UPDOWN_InBounds(hwnd, (int)lParam)){
- if((int)lParam < infoPtr->MinVal)
- lParam = infoPtr->MinVal;
- if((int)lParam > infoPtr->MaxVal)
- lParam = infoPtr->MaxVal;
- }
- temp = infoPtr->CurVal; /* save prev value */
- infoPtr->CurVal = (int)lParam; /* set the new value */
- if(dwStyle & UDS_SETBUDDYINT)
- UPDOWN_SetBuddyInt (hwnd);
- return temp; /* return prev value */
-
- default:
- if (message >= WM_USER)
- ERR("unknown msg %04x wp=%04x lp=%08lx\n",
- message, wParam, lParam);
- return DefWindowProcA (hwnd, message, wParam, lParam);
- }
+ case UDM_GETBASE:
+ return infoPtr->Base;
- return 0;
-}
+ case UDM_SETBASE:
+ TRACE("UpDown Ctrl new base(%ld), hwnd=%p\n", wParam, hwnd);
+ if (wParam==10 || wParam==16) {
+ WPARAM temp = infoPtr->Base;
+ infoPtr->Base = wParam;
+ return temp;
+ }
+ break;
-/***********************************************************************
- * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy
- * control.
- */
-LRESULT CALLBACK
-UPDOWN_Buddy_SubclassProc (
- HWND hwnd,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam)
-{
- WNDPROC superClassWndProc = (WNDPROC)GetPropA(hwnd, BUDDY_SUPERCLASS_WNDPROC);
- TRACE("hwnd=%04x, wndProc=%d, uMsg=%04x, wParam=%d, lParam=%d\n",
- hwnd, (INT)superClassWndProc, uMsg, wParam, (UINT)lParam);
+ case UDM_GETBUDDY:
+ return (LRESULT)infoPtr->Buddy;
- switch (uMsg)
- {
- case WM_KEYDOWN:
- {
- if ( ((int)wParam == VK_UP ) || ((int)wParam == VK_DOWN ) )
- {
- HWND upDownHwnd = GetPropA(hwnd, BUDDY_UPDOWN_HWND);
- UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(upDownHwnd);
-
- if (!lstrcmpA (infoPtr->szBuddyClass, "ListBox"))
- {
- /* if the buddy is a list window, we must update curr index */
- INT oldVal = SendMessageA(hwnd, LB_GETCURSEL, 0, 0);
- SendMessageA(hwnd, LB_SETCURSEL, oldVal+1, 0);
- }
- else
- {
- UPDOWN_GetBuddyInt(upDownHwnd);
- UPDOWN_DoAction(upDownHwnd, 1, wParam==VK_UP);
- }
+ case UDM_SETBUDDY:
+ return (LRESULT)UPDOWN_SetBuddy (infoPtr, (HWND)wParam);
+
+ case UDM_GETPOS:
+ {
+ int temp = UPDOWN_GetBuddyInt (infoPtr);
+ return MAKELONG(infoPtr->CurVal, temp ? 0 : 1);
+ }
+ case UDM_SETPOS:
+ {
+ int temp = (short)LOWORD(lParam);
+
+ TRACE("UpDown Ctrl new value(%d), hwnd=%p\n", temp, hwnd);
+ if(!UPDOWN_InBounds(infoPtr, temp)) {
+ if(temp < infoPtr->MinVal) temp = infoPtr->MinVal;
+ if(temp > infoPtr->MaxVal) temp = infoPtr->MaxVal;
+ }
+ wParam = infoPtr->CurVal;
+ infoPtr->CurVal = temp;
+ UPDOWN_SetBuddyInt (infoPtr);
+ return wParam; /* return prev value */
+ }
+ case UDM_GETRANGE:
+ return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal);
+
+ case UDM_SETRANGE:
+ /* we must have: */
+ infoPtr->MaxVal = (short)(lParam); /* UD_MINVAL <= Max <= UD_MAXVAL */
+ infoPtr->MinVal = (short)HIWORD(lParam); /* UD_MINVAL <= Min <= UD_MAXVAL */
+ /* |Max-Min| <= UD_MAXVAL */
+ TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n",
+ infoPtr->MinVal, infoPtr->MaxVal, hwnd);
+ break;
+
+ case UDM_GETRANGE32:
+ if (wParam) *(LPINT)wParam = infoPtr->MinVal;
+ if (lParam) *(LPINT)lParam = infoPtr->MaxVal;
+ break;
+
+ case UDM_SETRANGE32:
+ infoPtr->MinVal = (INT)wParam;
+ infoPtr->MaxVal = (INT)lParam;
+ if (infoPtr->MaxVal <= infoPtr->MinVal)
+ infoPtr->MaxVal = infoPtr->MinVal + 1;
+ TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n",
+ infoPtr->MinVal, infoPtr->MaxVal, hwnd);
+ break;
+
+ case UDM_GETPOS32:
+ if ((LPBOOL)lParam != NULL) *((LPBOOL)lParam) = TRUE;
+ return infoPtr->CurVal;
+
+ case UDM_SETPOS32:
+ {
+ int temp;
+
+ if(!UPDOWN_InBounds(infoPtr, (int)lParam)) {
+ if((int)lParam < infoPtr->MinVal) lParam = infoPtr->MinVal;
+ if((int)lParam > infoPtr->MaxVal) lParam = infoPtr->MaxVal;
+ }
+ temp = infoPtr->CurVal; /* save prev value */
+ infoPtr->CurVal = (int)lParam; /* set the new value */
+ UPDOWN_SetBuddyInt (infoPtr);
+ return temp; /* return prev value */
+ }
+ case UDM_GETUNICODEFORMAT:
+ /* we lie a bit here, we're always using Unicode internally */
+ return infoPtr->UnicodeFormat;
- break;
- }
- /* else Fall Through */
+ case UDM_SETUNICODEFORMAT:
+ {
+ /* do we really need to honour this flag? */
+ int temp = infoPtr->UnicodeFormat;
+ infoPtr->UnicodeFormat = (BOOL)wParam;
+ return temp;
+ }
+ default:
+ if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
+ ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam);
+ return DefWindowProcW (hwnd, message, wParam, lParam);
}
- }
- return CallWindowProcA( superClassWndProc, hwnd, uMsg, wParam, lParam);
+
+ return 0;
}
/***********************************************************************
*
* Registers the updown window class.
*/
-
-VOID
-UPDOWN_Register(void)
+void UPDOWN_Register(void)
{
- WNDCLASSA wndClass;
+ WNDCLASSW wndClass;
- ZeroMemory( &wndClass, sizeof( WNDCLASSA ) );
- wndClass.style = CS_GLOBALCLASS | CS_VREDRAW;
- wndClass.lpfnWndProc = (WNDPROC)UpDownWindowProc;
+ ZeroMemory( &wndClass, sizeof( WNDCLASSW ) );
+ wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
+ wndClass.lpfnWndProc = UpDownWindowProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = sizeof(UPDOWN_INFO*);
- wndClass.hCursor = LoadCursorA( 0, IDC_ARROWA );
- wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
- wndClass.lpszClassName = UPDOWN_CLASSA;
-
- RegisterClassA( &wndClass );
+ wndClass.hCursor = LoadCursorW( 0, (LPWSTR)IDC_ARROW );
+ wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
+ wndClass.lpszClassName = UPDOWN_CLASSW;
+
+ RegisterClassW( &wndClass );
}
*
* Unregisters the updown window class.
*/
-
-VOID
-UPDOWN_Unregister (void)
+void UPDOWN_Unregister (void)
{
- UnregisterClassA (UPDOWN_CLASSA, (HINSTANCE)NULL);
+ UnregisterClassW (UPDOWN_CLASSW, NULL);
}
-