Sun Oct 12 15:03:01 1997 Alexandre Julliard <julliard@lrc.epfl.ch> * [if1632/builtin.c] [if1632/relay.c] Relay debugging entry points are now generated on the fly for Win32 DLLs. * [include/stackframe.h] Added VA_LIST16 type and macros to access arguments on the 16-bit stack. * [memory/global.c] Fixed GlobalHandle32 to work with fixed blocks. * [misc/ddeml.c] (New file) Added a lot of stubs for DDEML functions. * [objects/dc.c] Added Get/SetGraphicsMode(). * [objects/gdiobj.c] [windows/winpos.c] Added a few stubs. * [tools/build.c] Removed 'byte', 'word', 'long' and 'return' entry points for Win32. 'register' functions can no longer take arguments in Win32. The Win32 NE module is now generated by MODULE_CreateDummyModule. CallFrom32 callbacks removed except for register functions. Fri Oct 10 18:22:18 1997 John Harvey <john@division.co.uk> * [graphics/win16drv/Makefile.in] [graphics/win16drv/brush.c] [graphics/win16drv/graphics.c] [graphics/win16drv/init.c] [graphics/win16drv/objects.c] [graphics/win16drv/pen.c] [graphics/win16drv/prtdrv.c] [graphics/win16drv/text.c] [include/callback.h] [include/win16drv.h] Added support for pens and brushes in SelectObject. Added support for LineTo, MoveToEx, PatBlt (very preliminary), Polygon and Rectangle. Text is drawn in the correct place more often. These changes may only work with the Windows Postscript driver since many other drivers now need more GDI support. Tue Oct 7 21:06:23 1997 Kristian Nielsen <kristian.nielsen@risoe.dk> * [debugger/expr.c] Fixed typo for the >> operator. * [loader/task.c] Fixed SwitchStackTo(); it used to return with the new stack placed four bytes too high in memory. * [loader/ne_resource.c] Removed problematic nametable code introduced in Wine 970914. Tue Oct 7 02:24:12 1997 Dimitrie O. Paun <dimi@cs.toronto.edu> * [controls/commctrl.c] Added this files to hold functions from the comctl32.dll Added to this files some functions scattered in different places (such as InitCommonControls) and added some new ones as well. * [include/syscolor.h] [windows/syscolor.c] Added proper entries for all possible COLOR_* values. * [objects/brush.c] Modified GetSysColorBrush to return the correct brush for all possible COLOR_* constants. Sat Oct 4 23:35:20 1997 U.Bonnes <bon@elektron.ikp.physik.th-darmstadt.de> * [loader/module.c] [scheduler/process.c] [win32/environment.c] Another approach to get access to an unrestricted commandline. * [misc/crtdll.c] Make fclose work again. * [if1632/crtdll.spec] Use sprintf for crtdll-sprintf again as e.g. %g is not available for wsprintf. * [misc/wsprintf.c] Make WPR_STRING work in more situations. Added debug output for the wsprintf functions. * [misc/crtdll.c] [misc/main.c] Use argv[0] as comand with CRTDLL_system. Fri Oct 3 14:00:29 MET DST 1997 Jan Willamowius <jan@janhh.shnet.org> * [*/*] Removed some compiler warnings. * [msdos/int15.c] New INT 15 handler.
849 lines
25 KiB
C
849 lines
25 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include "windows.h"
|
|
#include "winnls.h"
|
|
#include "syscolor.h"
|
|
#include "sysmetrics.h"
|
|
#include "updown.h"
|
|
#include "graphics.h"
|
|
#include "heap.h"
|
|
#include "win.h"
|
|
#include "stddebug.h"
|
|
/*#define DEBUG_UPDOWN*/
|
|
#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) dprintf_updown(stddeb, \
|
|
"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_GetArrawRect
|
|
* 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;
|
|
|
|
dprintf_updown(stddeb, "UpDown Ctrl: 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;
|
|
|
|
dprintf_updown(stddeb, "UpDown Ctrl: 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_DrawArraw
|
|
* Draw the arrows for the up-down control. The arrows are drawn with the
|
|
* current pen and filled with the current brush.
|
|
* Input:
|
|
* hdc - the DC to draw on
|
|
* rect - rectangle holding the arrow
|
|
* incr - TRUE if we draw the "increment" arrow
|
|
* FALSE if we draw the "decrement" arrow
|
|
* pressed - TRUE if the arrow is pressed (clicked)
|
|
* FALSE if the arrow is not pressed (clicked)
|
|
* horz - TRUE if the arrow is horizontal
|
|
* FLASE if the arrow is vertical
|
|
*/
|
|
static void UPDOWN_DrawArrow(HDC32 hdc, RECT32 *rect, BOOL32 incr,
|
|
BOOL32 pressed, BOOL32 horz)
|
|
{
|
|
const int rw = rect->right - rect->left;
|
|
const int rh = rect->bottom - rect->top;
|
|
int offset = pressed ? 1 : 0;
|
|
int th, x, y, len;
|
|
|
|
/* compute max extents of the triangle */
|
|
if(horz){ /* horizontal arrows */
|
|
th = (3*rh)/5-2*4;
|
|
if(th > rw/2)
|
|
th = rw/2;
|
|
if(th < 2)
|
|
th = 2;
|
|
|
|
/* compute the position of the tip */
|
|
y = (rect->top+rect->bottom+1)/2 + offset;
|
|
if(incr)
|
|
x = (rect->left+rect->right+1)/2 + (2*th)/3 + offset;
|
|
else
|
|
x = (rect->left+rect->right)/2 + th/3 + offset;
|
|
|
|
for(len=1; th>0; th--, len+=2){
|
|
MoveToEx32(hdc, x, y, 0);
|
|
LineTo32(hdc, x, y+len);
|
|
if(incr) x--;
|
|
else x++;
|
|
y++;
|
|
}
|
|
}
|
|
else{ /* vertical arrows */
|
|
th = (3*rw)/5-2*4;
|
|
if(th > rh/2)
|
|
th = rh/2;
|
|
if(th < 2)
|
|
th = 2;
|
|
|
|
/* compute the position of the tip */
|
|
x = (rect->left+rect->right+1)/2 + offset;
|
|
if(incr)
|
|
y = (rect->top+rect->bottom+1)/2 - th/3 + offset;
|
|
else
|
|
y = (rect->top+rect->bottom)/2 + (2*th)/3 + offset;
|
|
|
|
for(len=1; th>0; th--, len+=2){
|
|
MoveToEx32(hdc, x, y, 0);
|
|
LineTo32(hdc, x+len, y);
|
|
if(incr) y++;
|
|
else y--;
|
|
x--;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/***********************************************************************
|
|
* 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;
|
|
HBRUSH32 oldBrush;
|
|
|
|
hdc = BeginPaint32( wndPtr->hwndSelf, &ps );
|
|
|
|
/* First select the proper brush */
|
|
oldBrush = wndPtr->dwStyle & WS_DISABLED ? GRAY_BRUSH : BLACK_BRUSH;
|
|
oldBrush = SelectObject32(hdc, GetStockObject32(oldBrush));
|
|
|
|
/* Draw the incr button */
|
|
UPDOWN_GetArrowRect(wndPtr, &rect, TRUE);
|
|
prssed = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
|
|
DrawEdge32(hdc, &rect, prssed?EDGE_SUNKEN:EDGE_RAISED, BF_RECT|BF_MIDDLE);
|
|
UPDOWN_DrawArrow(hdc, &rect, TRUE, prssed, wndPtr->dwStyle & UDS_HORZ);
|
|
|
|
/* 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);
|
|
DrawEdge32(hdc, &rect, prssed ? EDGE_SUNKEN : EDGE_RAISED,
|
|
BF_RECT | BF_SOFT | BF_MIDDLE);
|
|
UPDOWN_DrawArrow(hdc, &rect, FALSE, prssed, wndPtr->dwStyle & UDS_HORZ);
|
|
|
|
/* clean-up */
|
|
SelectObject32(hdc, oldBrush);
|
|
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: we need to subclass the buddy to process the arrow keys. */
|
|
fprintf(stderr, "UpDown Ctrl: we should subclass the buddy window!\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;
|
|
|
|
dprintf_updown(stddeb, "UpDown Ctrl action: %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:
|
|
fprintf(stderr, "UpDown: Impossible case in proc "
|
|
"UPDOWN_HandleMouseEvent");
|
|
}
|
|
|
|
}
|
|
|
|
/***********************************************************************
|
|
* 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));
|
|
|
|
dprintf_updown(stddeb, "UpDown Ctrl creation, hwnd=%04x\n", hwnd);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
if(infoPtr->AccelVect)
|
|
free(infoPtr->AccelVect);
|
|
dprintf_updown(stddeb, "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:
|
|
dprintf_updown(stddeb, "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:
|
|
dprintf_updown(stddeb, "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);
|
|
dprintf_updown(stddeb, "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);
|
|
dprintf_updown(stddeb, "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 */
|
|
dprintf_updown(stddeb, "UpDown Ctrl new range(%d to %d), hwnd=%04x\n",
|
|
infoPtr->MinVal, infoPtr->MaxVal, hwnd);
|
|
break;
|
|
|
|
default:
|
|
if (message >= WM_USER)
|
|
fprintf( stderr, "UpDown Ctrl: unknown msg %04x wp=%04x lp=%08lx\n",
|
|
message, wParam, lParam );
|
|
return DefWindowProc32A( hwnd, message, wParam, lParam );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|