| /* |
| * Updown control |
| * |
| * Copyright 1997 Dimitrie O. Paun |
| * |
| * TODO: |
| * - subclass the buddy window (in UPDOWN_SetBuddy) to process the |
| * arrow keys |
| * - I am not sure about the default values for the Min, Max, Pos |
| * (in the UPDOWN_INFO the fields: MinVal, MaxVal, CurVal) |
| * - I think I do not handle correctly the WS_BORDER style. |
| * Testing: |
| * Not much. The following have not been tested at all: |
| * - horizontal arrows |
| * - listbox as buddy window |
| * - acceleration |
| * - base 16 |
| * - UDS_ALIGNLEFT, ~UDS_WRAP |
| * - integers with thousand separators. |
| * 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. |
| * Problems: |
| * I do not like the arrows yet, I'll work more on them later on. |
| */ |
| |
| #include <stdlib.h> |
| #include <assert.h> |
| #include <string.h> |
| #include "windows.h" |
| #include "winnls.h" |
| #include "sysmetrics.h" |
| #include "updown.h" |
| #include "graphics.h" |
| #include "heap.h" |
| #include "win.h" |
| #include "debug.h" |
| |
| /* 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 */ |
| |
| |
| /* Work constants */ |
| |
| #define FLAG_INCR 0x01 |
| #define FLAG_DECR 0x02 |
| #define FLAG_MOUSEIN 0x04 |
| #define FLAG_CLICKED (FLAG_INCR | FLAG_DECR) |
| |
| #define TIMERID1 1 |
| #define TIMERID2 2 |
| |
| static int accelIndex = -1; |
| |
| #define UNKNOWN_PARAM(msg, wParam, lParam) WARN(updown, \ |
| "UpDown Ctrl: Unknown parameter(s) for message " #msg \ |
| "(%04x): wp=%04x lp=%08lx\n", msg, wParam, lParam); |
| |
| #define UPDOWN_GetInfoPtr(wndPtr) ((UPDOWN_INFO *)wndPtr->wExtra) |
| |
| /*********************************************************************** |
| * UPDOWN_InBounds |
| * Tests if a given value 'val' is between the Min&Max limits |
| */ |
| static BOOL32 UPDOWN_InBounds(WND *wndPtr, int val) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| |
| 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. |
| */ |
| static BOOL32 UPDOWN_OffsetVal(WND *wndPtr, int delta) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| |
| /* check if we can do the modification first */ |
| if(!UPDOWN_InBounds(wndPtr, infoPtr->CurVal+delta)){ |
| if(wndPtr->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; |
| } |
| |
| infoPtr->CurVal += delta; |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * 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) |
| * |
| */ |
| static void UPDOWN_GetArrowRect(WND *wndPtr, RECT32 *rect, BOOL32 incr) |
| { |
| int len; /* will hold the width or height */ |
| |
| GetClientRect32(wndPtr->hwndSelf, rect); |
| |
| if (wndPtr->dwStyle & UDS_HORZ) { |
| len = rect->right - rect->left; /* compute the width */ |
| if (incr) |
| rect->left = len/2+1; |
| else |
| rect->right = len/2; |
| } |
| else { |
| len = rect->bottom - rect->top; /* compute the height */ |
| if (incr) |
| rect->bottom = len/2; |
| else |
| rect->top = len/2+1; |
| } |
| } |
| |
| /*********************************************************************** |
| * 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. |
| */ |
| static int UPDOWN_GetArrowFromPoint(WND *wndPtr, RECT32 *rect, POINT32 pt) |
| { |
| UPDOWN_GetArrowRect(wndPtr, rect, TRUE); |
| if(PtInRect32(rect, pt)) |
| return TRUE; |
| |
| UPDOWN_GetArrowRect(wndPtr, rect, FALSE); |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * UPDOWN_GetThousandSep |
| * Returns the thousand sep. If an error occurs, it returns ','. |
| */ |
| static char UPDOWN_GetThousandSep() |
| { |
| char sep[2]; |
| |
| if(GetLocaleInfo32A(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, |
| sep, sizeof(sep)) != 1) |
| return ','; |
| |
| return sep[0]; |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_GetBuddyInt |
| * Tries to read the pos from the buddy window and if it succeeds, |
| * it stores it in the control's CurVal |
| * returns: |
| * TRUE - if it read the integer from the buddy successfully |
| * FALSE - if an error occured |
| */ |
| static BOOL32 UPDOWN_GetBuddyInt(WND *wndPtr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| char txt[20], sep, *src, *dst; |
| int newVal; |
| |
| if (!IsWindow32(infoPtr->Buddy)) |
| return FALSE; |
| |
| /*if the buddy is a list window, we must set curr index */ |
| if(WIDGETS_IsControl32(WIN_FindWndPtr(infoPtr->Buddy), BIC32_LISTBOX)){ |
| newVal = SendMessage32A(infoPtr->Buddy, LB_GETCARETINDEX32, 0, 0); |
| if(newVal < 0) |
| return FALSE; |
| } |
| else{ |
| /* we have a regural window, so will get the text */ |
| if (!GetWindowText32A(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(wndPtr, newVal)) |
| return FALSE; |
| |
| TRACE(updown, "new value(%d) read from buddy (old=%d)\n", |
| newVal, infoPtr->CurVal); |
| } |
| |
| infoPtr->CurVal = newVal; |
| return TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * UPDOWN_SetBuddyInt |
| * 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 |
| */ |
| static BOOL32 UPDOWN_SetBuddyInt(WND *wndPtr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| char txt1[20], sep; |
| int len; |
| |
| if (!IsWindow32(infoPtr->Buddy)) |
| return FALSE; |
| |
| TRACE(updown, "set new value(%d) to buddy.\n", |
| infoPtr->CurVal); |
| |
| /*if the buddy is a list window, we must set curr index */ |
| if(WIDGETS_IsControl32(WIN_FindWndPtr(infoPtr->Buddy), BIC32_LISTBOX)){ |
| SendMessage32A(infoPtr->Buddy, LB_SETCURSEL32, infoPtr->CurVal, 0); |
| } |
| else{ /* Regural window, so set caption to the number */ |
| len = sprintf(txt1, (infoPtr->Base==16) ? "%X" : "%d", infoPtr->CurVal); |
| |
| sep = UPDOWN_GetThousandSep(); |
| |
| if (!(wndPtr->dwStyle & UDS_NOTHOUSANDS)) { |
| char txt2[20], *src = txt1, *dst = txt2; |
| if(len%3 > 0){ |
| strncpy(dst, src, len%3); |
| dst += len%3; |
| src += len%3; |
| } |
| for(len=0; *src; len++,src++){ |
| if(len%3==0) |
| *dst++ = sep; |
| *dst++ = *src++; |
| } |
| *dst = 0; /* null terminate it */ |
| strcpy(txt1, txt2); /* move it to the proper place */ |
| } |
| SetWindowText32A(infoPtr->Buddy, txt1); |
| } |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_Paint |
| * Draw the arrows. The background need not be erased. |
| */ |
| static void UPDOWN_Paint(WND *wndPtr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| PAINTSTRUCT32 ps; |
| BOOL32 prssed; |
| RECT32 rect; |
| HDC32 hdc; |
| |
| /* start painting the button */ |
| hdc = BeginPaint32( wndPtr->hwndSelf, &ps ); |
| |
| /* Draw the incr button */ |
| UPDOWN_GetArrowRect(wndPtr, &rect, TRUE); |
| prssed = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN); |
| DrawFrameControl32(hdc, &rect, DFC_SCROLL, |
| (wndPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLUP) | |
| (prssed ? DFCS_PUSHED : 0) | |
| (wndPtr->dwStyle&WS_DISABLED ? DFCS_INACTIVE : 0) ); |
| |
| /* Draw the space between the buttons */ |
| rect.top = rect.bottom; rect.bottom++; |
| DrawEdge32(hdc, &rect, 0, BF_MIDDLE); |
| |
| /* Draw the decr button */ |
| UPDOWN_GetArrowRect(wndPtr, &rect, FALSE); |
| prssed = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN); |
| DrawFrameControl32(hdc, &rect, DFC_SCROLL, |
| (wndPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLDOWN) | |
| (prssed ? DFCS_PUSHED : 0) | |
| (wndPtr->dwStyle&WS_DISABLED ? DFCS_INACTIVE : 0) ); |
| |
| |
| /* clean-up */ |
| EndPaint32( wndPtr->hwndSelf, &ps ); |
| } |
| |
| /*********************************************************************** |
| * 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 |
| * 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 BOOL32 UPDOWN_SetBuddy(WND *wndPtr, HWND32 hwndBud) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| RECT32 budRect; /* new coord for the buddy */ |
| int x; /* new x position and width for the up-down */ |
| |
| /* Is is a valid bud? */ |
| if(!IsWindow32(hwndBud)) |
| return FALSE; |
| |
| if(wndPtr->dwStyle & UDS_ARROWKEYS){ |
| FIXME(updown, "we need to subclass the buddy to process the arrow keys.\n"); |
| } |
| |
| /* do we need to do any adjustments? */ |
| if(!(wndPtr->dwStyle & (UDS_ALIGNLEFT | UDS_ALIGNRIGHT))) |
| return TRUE; |
| |
| /* Get the rect of the buddy relative to its parent */ |
| GetWindowRect32(infoPtr->Buddy, &budRect); |
| MapWindowPoints32(HWND_DESKTOP, GetParent32(infoPtr->Buddy), |
| (POINT32 *)(&budRect.left), 2); |
| |
| /* now do the positioning */ |
| if(wndPtr->dwStyle & UDS_ALIGNRIGHT){ |
| budRect.right -= DEFAULT_WIDTH+DEFAULT_XSEP; |
| x = budRect.right+DEFAULT_XSEP; |
| } |
| else{ /* UDS_ALIGNLEFT */ |
| x = budRect.left; |
| budRect.left += DEFAULT_WIDTH+DEFAULT_XSEP; |
| } |
| |
| /* first adjust the buddy to accomodate the up/down */ |
| SetWindowPos32(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. */ |
| SetWindowPos32(wndPtr->hwndSelf,0,x,budRect.top-DEFAULT_ADDTOP,DEFAULT_WIDTH, |
| (budRect.bottom-budRect.top)+DEFAULT_ADDTOP+DEFAULT_ADDBOT, |
| SWP_NOACTIVATE|SWP_NOZORDER); |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_DoAction |
| * |
| * This function increments/decrements the CurVal by the |
| * 'delta' amount according to the 'incr' flag |
| * It notifies the parent as required. |
| * It handles wraping and non-wraping correctly. |
| * It is assumed that delta>0 |
| */ |
| static void UPDOWN_DoAction(WND *wndPtr, int delta, BOOL32 incr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| int old_val = infoPtr->CurVal; |
| NM_UPDOWN ni; |
| |
| TRACE(updown, "%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); |
| if(!UPDOWN_OffsetVal(wndPtr, delta)) |
| return; |
| |
| /* so, if we can do the change, recompute delta and restore old value */ |
| delta = infoPtr->CurVal - old_val; |
| infoPtr->CurVal = old_val; |
| |
| /* We must notify parent now to obtain permission */ |
| ni.iPos = infoPtr->CurVal; |
| ni.iDelta = delta; |
| ni.hdr.hwndFrom = wndPtr->hwndSelf; |
| ni.hdr.idFrom = wndPtr->wIDmenu; |
| ni.hdr.code = UDN_DELTAPOS; |
| if(SendMessage32A(wndPtr->parent->hwndSelf, |
| WM_NOTIFY, wndPtr->wIDmenu, (LPARAM)&ni)) |
| return; /* we are not allowed to change */ |
| |
| /* Now adjust value with (maybe new) delta */ |
| if(!UPDOWN_OffsetVal(wndPtr, ni.iDelta)) |
| return; |
| |
| /* Now take care about our buddy */ |
| if(!IsWindow32(infoPtr->Buddy)) |
| return; /* Nothing else to do */ |
| |
| |
| if(wndPtr->dwStyle & UDS_SETBUDDYINT) |
| UPDOWN_SetBuddyInt(wndPtr); |
| |
| /* Also, notify it */ |
| /* FIXME: do we need to send the notification only if |
| we do not have the UDS_SETBUDDYINT style set? */ |
| SendMessage32A(infoPtr->Buddy, |
| wndPtr->dwStyle & UDS_HORZ ? WM_HSCROLL : WM_VSCROLL, |
| MAKELONG(incr ? SB_LINEUP : SB_LINEDOWN, infoPtr->CurVal), |
| wndPtr->hwndSelf); |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_IsEnabled |
| * |
| * Returns TRUE if it is enabled as well as its buddy (if any) |
| * FALSE otherwise |
| */ |
| static BOOL32 UPDOWN_IsEnabled(WND *wndPtr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| |
| if(wndPtr->dwStyle & WS_DISABLED) |
| return FALSE; |
| return IsWindowEnabled32(infoPtr->Buddy); |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_CancelMode |
| * |
| * 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 in cancel mode, it returns TRUE. |
| */ |
| static BOOL32 UPDOWN_CancelMode(WND *wndPtr) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| |
| /* if not in 'capture' mode, do nothing */ |
| if(!(infoPtr->Flags & FLAG_CLICKED)) |
| return FALSE; |
| |
| KillTimer32(wndPtr->hwndSelf, TIMERID1); /* kill all possible timers */ |
| KillTimer32(wndPtr->hwndSelf, TIMERID2); |
| |
| if(GetCapture32() == wndPtr->hwndSelf) /* let the mouse go */ |
| ReleaseCapture(); /* if we still have it */ |
| |
| infoPtr->Flags = 0; /* get rid of any flags */ |
| UPDOWN_Paint(wndPtr); /* redraw the control just in case */ |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_HandleMouseEvent |
| * |
| * Handle a mouse event for the updown. |
| * 'pt' is the location of the mouse event in client or |
| * windows coordinates. |
| */ |
| static void UPDOWN_HandleMouseEvent(WND *wndPtr, UINT32 msg, POINT32 pt) |
| { |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| RECT32 rect; |
| int temp; |
| |
| 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(WIDGETS_IsControl32(WIN_FindWndPtr(infoPtr->Buddy), BIC32_EDIT)) |
| SetFocus32(infoPtr->Buddy); |
| |
| /* Now see which one is the 'active' arrow */ |
| temp = UPDOWN_GetArrowFromPoint(wndPtr, &rect, pt); |
| |
| /* Update the CurVal if necessary */ |
| if(wndPtr->dwStyle & UDS_SETBUDDYINT) |
| UPDOWN_GetBuddyInt(wndPtr); |
| |
| /* Before we proceed, see if we can spin... */ |
| if(!(wndPtr->dwStyle & UDS_WRAP)) |
| if(( temp && infoPtr->CurVal==infoPtr->MaxVal) || |
| (!temp && infoPtr->CurVal==infoPtr->MinVal)) |
| return; |
| |
| /* Set up the correct flags */ |
| infoPtr->Flags = 0; |
| infoPtr->Flags |= temp ? FLAG_INCR : FLAG_DECR; |
| infoPtr->Flags |= FLAG_MOUSEIN; |
| |
| /* repaint the control */ |
| UPDOWN_Paint(wndPtr); |
| |
| /* process the click */ |
| UPDOWN_DoAction(wndPtr, 1, infoPtr->Flags & FLAG_INCR); |
| |
| /* now capture all mouse messages */ |
| SetCapture32(wndPtr->hwndSelf); |
| |
| /* and startup the first timer */ |
| SetTimer32(wndPtr->hwndSelf, 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(wndPtr, &rect, TRUE); |
| else |
| UPDOWN_GetArrowRect(wndPtr, &rect, FALSE); |
| |
| /* Update the flags if we are in/out */ |
| if(PtInRect32(&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_Paint(wndPtr); |
| break; |
| |
| default: |
| ERR(updown, "Impossible case!\n"); |
| } |
| |
| } |
| |
| /*********************************************************************** |
| * UpDownWndProc |
| */ |
| LRESULT WINAPI UpDownWindowProc(HWND32 hwnd, UINT32 message, WPARAM32 wParam, |
| LPARAM lParam) |
| { |
| WND *wndPtr = WIN_FindWndPtr(hwnd); |
| UPDOWN_INFO *infoPtr = UPDOWN_GetInfoPtr(wndPtr); |
| int temp; |
| |
| switch(message) |
| { |
| case WM_CREATE: |
| /* get rid of border, if any */ |
| wndPtr->dwStyle &= ~WS_BORDER; |
| |
| /* initialize the info struct */ |
| infoPtr->AccelCount=0; infoPtr->AccelVect=0; |
| infoPtr->CurVal=0; infoPtr->MinVal=0; infoPtr->MaxVal=100; /*FIXME*/ |
| 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(wndPtr->dwStyle & UDS_AUTOBUDDY) |
| UPDOWN_SetBuddy(wndPtr, GetWindow32(wndPtr->hwndSelf, GW_HWNDPREV)); |
| |
| TRACE(updown, "UpDown Ctrl creation, hwnd=%04x\n", hwnd); |
| break; |
| |
| case WM_DESTROY: |
| if(infoPtr->AccelVect) |
| free(infoPtr->AccelVect); |
| TRACE(updown, "UpDown Ctrl destruction, hwnd=%04x\n", hwnd); |
| break; |
| |
| case WM_ENABLE: |
| if(wndPtr->dwStyle & WS_DISABLED) |
| UPDOWN_CancelMode(wndPtr); |
| UPDOWN_Paint(wndPtr); |
| break; |
| |
| case WM_TIMER: |
| /* if initial timer, kill it and start the repeat timer */ |
| if(wParam == TIMERID1){ |
| KillTimer32(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; |
| } |
| SetTimer32(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(wndPtr, temp, infoPtr->Flags & FLAG_INCR); |
| |
| if(accelIndex!=-1 && accelIndex < infoPtr->AccelCount-1){ |
| KillTimer32(hwnd, TIMERID2); |
| accelIndex++; /* move to the next accel info */ |
| temp = infoPtr->AccelVect[accelIndex].nSec * 1000 + 1; |
| /* make sure we have at least 1ms intervals */ |
| SetTimer32(hwnd, TIMERID2, temp, 0); |
| } |
| } |
| break; |
| |
| case WM_CANCELMODE: |
| UPDOWN_CancelMode(wndPtr); |
| break; |
| |
| case WM_LBUTTONUP: |
| if(!UPDOWN_CancelMode(wndPtr)) |
| break; |
| /*If we released the mouse and our buddy is an edit */ |
| /* we must select all text in it. */ |
| if(WIDGETS_IsControl32(WIN_FindWndPtr(infoPtr->Buddy), BIC32_EDIT)) |
| SendMessage32A(infoPtr->Buddy, EM_SETSEL32, 0, MAKELONG(0, -1)); |
| break; |
| |
| case WM_LBUTTONDOWN: |
| case WM_MOUSEMOVE: |
| if(UPDOWN_IsEnabled(wndPtr)){ |
| POINT32 pt; |
| CONV_POINT16TO32( (POINT16 *)&lParam, &pt ); |
| UPDOWN_HandleMouseEvent( wndPtr, message, pt ); |
| } |
| break; |
| |
| case WM_KEYDOWN: |
| if((wndPtr->dwStyle & UDS_ARROWKEYS) && UPDOWN_IsEnabled(wndPtr)){ |
| switch(wParam){ |
| case VK_UP: |
| case VK_DOWN: |
| UPDOWN_GetBuddyInt(wndPtr); |
| UPDOWN_DoAction(wndPtr, 1, wParam==VK_UP); |
| break; |
| } |
| } |
| break; |
| |
| case WM_PAINT: |
| UPDOWN_Paint(wndPtr); |
| 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, "UpDown Ctrl new accel info, hwnd=%04x\n", hwnd); |
| if(infoPtr->AccelVect){ |
| free(infoPtr->AccelVect); |
| infoPtr->AccelCount = 0; |
| infoPtr->AccelVect = 0; |
| } |
| if(wParam==0) |
| return TRUE; |
| infoPtr->AccelVect = malloc(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, "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; |
| infoPtr->Buddy = wParam; |
| UPDOWN_SetBuddy(wndPtr, wParam); |
| TRACE(updown, "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(wndPtr); |
| 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, "UpDown Ctrl new value(%d), hwnd=%04x\n", |
| temp, hwnd); |
| if(!UPDOWN_InBounds(wndPtr, 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(wndPtr->dwStyle & UDS_SETBUDDYINT) |
| UPDOWN_SetBuddyInt(wndPtr); |
| 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, "UpDown Ctrl new range(%d to %d), hwnd=%04x\n", |
| infoPtr->MinVal, infoPtr->MaxVal, hwnd); |
| break; |
| |
| case UDM_GETRANGE32: |
| if (wParam) |
| *(LPINT32)wParam = infoPtr->MinVal; |
| if (lParam) |
| *(LPINT32)lParam = infoPtr->MaxVal; |
| break; |
| |
| case UDM_SETRANGE32: |
| infoPtr->MinVal = (INT32)wParam; |
| infoPtr->MaxVal = (INT32)lParam; |
| if (infoPtr->MaxVal <= infoPtr->MinVal) |
| infoPtr->MaxVal = infoPtr->MinVal + 1; |
| TRACE(updown, "UpDown Ctrl new range(%d to %d), hwnd=%04x\n", |
| infoPtr->MinVal, infoPtr->MaxVal, hwnd); |
| break; |
| |
| default: |
| if (message >= WM_USER) |
| WARN(updown, "unknown msg %04x wp=%04x lp=%08lx\n", |
| message, wParam, lParam ); |
| return DefWindowProc32A( hwnd, message, wParam, lParam ); |
| } |
| |
| return 0; |
| } |
| |
| /*********************************************************************** |
| * UPDOWN_Register [Internal] |
| * |
| * Registers the updown window class. |
| */ |
| void UPDOWN_Register(void) |
| { |
| WNDCLASS32A wndClass; |
| |
| if( GlobalFindAtom32A( UPDOWN_CLASS32A ) ) return; |
| |
| ZeroMemory( &wndClass, sizeof( WNDCLASS32A ) ); |
| wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_VREDRAW; |
| wndClass.lpfnWndProc = (WNDPROC32)UpDownWindowProc; |
| wndClass.cbClsExtra = 0; |
| wndClass.cbWndExtra = sizeof(UPDOWN_INFO); |
| wndClass.hCursor = LoadCursor32A( 0, IDC_ARROW32A ); |
| wndClass.hbrBackground = (HBRUSH32)(COLOR_3DFACE + 1); |
| wndClass.lpszClassName = UPDOWN_CLASS32A; |
| |
| RegisterClass32A( &wndClass ); |
| } |
| |