ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

updown.c
Go to the documentation of this file.
00001 /*
00002  * Updown control
00003  *
00004  * Copyright 1997, 2002 Dimitrie O. Paun
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  *
00020  * NOTE
00021  * 
00022  * This code was audited for completeness against the documented features
00023  * of Comctl32.dll version 6.0 on Sep. 9, 2002, by Dimitrie O. Paun.
00024  * 
00025  * Unless otherwise noted, we believe this code to be complete, as per
00026  * the specification mentioned above.
00027  * If you discover missing features, or bugs, please note them below.
00028  * 
00029  */
00030 
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <stdarg.h>
00034 #include <stdio.h>
00035 
00036 #include "windef.h"
00037 #include "winbase.h"
00038 #include "wingdi.h"
00039 #include "winuser.h"
00040 #include "winnls.h"
00041 #include "commctrl.h"
00042 #include "comctl32.h"
00043 #include "uxtheme.h"
00044 #include "vssym32.h"
00045 #include "wine/unicode.h"
00046 #include "wine/debug.h"
00047 
00048 WINE_DEFAULT_DEBUG_CHANNEL(updown);
00049 
00050 typedef struct
00051 {
00052     HWND      Self;            /* Handle to this up-down control */
00053     HWND      Notify;          /* Handle to the parent window */
00054     DWORD     dwStyle;         /* The GWL_STYLE for this window */
00055     UINT      AccelCount;      /* Number of elements in AccelVect */
00056     UDACCEL*  AccelVect;       /* Vector containing AccelCount elements */
00057     INT       AccelIndex;      /* Current accel index, -1 if not accel'ing */
00058     INT       Base;            /* Base to display nr in the buddy window */
00059     INT       CurVal;          /* Current up-down value */
00060     INT       MinVal;          /* Minimum up-down value */
00061     INT       MaxVal;          /* Maximum up-down value */
00062     HWND      Buddy;           /* Handle to the buddy window */
00063     INT       BuddyType;       /* Remembers the buddy type BUDDY_TYPE_* */
00064     INT       Flags;           /* Internal Flags FLAG_* */
00065     BOOL      UnicodeFormat;   /* Marks the use of Unicode internally */
00066 } UPDOWN_INFO;
00067 
00068 /* Control configuration constants */
00069 
00070 #define INITIAL_DELAY   500    /* initial timer until auto-inc kicks in */
00071 #define AUTOPRESS_DELAY 250    /* time to keep arrow pressed on KEY_DOWN */
00072 #define REPEAT_DELAY    50     /* delay between auto-increments */
00073 
00074 #define DEFAULT_WIDTH       16 /* default width of the ctrl */
00075 #define DEFAULT_XSEP         0 /* default separation between buddy and ctrl */
00076 #define DEFAULT_ADDTOP       0 /* amount to extend above the buddy window */
00077 #define DEFAULT_ADDBOT       0 /* amount to extend below the buddy window */
00078 #define DEFAULT_BUDDYBORDER  2 /* Width/height of the buddy border */
00079 #define DEFAULT_BUDDYSPACER  2 /* Spacer between the buddy and the ctrl */
00080 #define DEFAULT_BUDDYBORDER_THEMED  1 /* buddy border when theming is enabled */
00081 #define DEFAULT_BUDDYSPACER_THEMED  0 /* buddy spacer when theming is enabled */
00082 
00083 /* Work constants */
00084 
00085 #define FLAG_INCR   0x01
00086 #define FLAG_DECR   0x02
00087 #define FLAG_MOUSEIN    0x04
00088 #define FLAG_PRESSED    0x08
00089 #define FLAG_BUDDYINT   0x10 /* UDS_SETBUDDYINT was set on creation */
00090 #define FLAG_ARROW  (FLAG_INCR | FLAG_DECR)
00091 
00092 #define BUDDY_TYPE_UNKNOWN 0
00093 #define BUDDY_TYPE_LISTBOX 1
00094 #define BUDDY_TYPE_EDIT    2
00095 
00096 #define TIMER_AUTOREPEAT   1
00097 #define TIMER_ACCEL        2
00098 #define TIMER_AUTOPRESS    3
00099 
00100 #define UPDOWN_GetInfoPtr(hwnd) ((UPDOWN_INFO *)GetWindowLongPtrW (hwnd,0))
00101 #define COUNT_OF(a) (sizeof(a)/sizeof(a[0]))
00102 
00103 /* id used for SetWindowSubclass */
00104 #define BUDDY_SUBCLASSID   1
00105 
00106 static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action);
00107 
00108 /***********************************************************************
00109  *           UPDOWN_IsBuddyEdit
00110  * Tests if our buddy is an edit control.
00111  */
00112 static inline BOOL UPDOWN_IsBuddyEdit(const UPDOWN_INFO *infoPtr)
00113 {
00114     return infoPtr->BuddyType == BUDDY_TYPE_EDIT;
00115 }
00116 
00117 /***********************************************************************
00118  *           UPDOWN_IsBuddyListbox
00119  * Tests if our buddy is a listbox control.
00120  */
00121 static inline BOOL UPDOWN_IsBuddyListbox(const UPDOWN_INFO *infoPtr)
00122 {
00123     return infoPtr->BuddyType == BUDDY_TYPE_LISTBOX;
00124 }
00125 
00126 /***********************************************************************
00127  *           UPDOWN_InBounds
00128  * Tests if a given value 'val' is between the Min&Max limits
00129  */
00130 static BOOL UPDOWN_InBounds(const UPDOWN_INFO *infoPtr, int val)
00131 {
00132     if(infoPtr->MaxVal > infoPtr->MinVal)
00133         return (infoPtr->MinVal <= val) && (val <= infoPtr->MaxVal);
00134     else
00135         return (infoPtr->MaxVal <= val) && (val <= infoPtr->MinVal);
00136 }
00137 
00138 /***********************************************************************
00139  *           UPDOWN_OffsetVal
00140  * Change the current value by delta.
00141  * It returns TRUE is the value was changed successfully, or FALSE
00142  * if the value was not changed, as it would go out of bounds.
00143  */
00144 static BOOL UPDOWN_OffsetVal(UPDOWN_INFO *infoPtr, int delta)
00145 {
00146     /* check if we can do the modification first */
00147     if(!UPDOWN_InBounds (infoPtr, infoPtr->CurVal+delta)) {
00148         if (infoPtr->dwStyle & UDS_WRAP) {
00149             delta += (delta < 0 ? -1 : 1) *
00150              (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1) *
00151              (infoPtr->MinVal - infoPtr->MaxVal) +
00152              (delta < 0 ? 1 : -1);
00153         } else return FALSE;
00154     }
00155 
00156     infoPtr->CurVal += delta;
00157     return TRUE;
00158 }
00159 
00160 /***********************************************************************
00161  * UPDOWN_HasBuddyBorder
00162  *
00163  * When we have a buddy set and that we are aligned on our buddy, we
00164  * want to draw a sunken edge to make like we are part of that control.
00165  */
00166 static BOOL UPDOWN_HasBuddyBorder(const UPDOWN_INFO *infoPtr)
00167 {
00168     return  ( ((infoPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT)) != 0) &&
00169           UPDOWN_IsBuddyEdit(infoPtr) );
00170 }
00171 
00172 /***********************************************************************
00173  *           UPDOWN_GetArrowRect
00174  * wndPtr   - pointer to the up-down wnd
00175  * rect     - will hold the rectangle
00176  * arrow    - FLAG_INCR to get the "increment" rect (up or right)
00177  *            FLAG_DECR to get the "decrement" rect (down or left)
00178  *            If both flags are present, the envelope is returned.
00179  */
00180 static void UPDOWN_GetArrowRect (const UPDOWN_INFO* infoPtr, RECT *rect, int arrow)
00181 {
00182     HTHEME theme = GetWindowTheme (infoPtr->Self);
00183     const int border = theme ? DEFAULT_BUDDYBORDER_THEMED : DEFAULT_BUDDYBORDER;
00184     const int spacer = theme ? DEFAULT_BUDDYSPACER_THEMED : DEFAULT_BUDDYSPACER;
00185     GetClientRect (infoPtr->Self, rect);
00186 
00187     /*
00188      * Make sure we calculate the rectangle to fit even if we draw the
00189      * border.
00190      */
00191     if (UPDOWN_HasBuddyBorder(infoPtr)) {
00192         if (infoPtr->dwStyle & UDS_ALIGNLEFT)
00193             rect->left += border;
00194         else
00195             rect->right -= border;
00196 
00197         InflateRect(rect, 0, -border);
00198     }
00199 
00200     /* now figure out if we need a space away from the buddy */
00201     if (IsWindow(infoPtr->Buddy) ) {
00202     if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= spacer;
00203     else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) rect->left += spacer;
00204     }
00205 
00206     /*
00207      * We're calculating the midpoint to figure-out where the
00208      * separation between the buttons will lay. We make sure that we
00209      * round the uneven numbers by adding 1.
00210      */
00211     if (infoPtr->dwStyle & UDS_HORZ) {
00212         int len = rect->right - rect->left + 1; /* compute the width */
00213         if (arrow & FLAG_INCR)
00214             rect->left = rect->left + len/2;
00215         if (arrow & FLAG_DECR)
00216             rect->right =  rect->left + len/2 - (theme ? 0 : 1);
00217     } else {
00218         int len = rect->bottom - rect->top + 1; /* compute the height */
00219         if (arrow & FLAG_INCR)
00220             rect->bottom =  rect->top + len/2 - (theme ? 0 : 1);
00221         if (arrow & FLAG_DECR)
00222             rect->top =  rect->top + len/2;
00223     }
00224 }
00225 
00226 /***********************************************************************
00227  *           UPDOWN_GetArrowFromPoint
00228  * Returns the rectagle (for the up or down arrow) that contains pt.
00229  * If it returns the up rect, it returns FLAG_INCR.
00230  * If it returns the down rect, it returns FLAG_DECR.
00231  */
00232 static INT UPDOWN_GetArrowFromPoint (const UPDOWN_INFO *infoPtr, RECT *rect, POINT pt)
00233 {
00234     UPDOWN_GetArrowRect (infoPtr, rect, FLAG_INCR);
00235     if(PtInRect(rect, pt)) return FLAG_INCR;
00236 
00237     UPDOWN_GetArrowRect (infoPtr, rect, FLAG_DECR);
00238     if(PtInRect(rect, pt)) return FLAG_DECR;
00239 
00240     return 0;
00241 }
00242 
00243 
00244 /***********************************************************************
00245  *           UPDOWN_GetThousandSep
00246  * Returns the thousand sep. If an error occurs, it returns ','.
00247  */
00248 static WCHAR UPDOWN_GetThousandSep(void)
00249 {
00250     WCHAR sep[2];
00251 
00252     if(GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sep, 2) != 1)
00253         sep[0] = ',';
00254 
00255     return sep[0];
00256 }
00257 
00258 /***********************************************************************
00259  *           UPDOWN_GetBuddyInt
00260  * Tries to read the pos from the buddy window and if it succeeds,
00261  * it stores it in the control's CurVal
00262  * returns:
00263  *   TRUE  - if it read the integer from the buddy successfully
00264  *   FALSE - if an error occurred
00265  */
00266 static BOOL UPDOWN_GetBuddyInt (UPDOWN_INFO *infoPtr)
00267 {
00268     WCHAR txt[20], sep, *src, *dst;
00269     int newVal;
00270 
00271     if (!((infoPtr->Flags & FLAG_BUDDYINT) && IsWindow(infoPtr->Buddy)))
00272         return FALSE;
00273 
00274     /*if the buddy is a list window, we must set curr index */
00275     if (UPDOWN_IsBuddyListbox(infoPtr)) {
00276         newVal = SendMessageW(infoPtr->Buddy, LB_GETCARETINDEX, 0, 0);
00277         if(newVal < 0) return FALSE;
00278     } else {
00279         /* we have a regular window, so will get the text */
00280         /* note that a zero-length string is a legitimate value for 'txt',
00281          * and ought to result in a successful conversion to '0'. */
00282         if (GetWindowTextW(infoPtr->Buddy, txt, COUNT_OF(txt)) < 0)
00283             return FALSE;
00284 
00285         sep = UPDOWN_GetThousandSep();
00286 
00287         /* now get rid of the separators */
00288         for(src = dst = txt; *src; src++)
00289             if(*src != sep) *dst++ = *src;
00290         *dst = 0;
00291 
00292         /* try to convert the number and validate it */
00293         newVal = strtolW(txt, &src, infoPtr->Base);
00294         if(*src || !UPDOWN_InBounds (infoPtr, newVal)) return FALSE;
00295     }
00296 
00297     TRACE("new value(%d) from buddy (old=%d)\n", newVal, infoPtr->CurVal);
00298     infoPtr->CurVal = newVal;
00299     return TRUE;
00300 }
00301 
00302 
00303 /***********************************************************************
00304  *           UPDOWN_SetBuddyInt
00305  * Tries to set the pos to the buddy window based on current pos
00306  * returns:
00307  *   TRUE  - if it set the caption of the  buddy successfully
00308  *   FALSE - if an error occurred
00309  */
00310 static BOOL UPDOWN_SetBuddyInt (const UPDOWN_INFO *infoPtr)
00311 {
00312     static const WCHAR fmt_hex[] = { '0', 'x', '%', '0', '4', 'X', 0 };
00313     static const WCHAR fmt_dec_oct[] = { '%', 'd', '\0' };
00314     const WCHAR *fmt;
00315     WCHAR txt[20], txt_old[20] = { 0 };
00316     int len;
00317 
00318     if (!((infoPtr->Flags & FLAG_BUDDYINT) && IsWindow(infoPtr->Buddy)))
00319         return FALSE;
00320 
00321     TRACE("set new value(%d) to buddy.\n", infoPtr->CurVal);
00322 
00323     /*if the buddy is a list window, we must set curr index */
00324     if (UPDOWN_IsBuddyListbox(infoPtr)) {
00325         return SendMessageW(infoPtr->Buddy, LB_SETCURSEL, infoPtr->CurVal, 0) != LB_ERR;
00326     }
00327 
00328     /* Regular window, so set caption to the number */
00329     fmt = (infoPtr->Base == 16) ? fmt_hex : fmt_dec_oct;
00330     len = wsprintfW(txt, fmt, infoPtr->CurVal);
00331 
00332 
00333     /* Do thousands separation if necessary */
00334     if ((infoPtr->Base == 10) && !(infoPtr->dwStyle & UDS_NOTHOUSANDS) && (len > 3)) {
00335         WCHAR tmp[COUNT_OF(txt)], *src = tmp, *dst = txt;
00336         WCHAR sep = UPDOWN_GetThousandSep();
00337     int start = len % 3;
00338 
00339     memcpy(tmp, txt, sizeof(txt));
00340     if (start == 0) start = 3;
00341     dst += start;
00342     src += start;
00343         for (len=0; *src; len++) {
00344         if (len % 3 == 0) *dst++ = sep;
00345         *dst++ = *src++;
00346         }
00347         *dst = 0;
00348     }
00349 
00350     /* if nothing changed exit earlier */
00351     GetWindowTextW(infoPtr->Buddy, txt_old, sizeof(txt_old)/sizeof(WCHAR));
00352     if (lstrcmpiW(txt_old, txt) == 0) return 0;
00353 
00354     return SetWindowTextW(infoPtr->Buddy, txt);
00355 }
00356 
00357 /***********************************************************************
00358  * UPDOWN_DrawBuddyBackground
00359  *
00360  * Draw buddy background for visual integration.
00361  */
00362 static BOOL UPDOWN_DrawBuddyBackground (const UPDOWN_INFO *infoPtr, HDC hdc)
00363 {
00364     RECT br;
00365     HTHEME buddyTheme = GetWindowTheme (infoPtr->Buddy);
00366     if (!buddyTheme) return FALSE;
00367 
00368     GetClientRect (infoPtr->Buddy, &br);
00369     MapWindowPoints (infoPtr->Buddy, infoPtr->Self, (POINT*)&br, 2);
00370     /* FIXME: take disabled etc. into account */
00371     DrawThemeBackground (buddyTheme, hdc, 0, 0, &br, NULL);
00372     return TRUE;
00373 }
00374 
00375 /***********************************************************************
00376  * UPDOWN_Draw
00377  *
00378  * Draw the arrows. The background need not be erased.
00379  */
00380 static LRESULT UPDOWN_Draw (const UPDOWN_INFO *infoPtr, HDC hdc)
00381 {
00382     BOOL uPressed, uHot, dPressed, dHot;
00383     RECT rect;
00384     HTHEME theme = GetWindowTheme (infoPtr->Self);
00385     int uPart = 0, uState = 0, dPart = 0, dState = 0;
00386     BOOL needBuddyBg = FALSE;
00387 
00388     uPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR);
00389     uHot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
00390     dPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR);
00391     dHot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
00392     if (theme) {
00393         uPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_UPHORZ : SPNP_UP;
00394         uState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED 
00395             : (uPressed ? DNS_PRESSED : (uHot ? DNS_HOT : DNS_NORMAL));
00396         dPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_DOWNHORZ : SPNP_DOWN;
00397         dState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED 
00398             : (dPressed ? DNS_PRESSED : (dHot ? DNS_HOT : DNS_NORMAL));
00399         needBuddyBg = IsWindow (infoPtr->Buddy)
00400             && (IsThemeBackgroundPartiallyTransparent (theme, uPart, uState)
00401               || IsThemeBackgroundPartiallyTransparent (theme, dPart, dState));
00402     }
00403 
00404     /* Draw the common border between ourselves and our buddy */
00405     if (UPDOWN_HasBuddyBorder(infoPtr) || needBuddyBg) {
00406         if (!theme || !UPDOWN_DrawBuddyBackground (infoPtr, hdc)) {
00407             GetClientRect(infoPtr->Self, &rect);
00408         DrawEdge(hdc, &rect, EDGE_SUNKEN,
00409              BF_BOTTOM | BF_TOP |
00410              (infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT));
00411         }
00412     }
00413 
00414     /* Draw the incr button */
00415     UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR);
00416     if (theme) {
00417         DrawThemeBackground(theme, hdc, uPart, uState, &rect, NULL);
00418     } else {
00419         DrawFrameControl(hdc, &rect, DFC_SCROLL,
00420             (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) |
00421             ((infoPtr->dwStyle & UDS_HOTTRACK) && uHot ? DFCS_HOT : 0) |
00422             (uPressed ? DFCS_PUSHED : 0) |
00423             (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
00424     }
00425 
00426     /* Draw the decr button */
00427     UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR);
00428     if (theme) {
00429         DrawThemeBackground(theme, hdc, dPart, dState, &rect, NULL);
00430     } else {
00431         DrawFrameControl(hdc, &rect, DFC_SCROLL,
00432             (infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) |
00433             ((infoPtr->dwStyle & UDS_HOTTRACK) && dHot ? DFCS_HOT : 0) |
00434             (dPressed ? DFCS_PUSHED : 0) |
00435             (infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
00436     }
00437 
00438     return 0;
00439 }
00440 
00441 /***********************************************************************
00442  * UPDOWN_Paint
00443  *
00444  * Asynchronous drawing (must ONLY be used in WM_PAINT).
00445  * Calls UPDOWN_Draw.
00446  */
00447 static LRESULT UPDOWN_Paint (const UPDOWN_INFO *infoPtr, HDC hdc)
00448 {
00449     PAINTSTRUCT ps;
00450     if (hdc) return UPDOWN_Draw (infoPtr, hdc);
00451     hdc = BeginPaint (infoPtr->Self, &ps);
00452     UPDOWN_Draw (infoPtr, hdc);
00453     EndPaint (infoPtr->Self, &ps);
00454     return 0;
00455 }
00456 
00457 /***********************************************************************
00458  * UPDOWN_KeyPressed
00459  *
00460  * Handle key presses (up & down) when we have to do so
00461  */
00462 static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key)
00463 {
00464     int arrow, accel;
00465 
00466     if (key == VK_UP) arrow = FLAG_INCR;
00467     else if (key == VK_DOWN) arrow = FLAG_DECR;
00468     else return 1;
00469 
00470     UPDOWN_GetBuddyInt (infoPtr);
00471     infoPtr->Flags &= ~FLAG_ARROW;
00472     infoPtr->Flags |= FLAG_PRESSED | arrow;
00473     InvalidateRect (infoPtr->Self, NULL, FALSE);
00474     SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0);
00475     accel = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1;
00476     UPDOWN_DoAction (infoPtr, accel, arrow);
00477     return 0;
00478 }
00479 
00480 /***********************************************************************
00481  * UPDOWN_SetRange
00482  *
00483  * Handle UDM_SETRANGE, UDM_SETRANGE32
00484  *
00485  * FIXME: handle Max == Min properly:
00486  *        - arrows should be disabled (without WS_DISABLED set),
00487  *          visually they can't be pressed and don't respond;
00488  *        - all input messages should still pass in.
00489  */
00490 static LRESULT UPDOWN_SetRange(UPDOWN_INFO *infoPtr, INT Max, INT Min)
00491 {
00492     infoPtr->MaxVal = Max;
00493     infoPtr->MinVal = Min;
00494 
00495     TRACE("UpDown Ctrl new range(%d to %d), hwnd=%p\n",
00496            infoPtr->MinVal, infoPtr->MaxVal, infoPtr->Self);
00497 
00498     return 0;
00499 }
00500 
00501 /***********************************************************************
00502  * UPDOWN_MouseWheel
00503  *
00504  * Handle mouse wheel scrolling
00505  */
00506 static LRESULT UPDOWN_MouseWheel(UPDOWN_INFO *infoPtr, WPARAM wParam)
00507 {
00508     int iWheelDelta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
00509 
00510     if (wParam & (MK_SHIFT | MK_CONTROL))
00511         return 0;
00512 
00513     if (iWheelDelta != 0)
00514     {
00515         UPDOWN_GetBuddyInt(infoPtr);
00516         UPDOWN_DoAction(infoPtr, abs(iWheelDelta), iWheelDelta > 0 ? FLAG_INCR : FLAG_DECR);
00517     }
00518 
00519     return 1;
00520 }
00521 
00522 
00523 /***********************************************************************
00524  * UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy
00525  *                           control.
00526  */
00527 static LRESULT CALLBACK
00528 UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
00529                           UINT_PTR uId, DWORD_PTR ref_data)
00530 {
00531     UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr((HWND)ref_data);
00532 
00533     TRACE("hwnd=%p, uMsg=%04x, wParam=%08lx, lParam=%08lx\n",
00534           hwnd, uMsg, wParam, lParam);
00535 
00536     switch(uMsg)
00537     {
00538     case WM_KEYDOWN:
00539     UPDOWN_KeyPressed(infoPtr, (int)wParam);
00540     if ((wParam == VK_UP) || (wParam == VK_DOWN)) return 0;
00541     break;
00542 
00543     case WM_MOUSEWHEEL:
00544     UPDOWN_MouseWheel(infoPtr, (int)wParam);
00545     break;
00546 
00547     default:
00548     break;
00549     }
00550 
00551     return DefSubclassProc(hwnd, uMsg, wParam, lParam);
00552 }
00553 
00554 /***********************************************************************
00555  *           UPDOWN_SetBuddy
00556  *
00557  * Sets bud as a new Buddy.
00558  * Then, it should subclass the buddy
00559  * If window has the UDS_ARROWKEYS, it subclasses the buddy window to
00560  * process the UP/DOWN arrow keys.
00561  * If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style
00562  * the size/pos of the buddy and the control are adjusted accordingly.
00563  */
00564 static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud)
00565 {
00566     RECT  budRect;  /* new coord for the buddy */
00567     int   x, width;  /* new x position and width for the up-down */
00568     WCHAR buddyClass[40];
00569     HWND ret;
00570 
00571     TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud);
00572 
00573     ret = infoPtr->Buddy;
00574 
00575     /* there is already a buddy assigned */
00576     if (infoPtr->Buddy) RemoveWindowSubclass(infoPtr->Buddy, UPDOWN_Buddy_SubclassProc,
00577                                              BUDDY_SUBCLASSID);
00578     if (!IsWindow(bud)) bud = NULL;
00579 
00580     /* Store buddy window handle */
00581     infoPtr->Buddy = bud;
00582 
00583     if(bud) {
00584         /* Store buddy window class type */
00585         infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN;
00586         if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) {
00587             if (lstrcmpiW(buddyClass, WC_EDITW) == 0)
00588                 infoPtr->BuddyType = BUDDY_TYPE_EDIT;
00589             else if (lstrcmpiW(buddyClass, WC_LISTBOXW) == 0)
00590                 infoPtr->BuddyType = BUDDY_TYPE_LISTBOX;
00591         }
00592 
00593         if (infoPtr->dwStyle & UDS_ARROWKEYS)
00594             SetWindowSubclass(bud, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID,
00595                               (DWORD_PTR)infoPtr->Self);
00596 
00597         /* Get the rect of the buddy relative to its parent */
00598         GetWindowRect(infoPtr->Buddy, &budRect);
00599         MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2);
00600 
00601         /* now do the positioning */
00602         if  (infoPtr->dwStyle & UDS_ALIGNLEFT) {
00603             x  = budRect.left;
00604             budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP;
00605         } else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) {
00606             budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP;
00607             x  = budRect.right+DEFAULT_XSEP;
00608         } else {
00609             /* nothing to do */
00610             return ret;
00611         }
00612 
00613         /* first adjust the buddy to accommodate the up/down */
00614         SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
00615                      budRect.right  - budRect.left, budRect.bottom - budRect.top,
00616                      SWP_NOACTIVATE|SWP_NOZORDER);
00617 
00618         /* now position the up/down */
00619         /* Since the UDS_ALIGN* flags were used, */
00620         /* we will pick the position and size of the window. */
00621         width = DEFAULT_WIDTH;
00622 
00623         /*
00624          * If the updown has a buddy border, it has to overlap with the buddy
00625          * to look as if it is integrated with the buddy control.
00626          * We nudge the control or change its size to overlap.
00627          */
00628         if (UPDOWN_HasBuddyBorder(infoPtr)) {
00629             if(infoPtr->dwStyle & UDS_ALIGNLEFT)
00630                 width += DEFAULT_BUDDYBORDER;
00631             else
00632                 x -= DEFAULT_BUDDYBORDER;
00633         }
00634 
00635         SetWindowPos(infoPtr->Self, 0, x,
00636                      budRect.top - DEFAULT_ADDTOP, width,
00637                      budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT,
00638                      SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
00639     } else {
00640         RECT rect;
00641         GetWindowRect(infoPtr->Self, &rect);
00642         MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2);
00643         SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top,
00644                      SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
00645     }
00646     return ret;
00647 }
00648 
00649 /***********************************************************************
00650  *           UPDOWN_DoAction
00651  *
00652  * This function increments/decrements the CurVal by the
00653  * 'delta' amount according to the 'action' flag which can be a
00654  * combination of FLAG_INCR and FLAG_DECR
00655  * It notifies the parent as required.
00656  * It handles wrapping and non-wrapping correctly.
00657  * It is assumed that delta>0
00658  */
00659 static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action)
00660 {
00661     NM_UPDOWN ni;
00662 
00663     TRACE("%d by %d\n", action, delta);
00664 
00665     /* check if we can do the modification first */
00666     delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
00667     if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0;
00668 
00669     TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta);
00670 
00671     /* We must notify parent now to obtain permission */
00672     ni.iPos = infoPtr->CurVal;
00673     ni.iDelta = delta;
00674     ni.hdr.hwndFrom = infoPtr->Self;
00675     ni.hdr.idFrom   = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
00676     ni.hdr.code = UDN_DELTAPOS;
00677     if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, ni.hdr.idFrom, (LPARAM)&ni)) {
00678         /* Parent said: OK to adjust */
00679 
00680         /* Now adjust value with (maybe new) delta */
00681         if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) {
00682             TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta);
00683 
00684             /* Now take care about our buddy */
00685             UPDOWN_SetBuddyInt (infoPtr);
00686         }
00687     }
00688 
00689     /* Also, notify it. This message is sent in any case. */
00690     SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
00691           MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self);
00692 }
00693 
00694 /***********************************************************************
00695  *           UPDOWN_IsEnabled
00696  *
00697  * Returns TRUE if it is enabled as well as its buddy (if any)
00698  *         FALSE otherwise
00699  */
00700 static BOOL UPDOWN_IsEnabled (const UPDOWN_INFO *infoPtr)
00701 {
00702     if (!IsWindowEnabled(infoPtr->Self))
00703         return FALSE;
00704     if(infoPtr->Buddy)
00705         return IsWindowEnabled(infoPtr->Buddy);
00706     return TRUE;
00707 }
00708 
00709 /***********************************************************************
00710  *           UPDOWN_CancelMode
00711  *
00712  * Deletes any timers, releases the mouse and does  redraw if necessary.
00713  * If the control is not in "capture" mode, it does nothing.
00714  * If the control was not in cancel mode, it returns FALSE.
00715  * If the control was in cancel mode, it returns TRUE.
00716  */
00717 static BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr)
00718 {
00719     if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE;
00720 
00721     KillTimer (infoPtr->Self, TIMER_AUTOREPEAT);
00722     KillTimer (infoPtr->Self, TIMER_ACCEL);
00723     KillTimer (infoPtr->Self, TIMER_AUTOPRESS);
00724 
00725     if (GetCapture() == infoPtr->Self) {
00726     NMHDR hdr;
00727     hdr.hwndFrom = infoPtr->Self;
00728     hdr.idFrom   = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
00729     hdr.code = NM_RELEASEDCAPTURE;
00730     SendMessageW(infoPtr->Notify, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
00731     ReleaseCapture();
00732     }
00733 
00734     infoPtr->Flags &= ~FLAG_PRESSED;
00735     InvalidateRect (infoPtr->Self, NULL, FALSE);
00736 
00737     return TRUE;
00738 }
00739 
00740 /***********************************************************************
00741  *           UPDOWN_HandleMouseEvent
00742  *
00743  * Handle a mouse event for the updown.
00744  * 'pt' is the location of the mouse event in client or
00745  * windows coordinates.
00746  */
00747 static void UPDOWN_HandleMouseEvent (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y)
00748 {
00749     POINT pt = { x, y };
00750     RECT rect;
00751     int temp, arrow;
00752     TRACKMOUSEEVENT tme;
00753 
00754     TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt));
00755 
00756     switch(msg)
00757     {
00758         case WM_LBUTTONDOWN:  /* Initialise mouse tracking */
00759 
00760             /* If the buddy is an edit, will set focus to it */
00761         if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy);
00762 
00763             /* Now see which one is the 'active' arrow */
00764             arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
00765 
00766             /* Update the flags if we are in/out */
00767             infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
00768             if (arrow)
00769                 infoPtr->Flags |= FLAG_MOUSEIN | arrow;
00770             else
00771                 if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
00772 
00773         if (infoPtr->Flags & FLAG_ARROW) {
00774 
00775                 /* Update the CurVal if necessary */
00776                 UPDOWN_GetBuddyInt (infoPtr);
00777 
00778                 /* Set up the correct flags */
00779                 infoPtr->Flags |= FLAG_PRESSED;
00780 
00781                 /* repaint the control */
00782             InvalidateRect (infoPtr->Self, NULL, FALSE);
00783 
00784                 /* process the click */
00785         temp = (infoPtr->AccelCount && infoPtr->AccelVect) ? infoPtr->AccelVect[0].nInc : 1;
00786                 UPDOWN_DoAction (infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
00787 
00788                 /* now capture all mouse messages */
00789                 SetCapture (infoPtr->Self);
00790 
00791                 /* and startup the first timer */
00792                 SetTimer(infoPtr->Self, TIMER_AUTOREPEAT, INITIAL_DELAY, 0);
00793         }
00794             break;
00795 
00796     case WM_MOUSEMOVE:
00797             /* save the flags to see if any got modified */
00798             temp = infoPtr->Flags;
00799 
00800             /* Now see which one is the 'active' arrow */
00801             arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
00802 
00803             /* Update the flags if we are in/out */
00804         infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
00805             if(arrow) {
00806             infoPtr->Flags |=  FLAG_MOUSEIN | arrow;
00807             } else {
00808             if(infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
00809             }
00810 
00811             /* If state changed, redraw the control */
00812             if(temp != infoPtr->Flags)
00813          InvalidateRect (infoPtr->Self, NULL, FALSE);
00814 
00815             /* Set up tracking so the mousein flags can be reset when the 
00816              * mouse leaves the control */
00817             tme.cbSize = sizeof( tme );
00818             tme.dwFlags = TME_LEAVE;
00819             tme.hwndTrack = infoPtr->Self;
00820             TrackMouseEvent (&tme);
00821 
00822             break;
00823         case WM_MOUSELEAVE:
00824         infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
00825             InvalidateRect (infoPtr->Self, NULL, FALSE);
00826             break;
00827 
00828     default:
00829         ERR("Impossible case (msg=%x)!\n", msg);
00830     }
00831 
00832 }
00833 
00834 /***********************************************************************
00835  *           UpDownWndProc
00836  */
00837 static LRESULT WINAPI UpDownWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
00838 {
00839     UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr (hwnd);
00840     static const WCHAR themeClass[] = {'S','p','i','n',0};
00841     HTHEME theme;
00842 
00843     TRACE("hwnd=%p msg=%04x wparam=%08lx lparam=%08lx\n", hwnd, message, wParam, lParam);
00844 
00845     if (!infoPtr && (message != WM_CREATE))
00846         return DefWindowProcW (hwnd, message, wParam, lParam);
00847 
00848     switch(message)
00849     {
00850         case WM_CREATE:
00851         {
00852         CREATESTRUCTW *pcs = (CREATESTRUCTW*)lParam;
00853 
00854             infoPtr = Alloc (sizeof(UPDOWN_INFO));
00855         SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
00856 
00857         /* initialize the info struct */
00858         infoPtr->Self = hwnd;
00859         infoPtr->Notify  = pcs->hwndParent;
00860         infoPtr->dwStyle = pcs->style;
00861         infoPtr->AccelCount = 0;
00862         infoPtr->AccelVect = 0;
00863         infoPtr->AccelIndex = -1;
00864         infoPtr->CurVal = 0;
00865         infoPtr->MinVal = 100;
00866         infoPtr->MaxVal = 0;
00867         infoPtr->Base  = 10; /* Default to base 10  */
00868         infoPtr->Buddy = 0;  /* No buddy window yet */
00869         infoPtr->Flags = (infoPtr->dwStyle & UDS_SETBUDDYINT) ? FLAG_BUDDYINT : 0;
00870 
00871             SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle & ~WS_BORDER);
00872         if (!(infoPtr->dwStyle & UDS_HORZ))
00873             SetWindowPos (hwnd, NULL, 0, 0, DEFAULT_WIDTH, pcs->cy,
00874                           SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
00875 
00876             /* Do we pick the buddy win ourselves? */
00877         if (infoPtr->dwStyle & UDS_AUTOBUDDY)
00878         UPDOWN_SetBuddy (infoPtr, GetWindow (hwnd, GW_HWNDPREV));
00879 
00880         OpenThemeData (hwnd, themeClass);
00881 
00882         TRACE("UpDown Ctrl creation, hwnd=%p\n", hwnd);
00883         }
00884         break;
00885 
00886     case WM_DESTROY:
00887         Free (infoPtr->AccelVect);
00888 
00889         if (infoPtr->Buddy)
00890            RemoveWindowSubclass(infoPtr->Buddy, UPDOWN_Buddy_SubclassProc,
00891                                 BUDDY_SUBCLASSID);
00892         Free (infoPtr);
00893         SetWindowLongPtrW (hwnd, 0, 0);
00894             theme = GetWindowTheme (hwnd);
00895             CloseThemeData (theme);
00896         TRACE("UpDown Ctrl destruction, hwnd=%p\n", hwnd);
00897         break;
00898 
00899     case WM_ENABLE:
00900         if (wParam) {
00901         infoPtr->dwStyle &= ~WS_DISABLED;
00902         } else {
00903         infoPtr->dwStyle |= WS_DISABLED;
00904             UPDOWN_CancelMode (infoPtr);
00905         }
00906         InvalidateRect (infoPtr->Self, NULL, FALSE);
00907         break;
00908 
00909         case WM_STYLECHANGED:
00910             if (wParam == GWL_STYLE) {
00911                 infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew;
00912             InvalidateRect (infoPtr->Self, NULL, FALSE);
00913             }
00914             break;
00915 
00916         case WM_THEMECHANGED:
00917             theme = GetWindowTheme (hwnd);
00918             CloseThemeData (theme);
00919             OpenThemeData (hwnd, themeClass);
00920             InvalidateRect (hwnd, NULL, FALSE);
00921             break;
00922 
00923     case WM_TIMER:
00924        /* is this the auto-press timer? */
00925        if(wParam == TIMER_AUTOPRESS) {
00926         KillTimer(hwnd, TIMER_AUTOPRESS);
00927         infoPtr->Flags &= ~(FLAG_PRESSED | FLAG_ARROW);
00928         InvalidateRect(infoPtr->Self, NULL, FALSE);
00929        }
00930 
00931        /* if initial timer, kill it and start the repeat timer */
00932        if(wParam == TIMER_AUTOREPEAT) {
00933         INT delay;
00934 
00935         KillTimer(hwnd, TIMER_AUTOREPEAT);
00936         /* if no accel info given, used default timer */
00937         if(infoPtr->AccelCount==0 || infoPtr->AccelVect==0) {
00938             infoPtr->AccelIndex = -1;
00939             delay = REPEAT_DELAY;
00940         } else {
00941             infoPtr->AccelIndex = 0; /* otherwise, use it */
00942             delay = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
00943         }
00944         SetTimer(hwnd, TIMER_ACCEL, delay, 0);
00945             }
00946 
00947         /* now, if the mouse is above us, do the thing...*/
00948         if(infoPtr->Flags & FLAG_MOUSEIN) {
00949         int temp;
00950 
00951         temp = infoPtr->AccelIndex == -1 ? 1 : infoPtr->AccelVect[infoPtr->AccelIndex].nInc;
00952         UPDOWN_DoAction(infoPtr, temp, infoPtr->Flags & FLAG_ARROW);
00953 
00954         if(infoPtr->AccelIndex != -1 && infoPtr->AccelIndex < infoPtr->AccelCount-1) {
00955             KillTimer(hwnd, TIMER_ACCEL);
00956             infoPtr->AccelIndex++; /* move to the next accel info */
00957             temp = infoPtr->AccelVect[infoPtr->AccelIndex].nSec * 1000 + 1;
00958             /* make sure we have at least 1ms intervals */
00959             SetTimer(hwnd, TIMER_ACCEL, temp, 0);
00960         }
00961         }
00962         break;
00963 
00964     case WM_CANCELMODE:
00965       return UPDOWN_CancelMode (infoPtr);
00966 
00967     case WM_LBUTTONUP:
00968         if (GetCapture() != infoPtr->Self) break;
00969 
00970         if ( (infoPtr->Flags & FLAG_MOUSEIN) &&
00971          (infoPtr->Flags & FLAG_ARROW) ) {
00972 
00973             SendMessageW( infoPtr->Notify,
00974                   (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
00975                           MAKELONG(SB_ENDSCROLL, infoPtr->CurVal),
00976                   (LPARAM)hwnd);
00977         if (UPDOWN_IsBuddyEdit(infoPtr))
00978             SendMessageW(infoPtr->Buddy, EM_SETSEL, 0, MAKELONG(0, -1));
00979         }
00980         UPDOWN_CancelMode(infoPtr);
00981         break;
00982 
00983     case WM_LBUTTONDOWN:
00984     case WM_MOUSEMOVE:
00985         case WM_MOUSELEAVE:
00986         if(UPDOWN_IsEnabled(infoPtr))
00987         UPDOWN_HandleMouseEvent (infoPtr, message, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
00988         break;
00989 
00990         case WM_MOUSEWHEEL:
00991             UPDOWN_MouseWheel(infoPtr, wParam);
00992             break;
00993 
00994     case WM_KEYDOWN:
00995         if((infoPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(infoPtr))
00996         return UPDOWN_KeyPressed(infoPtr, (int)wParam);
00997         break;
00998 
00999     case WM_PRINTCLIENT:
01000     case WM_PAINT:
01001         return UPDOWN_Paint (infoPtr, (HDC)wParam);
01002 
01003     case UDM_GETACCEL:
01004         if (wParam==0 && lParam==0) return infoPtr->AccelCount;
01005         if (wParam && lParam) {
01006         int temp = min(infoPtr->AccelCount, wParam);
01007             memcpy((void *)lParam, infoPtr->AccelVect, temp*sizeof(UDACCEL));
01008             return temp;
01009             }
01010         return 0;
01011 
01012     case UDM_SETACCEL:
01013     {
01014         TRACE("UDM_SETACCEL\n");
01015 
01016         if(infoPtr->AccelVect) {
01017         Free (infoPtr->AccelVect);
01018         infoPtr->AccelCount = 0;
01019         infoPtr->AccelVect  = 0;
01020             }
01021         if(wParam==0) return TRUE;
01022         infoPtr->AccelVect = Alloc (wParam*sizeof(UDACCEL));
01023         if(infoPtr->AccelVect == 0) return FALSE;
01024         memcpy(infoPtr->AccelVect, (void*)lParam, wParam*sizeof(UDACCEL));
01025             infoPtr->AccelCount = wParam;
01026 
01027             if (TRACE_ON(updown))
01028             {
01029                 INT i;
01030 
01031                 for (i = 0; i < wParam; i++)
01032                     TRACE("%d: nSec %u nInc %u\n", i,
01033                         infoPtr->AccelVect[i].nSec, infoPtr->AccelVect[i].nInc);
01034             }
01035 
01036             return TRUE;
01037     }
01038     case UDM_GETBASE:
01039         return infoPtr->Base;
01040 
01041     case UDM_SETBASE:
01042         TRACE("UpDown Ctrl new base(%ld), hwnd=%p\n", wParam, hwnd);
01043         if (wParam==10 || wParam==16) {
01044         WPARAM old_base = infoPtr->Base;
01045         infoPtr->Base = wParam;
01046 
01047         if (old_base != infoPtr->Base)
01048             UPDOWN_SetBuddyInt(infoPtr);
01049 
01050         return old_base;
01051         }
01052         break;
01053 
01054     case UDM_GETBUDDY:
01055         return (LRESULT)infoPtr->Buddy;
01056 
01057     case UDM_SETBUDDY:
01058         return (LRESULT)UPDOWN_SetBuddy (infoPtr, (HWND)wParam);
01059 
01060     case UDM_GETPOS:
01061     {
01062         BOOL ret = UPDOWN_GetBuddyInt (infoPtr);
01063         return MAKELONG(infoPtr->CurVal, ret ? 0 : 1);
01064     }
01065     case UDM_SETPOS:
01066     {
01067         int temp = (short)LOWORD(lParam);
01068 
01069         TRACE("UpDown Ctrl new value(%d), hwnd=%p\n", temp, hwnd);
01070         if(!UPDOWN_InBounds(infoPtr, temp)) {
01071         if(temp < infoPtr->MinVal) temp = infoPtr->MinVal;
01072         if(temp > infoPtr->MaxVal) temp = infoPtr->MaxVal;
01073         }
01074         wParam = infoPtr->CurVal;
01075         infoPtr->CurVal = temp;
01076         UPDOWN_SetBuddyInt (infoPtr);
01077         return wParam;            /* return prev value */
01078     }
01079     case UDM_GETRANGE:
01080         return MAKELONG(infoPtr->MaxVal, infoPtr->MinVal);
01081 
01082     case UDM_SETRANGE:
01083         /* we must have:
01084         UD_MINVAL <= Max <= UD_MAXVAL
01085         UD_MINVAL <= Min <= UD_MAXVAL
01086         |Max-Min| <= UD_MAXVAL */
01087         UPDOWN_SetRange(infoPtr, (short)lParam, (short)HIWORD(lParam));
01088         break;
01089 
01090     case UDM_GETRANGE32:
01091         if (wParam) *(LPINT)wParam = infoPtr->MinVal;
01092         if (lParam) *(LPINT)lParam = infoPtr->MaxVal;
01093         break;
01094 
01095     case UDM_SETRANGE32:
01096         UPDOWN_SetRange(infoPtr, (INT)lParam, (INT)wParam);
01097         break;
01098 
01099     case UDM_GETPOS32:
01100     {
01101         BOOL ret = UPDOWN_GetBuddyInt (infoPtr);
01102         if ((LPBOOL)lParam) *((LPBOOL)lParam) = !ret;
01103         return infoPtr->CurVal;
01104     }
01105     case UDM_SETPOS32:
01106     {
01107         int temp;
01108 
01109         if(!UPDOWN_InBounds(infoPtr, (int)lParam)) {
01110         if((int)lParam < infoPtr->MinVal) lParam = infoPtr->MinVal;
01111         if((int)lParam > infoPtr->MaxVal) lParam = infoPtr->MaxVal;
01112         }
01113         temp = infoPtr->CurVal;         /* save prev value   */
01114         infoPtr->CurVal = (int)lParam;  /* set the new value */
01115         UPDOWN_SetBuddyInt (infoPtr);
01116         return temp;                    /* return prev value */
01117     }
01118     case UDM_GETUNICODEFORMAT:
01119         /* we lie a bit here, we're always using Unicode internally */
01120         return infoPtr->UnicodeFormat;
01121 
01122     case UDM_SETUNICODEFORMAT:
01123     {
01124         /* do we really need to honour this flag? */
01125         int temp = infoPtr->UnicodeFormat;
01126         infoPtr->UnicodeFormat = (BOOL)wParam;
01127         return temp;
01128     }
01129     default:
01130         if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message))
01131         ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam);
01132         return DefWindowProcW (hwnd, message, wParam, lParam);
01133     }
01134 
01135     return 0;
01136 }
01137 
01138 /***********************************************************************
01139  *      UPDOWN_Register [Internal]
01140  *
01141  * Registers the updown window class.
01142  */
01143 void UPDOWN_Register(void)
01144 {
01145     WNDCLASSW wndClass;
01146 
01147     ZeroMemory( &wndClass, sizeof( WNDCLASSW ) );
01148     wndClass.style         = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW;
01149     wndClass.lpfnWndProc   = UpDownWindowProc;
01150     wndClass.cbClsExtra    = 0;
01151     wndClass.cbWndExtra    = sizeof(UPDOWN_INFO*);
01152     wndClass.hCursor       = LoadCursorW( 0, (LPWSTR)IDC_ARROW );
01153     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
01154     wndClass.lpszClassName = UPDOWN_CLASSW;
01155 
01156     RegisterClassW( &wndClass );
01157 }
01158 
01159 
01160 /***********************************************************************
01161  *      UPDOWN_Unregister   [Internal]
01162  *
01163  * Unregisters the updown window class.
01164  */
01165 void UPDOWN_Unregister (void)
01166 {
01167     UnregisterClassW (UPDOWN_CLASSW, NULL);
01168 }

Generated on Sat May 26 2012 04:21:41 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.