/*********************************************************************** * 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_GetArrowRect * wndPtr - pointer to the up-down wnd * rect - will hold the rectangle * arrow - FLAG_INCR to get the "increment" rect (up or right) * FLAG_DECR to get the "decrement" rect (down or left) * If both flags are present, the envelope is returned. */ static void UPDOWN_GetArrowRect (const UPDOWN_INFO* infoPtr, RECT *rect, int arrow) { HTHEME theme = GetWindowTheme (infoPtr->Self); const int border = theme ? DEFAULT_BUDDYBORDER_THEMED : DEFAULT_BUDDYBORDER; const int spacer = theme ? DEFAULT_BUDDYSPACER_THEMED : DEFAULT_BUDDYSPACER; GetClientRect (infoPtr->Self, rect); /* * Make sure we calculate the rectangle to fit even if we draw the * border. */ if (UPDOWN_HasBuddyBorder(infoPtr)) { if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->left += border; else rect->right -= border; InflateRect(rect, 0, -border); } /* now figure out if we need a space away from the buddy */ if (IsWindow(infoPtr->Buddy) ) { if (infoPtr->dwStyle & UDS_ALIGNLEFT) rect->right -= spacer; else rect->left += spacer; } /* * We're calculating the midpoint to figure-out where the * separation between the buttons will lay. We make sure that we * round the uneven numbers by adding 1. */ if (infoPtr->dwStyle & UDS_HORZ) { int len = rect->right - rect->left + 1; /* compute the width */ if (arrow & FLAG_INCR) rect->left = rect->left + len/2; if (arrow & FLAG_DECR) rect->right = rect->left + len/2 - (theme ? 0 : 1); } else { int len = rect->bottom - rect->top + 1; /* compute the height */ if (arrow & FLAG_INCR) rect->bottom = rect->top + len/2 - (theme ? 0 : 1); if (arrow & FLAG_DECR) rect->top = rect->top + len/2; } }
/*********************************************************************** * 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_SetBuddy * * Sets bud as a new Buddy. * Then, it should subclass the buddy * If window has the UDS_ARROWKEYS, it subclasses 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) { RECT budRect; /* new coord for the buddy */ int x, width; /* new x position and width for the up-down */ WCHAR buddyClass[40]; HWND ret; TRACE("(hwnd=%p, bud=%p)\n", infoPtr->Self, bud); ret = infoPtr->Buddy; /* there is already a buddy assigned */ if (infoPtr->Buddy) RemoveWindowSubclass(infoPtr->Buddy, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID); if (!IsWindow(bud)) bud = NULL; /* Store buddy window handle */ infoPtr->Buddy = bud; if(bud) { /* Store buddy window class type */ infoPtr->BuddyType = BUDDY_TYPE_UNKNOWN; if (GetClassNameW(bud, buddyClass, COUNT_OF(buddyClass))) { if (lstrcmpiW(buddyClass, WC_EDITW) == 0) infoPtr->BuddyType = BUDDY_TYPE_EDIT; else if (lstrcmpiW(buddyClass, WC_LISTBOXW) == 0) infoPtr->BuddyType = BUDDY_TYPE_LISTBOX; } if (infoPtr->dwStyle & UDS_ARROWKEYS) SetWindowSubclass(bud, UPDOWN_Buddy_SubclassProc, BUDDY_SUBCLASSID, (DWORD_PTR)infoPtr->Self); /* 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; }