📄 updown.c
字号:
}
/***********************************************************************
* UPDOWN_Draw
*
* Draw the arrows. The background need not be erased.
*/
static LRESULT UPDOWN_Draw (const UPDOWN_INFO *infoPtr, HDC hdc)
{
BOOL uPressed, uHot, dPressed, dHot;
RECT rect;
HTHEME theme = GetWindowTheme (infoPtr->Self);
int uPart = 0, uState = 0, dPart = 0, dState = 0;
BOOL needBuddyBg = FALSE;
uPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_INCR);
uHot = (infoPtr->Flags & FLAG_INCR) && (infoPtr->Flags & FLAG_MOUSEIN);
dPressed = (infoPtr->Flags & FLAG_PRESSED) && (infoPtr->Flags & FLAG_DECR);
dHot = (infoPtr->Flags & FLAG_DECR) && (infoPtr->Flags & FLAG_MOUSEIN);
if (theme) {
uPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_UPHORZ : SPNP_UP;
uState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
: (uPressed ? DNS_PRESSED : (uHot ? DNS_HOT : DNS_NORMAL));
dPart = (infoPtr->dwStyle & UDS_HORZ) ? SPNP_DOWNHORZ : SPNP_DOWN;
dState = (infoPtr->dwStyle & WS_DISABLED) ? DNS_DISABLED
: (dPressed ? DNS_PRESSED : (dHot ? DNS_HOT : DNS_NORMAL));
needBuddyBg = IsWindow (infoPtr->Buddy)
&& (IsThemeBackgroundPartiallyTransparent (theme, uPart, uState)
|| IsThemeBackgroundPartiallyTransparent (theme, dPart, dState));
}
/* Draw the common border between ourselves and our buddy */
if (UPDOWN_HasBuddyBorder(infoPtr) || needBuddyBg) {
if (!theme || !UPDOWN_DrawBuddyBackground (infoPtr, hdc)) {
GetClientRect(infoPtr->Self, &rect);
DrawEdge(hdc, &rect, EDGE_SUNKEN,
BF_BOTTOM | BF_TOP |
(infoPtr->dwStyle & UDS_ALIGNLEFT ? BF_LEFT : BF_RIGHT));
}
}
/* Draw the incr button */
UPDOWN_GetArrowRect (infoPtr, &rect, FLAG_INCR);
if (theme) {
DrawThemeBackground(theme, hdc, uPart, uState, &rect, NULL);
} else {
DrawFrameControl(hdc, &rect, DFC_SCROLL,
(infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLRIGHT : DFCS_SCROLLUP) |
((infoPtr->dwStyle & UDS_HOTTRACK) && uHot ? DFCS_HOT : 0) |
(uPressed ? DFCS_PUSHED : 0) |
(infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
}
/* Draw the decr button */
UPDOWN_GetArrowRect(infoPtr, &rect, FLAG_DECR);
if (theme) {
DrawThemeBackground(theme, hdc, dPart, dState, &rect, NULL);
} else {
DrawFrameControl(hdc, &rect, DFC_SCROLL,
(infoPtr->dwStyle & UDS_HORZ ? DFCS_SCROLLLEFT : DFCS_SCROLLDOWN) |
((infoPtr->dwStyle & UDS_HOTTRACK) && dHot ? DFCS_HOT : 0) |
(dPressed ? DFCS_PUSHED : 0) |
(infoPtr->dwStyle & WS_DISABLED ? DFCS_INACTIVE : 0) );
}
return 0;
}
/***********************************************************************
* UPDOWN_Paint
*
* Asynchronous drawing (must ONLY be used in WM_PAINT).
* Calls UPDOWN_Draw.
*/
static LRESULT UPDOWN_Paint (const UPDOWN_INFO *infoPtr, HDC hdc)
{
PAINTSTRUCT ps;
if (hdc) return UPDOWN_Draw (infoPtr, hdc);
hdc = BeginPaint (infoPtr->Self, &ps);
UPDOWN_Draw (infoPtr, hdc);
EndPaint (infoPtr->Self, &ps);
return 0;
}
/***********************************************************************
* UPDOWN_KeyPressed
*
* Handle key presses (up & down) when we have to do so
*/
static LRESULT UPDOWN_KeyPressed(UPDOWN_INFO *infoPtr, int key)
{
int arrow;
if (key == VK_UP) arrow = FLAG_INCR;
else if (key == VK_DOWN) arrow = FLAG_DECR;
else return 1;
UPDOWN_GetBuddyInt (infoPtr);
infoPtr->Flags &= ~FLAG_ARROW;
infoPtr->Flags |= FLAG_PRESSED | arrow;
InvalidateRect (infoPtr->Self, NULL, FALSE);
SetTimer(infoPtr->Self, TIMER_AUTOPRESS, AUTOPRESS_DELAY, 0);
UPDOWN_DoAction (infoPtr, 1, arrow);
return 0;
}
/***********************************************************************
* UPDOWN_Buddy_SubclassProc used to handle messages sent to the buddy
* control.
*/
static LRESULT CALLBACK
UPDOWN_Buddy_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WNDPROC superClassWndProc = (WNDPROC)GetPropW(hwnd, BUDDY_SUPERCLASS_WNDPROC);
TRACE("hwnd=%p, wndProc=%p, uMsg=%04x, wParam=%08lx, lParam=%08lx\n",
hwnd, superClassWndProc, uMsg, wParam, lParam);
if (uMsg == WM_KEYDOWN) {
HWND upDownHwnd = GetPropW(hwnd, BUDDY_UPDOWN_HWND);
UPDOWN_KeyPressed(UPDOWN_GetInfoPtr(upDownHwnd), (int)wParam);
}
return CallWindowProcW( superClassWndProc, hwnd, uMsg, wParam, lParam);
}
/***********************************************************************
* UPDOWN_SetBuddy
*
* Sets bud as a new Buddy.
* Then, it should subclass the buddy
* If window has the UDS_ARROWKEYS, it subcalsses the buddy window to
* process the UP/DOWN arrow keys.
* If window has the UDS_ALIGNLEFT or UDS_ALIGNRIGHT style
* the size/pos of the buddy and the control are adjusted accordingly.
*/
static HWND UPDOWN_SetBuddy (UPDOWN_INFO* infoPtr, HWND bud)
{
static const WCHAR editW[] = { 'E', 'd', 'i', 't', 0 };
static const WCHAR listboxW[] = { 'L', 'i', 's', 't', 'b', 'o', 'x', 0 };
RECT budRect; /* new coord for the buddy */
int x, width; /* new x position and width for the up-down */
WNDPROC baseWndProc;
WCHAR buddyClass[40];
HWND ret;
TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud);
ret = infoPtr->Buddy;
/* there is already a body assigned */
if (infoPtr->Buddy) RemovePropW(infoPtr->Buddy, BUDDY_UPDOWN_HWND);
if(!IsWindow(bud))
bud = 0;
/* Store buddy window handle */
infoPtr->Buddy = bud;
if(bud) {
/* keep upDown ctrl hwnd in a buddy property */
SetPropW( bud, BUDDY_UPDOWN_HWND, infoPtr->Self);
/* Store buddy window class type */
infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN;
if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) {
if (lstrcmpiW(buddyClass, editW) == 0)
infoPtr->BuddyType = BUDDY_TYPE_EDIT;
else if (lstrcmpiW(buddyClass, listboxW) == 0)
infoPtr->BuddyType = BUDDY_TYPE_LISTBOX;
}
if(infoPtr->dwStyle & UDS_ARROWKEYS){
/* Note that I don't clear the BUDDY_SUPERCLASS_WNDPROC property
when we reset the upDown ctrl buddy to another buddy because it is not
good to break the window proc chain. */
if (!GetPropW(bud, BUDDY_SUPERCLASS_WNDPROC)) {
baseWndProc = (WNDPROC)SetWindowLongPtrW(bud, GWLP_WNDPROC, (LPARAM)UPDOWN_Buddy_SubclassProc);
SetPropW(bud, BUDDY_SUPERCLASS_WNDPROC, (HANDLE)baseWndProc);
}
}
/* Get the rect of the buddy relative to its parent */
GetWindowRect(infoPtr->Buddy, &budRect);
MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Buddy), (POINT *)(&budRect.left), 2);
/* now do the positioning */
if (infoPtr->dwStyle & UDS_ALIGNLEFT) {
x = budRect.left;
budRect.left += DEFAULT_WIDTH + DEFAULT_XSEP;
} else if (infoPtr->dwStyle & UDS_ALIGNRIGHT) {
budRect.right -= DEFAULT_WIDTH + DEFAULT_XSEP;
x = budRect.right+DEFAULT_XSEP;
} else {
/* nothing to do */
return ret;
}
/* first adjust the buddy to accommodate the up/down */
SetWindowPos(infoPtr->Buddy, 0, budRect.left, budRect.top,
budRect.right - budRect.left, budRect.bottom - budRect.top,
SWP_NOACTIVATE|SWP_NOZORDER);
/* now position the up/down */
/* Since the UDS_ALIGN* flags were used, */
/* we will pick the position and size of the window. */
width = DEFAULT_WIDTH;
/*
* If the updown has a buddy border, it has to overlap with the buddy
* to look as if it is integrated with the buddy control.
* We nudge the control or change its size to overlap.
*/
if (UPDOWN_HasBuddyBorder(infoPtr)) {
if(infoPtr->dwStyle & UDS_ALIGNLEFT)
width += DEFAULT_BUDDYBORDER;
else
x -= DEFAULT_BUDDYBORDER;
}
SetWindowPos(infoPtr->Self, 0, x,
budRect.top - DEFAULT_ADDTOP, width,
budRect.bottom - budRect.top + DEFAULT_ADDTOP + DEFAULT_ADDBOT,
SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
} else {
RECT rect;
GetWindowRect(infoPtr->Self, &rect);
MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->Self), (POINT *)&rect, 2);
SetWindowPos(infoPtr->Self, 0, rect.left, rect.top, DEFAULT_WIDTH, rect.bottom - rect.top,
SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOZORDER);
}
return ret;
}
/***********************************************************************
* UPDOWN_DoAction
*
* This function increments/decrements the CurVal by the
* 'delta' amount according to the 'action' flag which can be a
* combination of FLAG_INCR and FLAG_DECR
* It notifies the parent as required.
* It handles wraping and non-wraping correctly.
* It is assumed that delta>0
*/
static void UPDOWN_DoAction (UPDOWN_INFO *infoPtr, int delta, int action)
{
NM_UPDOWN ni;
TRACE("%d by %d\n", action, delta);
/* check if we can do the modification first */
delta *= (action & FLAG_INCR ? 1 : -1) * (infoPtr->MaxVal < infoPtr->MinVal ? -1 : 1);
if ( (action & FLAG_INCR) && (action & FLAG_DECR) ) delta = 0;
TRACE("current %d, delta: %d\n", infoPtr->CurVal, delta);
/* We must notify parent now to obtain permission */
ni.iPos = infoPtr->CurVal;
ni.iDelta = delta;
ni.hdr.hwndFrom = infoPtr->Self;
ni.hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
ni.hdr.code = UDN_DELTAPOS;
if (!SendMessageW(infoPtr->Notify, WM_NOTIFY, (WPARAM)ni.hdr.idFrom, (LPARAM)&ni)) {
/* Parent said: OK to adjust */
/* Now adjust value with (maybe new) delta */
if (UPDOWN_OffsetVal (infoPtr, ni.iDelta)) {
TRACE("new %d, delta: %d\n", infoPtr->CurVal, ni.iDelta);
/* Now take care about our buddy */
UPDOWN_SetBuddyInt (infoPtr);
}
}
/* Also, notify it. This message is sent in any case. */
SendMessageW( infoPtr->Notify, (infoPtr->dwStyle & UDS_HORZ) ? WM_HSCROLL : WM_VSCROLL,
MAKELONG(SB_THUMBPOSITION, infoPtr->CurVal), (LPARAM)infoPtr->Self);
}
/***********************************************************************
* UPDOWN_IsEnabled
*
* Returns TRUE if it is enabled as well as its buddy (if any)
* FALSE otherwise
*/
static BOOL UPDOWN_IsEnabled (const UPDOWN_INFO *infoPtr)
{
if (!IsWindowEnabled(infoPtr->Self))
return FALSE;
if(infoPtr->Buddy)
return IsWindowEnabled(infoPtr->Buddy);
return TRUE;
}
/***********************************************************************
* 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 BOOL UPDOWN_CancelMode (UPDOWN_INFO *infoPtr)
{
if (!(infoPtr->Flags & FLAG_PRESSED)) return FALSE;
KillTimer (infoPtr->Self, TIMER_AUTOREPEAT);
KillTimer (infoPtr->Self, TIMER_ACCEL);
KillTimer (infoPtr->Self, TIMER_AUTOPRESS);
if (GetCapture() == infoPtr->Self) {
NMHDR hdr;
hdr.hwndFrom = infoPtr->Self;
hdr.idFrom = GetWindowLongPtrW (infoPtr->Self, GWLP_ID);
hdr.code = NM_RELEASEDCAPTURE;
SendMessageW(infoPtr->Notify, WM_NOTIFY, hdr.idFrom, (LPARAM)&hdr);
ReleaseCapture();
}
infoPtr->Flags &= ~FLAG_PRESSED;
InvalidateRect (infoPtr->Self, NULL, FALSE);
return TRUE;
}
/***********************************************************************
* 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 (UPDOWN_INFO *infoPtr, UINT msg, INT x, INT y)
{
POINT pt = { x, y };
RECT rect;
int temp, arrow;
TRACKMOUSEEVENT tme;
TRACE("msg %04x point %s\n", msg, wine_dbgstr_point(&pt));
switch(msg)
{
case WM_LBUTTONDOWN: /* Initialise mouse tracking */
/* If the buddy is an edit, will set focus to it */
if (UPDOWN_IsBuddyEdit(infoPtr)) SetFocus(infoPtr->Buddy);
/* Now see which one is the 'active' arrow */
arrow = UPDOWN_GetArrowFromPoint (infoPtr, &rect, pt);
/* Update the flags if we are in/out */
infoPtr->Flags &= ~(FLAG_MOUSEIN | FLAG_ARROW);
if (arrow)
infoPtr->Flags |= FLAG_MOUSEIN | arrow;
else
if (infoPtr->AccelIndex != -1) infoPtr->AccelIndex = 0;
if (infoPtr->Flags & FLAG_ARROW) {
/* Update the CurVal if necessary */
UPDOWN_GetBuddyInt (infoPtr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -