309 lines
12 KiB
C
309 lines
12 KiB
C
/*
|
|
* Theming - Scrollbar control
|
|
*
|
|
* Copyright (c) 2015 Mark Harmstone
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "wingdi.h"
|
|
#include "winuser.h"
|
|
#include "uxtheme.h"
|
|
#include "uxthemedll.h"
|
|
#include "vssym32.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(theme_scroll);
|
|
|
|
void WINAPI UXTHEME_ScrollBarDraw(HWND hwnd, HDC dc, INT bar, enum SCROLL_HITTEST hit_test,
|
|
const struct SCROLL_TRACKING_INFO *tracking_info,
|
|
BOOL draw_arrows, BOOL draw_interior, RECT *rect, INT arrowsize,
|
|
INT thumbpos, INT thumbsize, BOOL vertical)
|
|
{
|
|
BOOL disabled = !IsWindowEnabled(hwnd);
|
|
HTHEME theme;
|
|
DWORD style;
|
|
|
|
if (bar == SB_CTL)
|
|
theme = GetWindowTheme(hwnd);
|
|
else
|
|
theme = OpenThemeDataForDpi(NULL, WC_SCROLLBARW, GetDpiForWindow(hwnd));
|
|
|
|
if (!theme)
|
|
{
|
|
user_api.pScrollBarDraw(hwnd, dc, bar, hit_test, tracking_info, draw_arrows, draw_interior,
|
|
rect, arrowsize, thumbpos, thumbsize, vertical);
|
|
return;
|
|
}
|
|
|
|
style = GetWindowLongW(hwnd, GWL_STYLE);
|
|
if (bar == SB_CTL && (style & SBS_SIZEBOX || style & SBS_SIZEGRIP)) {
|
|
int state;
|
|
|
|
if (style & SBS_SIZEBOXTOPLEFTALIGN)
|
|
state = SZB_TOPLEFTALIGN;
|
|
else
|
|
state = SZB_RIGHTALIGN;
|
|
|
|
/* Tests show that COLOR_BTNFACE is used instead of DrawThemeParentBackground() for drawing
|
|
* background */
|
|
FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
|
|
DrawThemeBackground(theme, dc, SBP_SIZEBOX, state, rect, NULL);
|
|
} else {
|
|
int uppertrackstate, lowertrackstate, thumbstate;
|
|
RECT partrect;
|
|
SIZE grippersize;
|
|
|
|
if (disabled) {
|
|
uppertrackstate = SCRBS_DISABLED;
|
|
lowertrackstate = SCRBS_DISABLED;
|
|
thumbstate = SCRBS_DISABLED;
|
|
} else {
|
|
uppertrackstate = SCRBS_NORMAL;
|
|
lowertrackstate = SCRBS_NORMAL;
|
|
thumbstate = SCRBS_NORMAL;
|
|
|
|
if (vertical == tracking_info->vertical && hit_test == tracking_info->hit_test
|
|
&& GetCapture() == hwnd)
|
|
{
|
|
if (hit_test == SCROLL_TOP_RECT)
|
|
uppertrackstate = SCRBS_PRESSED;
|
|
else if (hit_test == SCROLL_BOTTOM_RECT)
|
|
lowertrackstate = SCRBS_PRESSED;
|
|
else if (hit_test == SCROLL_THUMB)
|
|
thumbstate = SCRBS_PRESSED;
|
|
}
|
|
else
|
|
{
|
|
if (hit_test == SCROLL_TOP_RECT)
|
|
uppertrackstate = SCRBS_HOT;
|
|
else if (hit_test == SCROLL_BOTTOM_RECT)
|
|
lowertrackstate = SCRBS_HOT;
|
|
else if (hit_test == SCROLL_THUMB)
|
|
thumbstate = SCRBS_HOT;
|
|
}
|
|
|
|
/* Thumb is also shown as pressed when tracking */
|
|
if (tracking_info->win == hwnd && tracking_info->bar == bar)
|
|
thumbstate = SCRBS_PRESSED;
|
|
}
|
|
|
|
if (vertical) {
|
|
int uparrowstate, downarrowstate;
|
|
|
|
if (disabled) {
|
|
uparrowstate = ABS_UPDISABLED;
|
|
downarrowstate = ABS_DOWNDISABLED;
|
|
} else {
|
|
uparrowstate = ABS_UPNORMAL;
|
|
downarrowstate = ABS_DOWNNORMAL;
|
|
|
|
if (vertical == tracking_info->vertical && hit_test == tracking_info->hit_test
|
|
&& GetCapture() == hwnd)
|
|
{
|
|
if (hit_test == SCROLL_TOP_ARROW)
|
|
uparrowstate = ABS_UPPRESSED;
|
|
else if (hit_test == SCROLL_BOTTOM_ARROW)
|
|
downarrowstate = ABS_DOWNPRESSED;
|
|
}
|
|
else
|
|
{
|
|
if (hit_test == SCROLL_TOP_ARROW)
|
|
uparrowstate = ABS_UPHOT;
|
|
else if (hit_test == SCROLL_BOTTOM_ARROW)
|
|
downarrowstate = ABS_DOWNHOT;
|
|
}
|
|
}
|
|
|
|
partrect = *rect;
|
|
partrect.bottom = partrect.top + arrowsize;
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_ARROWBTN, uparrowstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_ARROWBTN, uparrowstate, &partrect, NULL);
|
|
|
|
partrect.bottom = rect->bottom;
|
|
partrect.top = partrect.bottom - arrowsize;
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_ARROWBTN, downarrowstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_ARROWBTN, downarrowstate, &partrect, NULL);
|
|
|
|
if (thumbpos > 0) {
|
|
partrect.top = rect->top + arrowsize;
|
|
partrect.bottom = rect->top + thumbpos;
|
|
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_UPPERTRACKVERT, uppertrackstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_UPPERTRACKVERT, uppertrackstate, &partrect, NULL);
|
|
}
|
|
|
|
if (thumbsize > 0) {
|
|
partrect.top = rect->top + thumbpos;
|
|
partrect.bottom = partrect.top + thumbsize;
|
|
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_THUMBBTNVERT, thumbstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_THUMBBTNVERT, thumbstate, &partrect, NULL);
|
|
|
|
if (SUCCEEDED(GetThemePartSize(theme, dc, SBP_GRIPPERVERT, thumbstate, NULL, TS_DRAW, &grippersize))) {
|
|
MARGINS margins;
|
|
|
|
if (SUCCEEDED(GetThemeMargins(theme, dc, SBP_THUMBBTNVERT, thumbstate, TMT_CONTENTMARGINS, &partrect, &margins))) {
|
|
if (grippersize.cy <= (thumbsize - margins.cyTopHeight - margins.cyBottomHeight))
|
|
DrawThemeBackground(theme, dc, SBP_GRIPPERVERT, thumbstate, &partrect, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
partrect.bottom = rect->bottom - arrowsize;
|
|
if (thumbsize > 0)
|
|
partrect.top = rect->top + thumbpos + thumbsize;
|
|
else
|
|
partrect.top = rect->top + arrowsize;
|
|
if (partrect.bottom > partrect.top)
|
|
{
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_LOWERTRACKVERT, lowertrackstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_LOWERTRACKVERT, lowertrackstate, &partrect, NULL);
|
|
}
|
|
} else {
|
|
int leftarrowstate, rightarrowstate;
|
|
|
|
if (disabled) {
|
|
leftarrowstate = ABS_LEFTDISABLED;
|
|
rightarrowstate = ABS_RIGHTDISABLED;
|
|
} else {
|
|
leftarrowstate = ABS_LEFTNORMAL;
|
|
rightarrowstate = ABS_RIGHTNORMAL;
|
|
|
|
if (vertical == tracking_info->vertical && hit_test == tracking_info->hit_test
|
|
&& GetCapture() == hwnd)
|
|
{
|
|
if (hit_test == SCROLL_TOP_ARROW)
|
|
leftarrowstate = ABS_LEFTPRESSED;
|
|
else if (hit_test == SCROLL_BOTTOM_ARROW)
|
|
rightarrowstate = ABS_RIGHTPRESSED;
|
|
}
|
|
else
|
|
{
|
|
if (hit_test == SCROLL_TOP_ARROW)
|
|
leftarrowstate = ABS_LEFTHOT;
|
|
else if (hit_test == SCROLL_BOTTOM_ARROW)
|
|
rightarrowstate = ABS_RIGHTHOT;
|
|
}
|
|
}
|
|
|
|
partrect = *rect;
|
|
partrect.right = partrect.left + arrowsize;
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_ARROWBTN, leftarrowstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_ARROWBTN, leftarrowstate, &partrect, NULL);
|
|
|
|
partrect.right = rect->right;
|
|
partrect.left = partrect.right - arrowsize;
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_ARROWBTN, rightarrowstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_ARROWBTN, rightarrowstate, &partrect, NULL);
|
|
|
|
if (thumbpos > 0) {
|
|
partrect.left = rect->left + arrowsize;
|
|
partrect.right = rect->left + thumbpos;
|
|
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_UPPERTRACKHORZ, uppertrackstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_UPPERTRACKHORZ, uppertrackstate, &partrect, NULL);
|
|
}
|
|
|
|
if (thumbsize > 0) {
|
|
partrect.left = rect->left + thumbpos;
|
|
partrect.right = partrect.left + thumbsize;
|
|
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_THUMBBTNHORZ, thumbstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_THUMBBTNHORZ, thumbstate, &partrect, NULL);
|
|
|
|
if (SUCCEEDED(GetThemePartSize(theme, dc, SBP_GRIPPERHORZ, thumbstate, NULL, TS_DRAW, &grippersize))) {
|
|
MARGINS margins;
|
|
|
|
if (SUCCEEDED(GetThemeMargins(theme, dc, SBP_THUMBBTNHORZ, thumbstate, TMT_CONTENTMARGINS, &partrect, &margins))) {
|
|
if (grippersize.cx <= (thumbsize - margins.cxLeftWidth - margins.cxRightWidth))
|
|
DrawThemeBackground(theme, dc, SBP_GRIPPERHORZ, thumbstate, &partrect, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
partrect.right = rect->right - arrowsize;
|
|
if (thumbsize > 0)
|
|
partrect.left = rect->left + thumbpos + thumbsize;
|
|
else
|
|
partrect.left = rect->left + arrowsize;
|
|
if (partrect.right > partrect.left)
|
|
{
|
|
if (bar == SB_CTL && IsThemeBackgroundPartiallyTransparent(theme, SBP_LOWERTRACKHORZ, lowertrackstate))
|
|
DrawThemeParentBackground(hwnd, dc, &partrect);
|
|
DrawThemeBackground(theme, dc, SBP_LOWERTRACKHORZ, lowertrackstate, &partrect, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bar != SB_CTL)
|
|
CloseThemeData(theme);
|
|
}
|
|
|
|
LRESULT WINAPI UXTHEME_ScrollbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam,
|
|
BOOL unicode)
|
|
{
|
|
const WCHAR* themeClass = WC_SCROLLBARW;
|
|
HTHEME theme;
|
|
LRESULT result;
|
|
|
|
TRACE("(%p, 0x%x, %lu, %lu, %d)\n", hwnd, msg, wParam, lParam, unicode);
|
|
|
|
switch (msg) {
|
|
case WM_CREATE:
|
|
result = user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
|
|
OpenThemeData(hwnd, themeClass);
|
|
return result;
|
|
|
|
case WM_DESTROY:
|
|
theme = GetWindowTheme(hwnd);
|
|
CloseThemeData(theme);
|
|
return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
|
|
|
|
case WM_THEMECHANGED:
|
|
theme = GetWindowTheme(hwnd);
|
|
CloseThemeData(theme);
|
|
OpenThemeData(hwnd, themeClass);
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
theme = GetWindowTheme(hwnd);
|
|
if (!theme) return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
|
|
/* Do nothing. When themed, a WM_THEMECHANGED will be received, too,
|
|
* which will do the repaint. */
|
|
break;
|
|
|
|
default:
|
|
return user_api.pScrollBarWndProc(hwnd, msg, wParam, lParam, unicode);
|
|
}
|
|
|
|
return 0;
|
|
}
|