Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenupdown.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
1.7.6.1
|