Merge branch 'dark-statusbar'
Fixes for status bar and dialog grippers appearance in dark mode. See #23602.
This commit is contained in:
commit
4c94d5d1e5
16 changed files with 496 additions and 325 deletions
|
|
@ -78,7 +78,7 @@ public:
|
|||
// need to be called any more.
|
||||
void UseHeaderThemeColors(HWND hwndHdr)
|
||||
{
|
||||
wxUxThemeHandle theme{hwndHdr, L"Header"};
|
||||
auto theme = wxUxThemeHandle::NewAtStdDPI(hwndHdr, L"Header");
|
||||
|
||||
m_attr.SetTextColour(theme.GetColour(HP_HEADERITEM, TMT_TEXTCOLOR));
|
||||
|
||||
|
|
|
|||
82
include/wx/msw/private/custompaint.h
Normal file
82
include/wx/msw/private/custompaint.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: wx/msw/private/custompaint.h
|
||||
// Purpose: Helper function for customizing the standard WM_PAINT handling.
|
||||
// Author: Vadim Zeitlin
|
||||
// Created: 2023-06-02
|
||||
// Copyright: (c) 2023 Vadim Zeitlin <vadim@wxwidgets.org>
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WX_MSW_PRIVATE_CUSTOMPAINT_H_
|
||||
#define _WX_MSW_PRIVATE_CUSTOMPAINT_H_
|
||||
|
||||
#include "wx/dcmemory.h"
|
||||
#include "wx/image.h"
|
||||
|
||||
#include "wx/msw/dc.h"
|
||||
|
||||
namespace wxMSWImpl
|
||||
{
|
||||
|
||||
// This function can be used as CustomPaint() callback to post process the
|
||||
// bitmap by applying the specific functor to each of its pixels.
|
||||
template <typename FuncProcessPixel>
|
||||
wxBitmap
|
||||
PostPaintEachPixel(const wxBitmap& bmp, FuncProcessPixel processPixel)
|
||||
{
|
||||
#if wxUSE_IMAGE
|
||||
wxImage image = bmp.ConvertToImage();
|
||||
|
||||
unsigned char *data = image.GetData();
|
||||
unsigned char *alpha = image.GetAlpha();
|
||||
unsigned char alphaOpaque = wxALPHA_OPAQUE;
|
||||
const int len = image.GetWidth()*image.GetHeight();
|
||||
for ( int i = 0; i < len; ++i, data += 3 )
|
||||
{
|
||||
processPixel(data[0], data[1], data[2], alpha ? *alpha++ : alphaOpaque);
|
||||
}
|
||||
|
||||
return wxBitmap(image);
|
||||
#else // !wxUSE_IMAGE
|
||||
return bmp;
|
||||
#endif // wxUSE_IMAGE/!wxUSE_IMAGE
|
||||
}
|
||||
|
||||
// This function uses the default WM_PAINT handler to paint the window contents
|
||||
// into a bitmap and then the provided function to tweak the pixels of this
|
||||
// bitmap.
|
||||
//
|
||||
// The first argument is a functor (typically a lambda) to paint the on the
|
||||
// given HDC and the second one is another functor called to post process the
|
||||
// bitmap before actually drawing it.
|
||||
//
|
||||
// It can only be called from WM_PAINT handler for a native control and assumes
|
||||
// that this control handles WPARAM argument of WM_PAINT as HDC to paint on.
|
||||
template <typename FuncDefPaint, typename FuncPostProcess>
|
||||
void
|
||||
CustomPaint(HWND hwnd, FuncDefPaint defPaint, FuncPostProcess postProcess)
|
||||
{
|
||||
const RECT rc = wxGetClientRect(hwnd);
|
||||
const wxSize size{rc.right - rc.left, rc.bottom - rc.top};
|
||||
|
||||
// Don't bother doing anything with the empty windows.
|
||||
if ( size == wxSize() )
|
||||
return;
|
||||
|
||||
// Ask the control to paint itself on the given bitmap.
|
||||
wxBitmap bmp(size);
|
||||
{
|
||||
wxMemoryDC mdc(bmp);
|
||||
|
||||
defPaint(hwnd, (WPARAM)GetHdcOf(mdc));
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
wxDCTemp dc(::BeginPaint(hwnd, &ps), size);
|
||||
dc.DrawBitmap(postProcess(bmp), 0, 0);
|
||||
::EndPaint(hwnd, &ps);
|
||||
}
|
||||
|
||||
} // namespace wxMSWImpl
|
||||
|
||||
#endif // _WX_MSW_PRIVATE_CUSTOMPAINT_H_
|
||||
|
|
@ -166,17 +166,40 @@ WXDLLIMPEXP_CORE bool wxUxThemeIsActive();
|
|||
// wxUxThemeHandle: encapsulates ::Open/CloseThemeData()
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxUxThemeHandle
|
||||
class WXDLLIMPEXP_CORE wxUxThemeHandle
|
||||
{
|
||||
public:
|
||||
wxUxThemeHandle(HWND hwnd, const wchar_t *classes) :
|
||||
m_hTheme{::OpenThemeData(hwnd, classes)}
|
||||
// For all factory functions, HWND doesn't need to be valid and may be
|
||||
// entirely omitted when using NewAtStdDPI(). However DPI must be valid if
|
||||
// it's specified, i.e. NewForStdDPI() can be used if the DPI doesn't
|
||||
// matter at all (which is the case if the theme is only used to query some
|
||||
// colours, for example), but otherwise (e.g. when using the theme to get
|
||||
// any metrics) the actual DPI of the window must be passed to NewForDPI().
|
||||
static wxUxThemeHandle NewAtDPI(HWND hwnd, const wchar_t *classes, int dpi)
|
||||
{
|
||||
return wxUxThemeHandle(hwnd, classes, dpi);
|
||||
}
|
||||
|
||||
static wxUxThemeHandle NewAtStdDPI(HWND hwnd, const wchar_t *classes)
|
||||
{
|
||||
return NewAtDPI(hwnd, classes, STD_DPI);
|
||||
}
|
||||
|
||||
static wxUxThemeHandle NewAtStdDPI(const wchar_t *classes)
|
||||
{
|
||||
return NewAtStdDPI(0, classes);
|
||||
}
|
||||
|
||||
// wxWindow pointer here must be valid and its DPI is always used.
|
||||
wxUxThemeHandle(const wxWindow *win, const wchar_t *classes) :
|
||||
wxUxThemeHandle(GetHwndOf(win), classes, win->GetDPI().y)
|
||||
{
|
||||
}
|
||||
|
||||
wxUxThemeHandle(const wxWindow *win, const wchar_t *classes) :
|
||||
wxUxThemeHandle(GetHwndOf(win), classes)
|
||||
wxUxThemeHandle(wxUxThemeHandle&& other)
|
||||
: m_hTheme{other.m_hTheme}
|
||||
{
|
||||
other.m_hTheme = 0;
|
||||
}
|
||||
|
||||
operator HTHEME() const { return m_hTheme; }
|
||||
|
|
@ -195,8 +218,41 @@ public:
|
|||
// GetThemeColor() because we want to default the state.
|
||||
wxColour GetColour(int part, int prop, int state = 0) const;
|
||||
|
||||
// Return the size of a theme element, either "as is" (TS_TRUE size) or as
|
||||
// it would be used for drawing (TS_DRAW size).
|
||||
//
|
||||
// For now we don't allow specifying the HDC or rectangle as they don't
|
||||
// seem to be useful.
|
||||
wxSize GetTrueSize(int part, int state = 0) const
|
||||
{
|
||||
return DoGetSize(part, state, TS_TRUE);
|
||||
}
|
||||
|
||||
wxSize GetDrawSize(int part, int state = 0) const
|
||||
{
|
||||
return DoGetSize(part, state, TS_DRAW);
|
||||
}
|
||||
|
||||
// Draw theme background: if the caller already has a RECT, it can be
|
||||
// provided directly, otherwise wxRect is converted to it.
|
||||
void DrawBackground(HDC hdc, const RECT& rc, int part, int state = 0);
|
||||
void DrawBackground(HDC hdc, const wxRect& rect, int part, int state = 0);
|
||||
|
||||
private:
|
||||
const HTHEME m_hTheme;
|
||||
static const int STD_DPI = 96;
|
||||
|
||||
static HTHEME DoOpenThemeData(HWND hwnd, const wchar_t *classes, int dpi);
|
||||
|
||||
wxUxThemeHandle(HWND hwnd, const wchar_t *classes, int dpi) :
|
||||
m_hTheme{DoOpenThemeData(hwnd, classes, dpi)}
|
||||
{
|
||||
}
|
||||
|
||||
wxSize DoGetSize(int part, int state, THEMESIZE ts) const;
|
||||
|
||||
|
||||
// This is almost, but not quite, const: it's only reset in move ctor.
|
||||
HTHEME m_hTheme;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(wxUxThemeHandle);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,31 +35,19 @@ wxAuiMSWToolBarArt::wxAuiMSWToolBarArt()
|
|||
wxWindow* window = static_cast<wxApp*>(wxApp::GetInstance())->GetTopWindow();
|
||||
wxUxThemeHandle hTheme(window, L"Rebar");
|
||||
|
||||
SIZE overflowSize;
|
||||
::GetThemePartSize(hTheme, nullptr, RP_CHEVRON, 0,
|
||||
nullptr, TS_TRUE, &overflowSize);
|
||||
m_overflowSize = overflowSize.cx;
|
||||
m_overflowSize = hTheme.GetTrueSize(RP_CHEVRON).x;
|
||||
|
||||
SIZE gripperSize;
|
||||
::GetThemePartSize(hTheme, nullptr, RP_GRIPPER, 0,
|
||||
nullptr, TS_TRUE, &gripperSize);
|
||||
m_gripperSize = gripperSize.cx;
|
||||
m_gripperSize = hTheme.GetTrueSize(RP_GRIPPER).x;
|
||||
|
||||
wxUxThemeHandle hThemeToolbar(window, L"Toolbar");
|
||||
|
||||
SIZE seperatorSize;
|
||||
::GetThemePartSize(hThemeToolbar, nullptr, TP_SEPARATOR, 0,
|
||||
nullptr, TS_TRUE, &seperatorSize);
|
||||
m_separatorSize = seperatorSize.cx;
|
||||
m_separatorSize = hThemeToolbar.GetTrueSize(TP_SEPARATOR).x;
|
||||
|
||||
// TP_DROPDOWNBUTTON is only 7px, too small to fit the dropdown arrow,
|
||||
// use 14px instead.
|
||||
m_dropdownSize = window->FromDIP(14);
|
||||
|
||||
SIZE buttonSize;
|
||||
::GetThemePartSize(hThemeToolbar, nullptr, TP_BUTTON, 0,
|
||||
nullptr, TS_TRUE, &buttonSize);
|
||||
m_buttonSize.Set(buttonSize.cx, buttonSize.cy);
|
||||
m_buttonSize = hThemeToolbar.GetTrueSize(TP_BUTTON);
|
||||
}
|
||||
else
|
||||
m_themed = false;
|
||||
|
|
@ -77,18 +65,13 @@ void wxAuiMSWToolBarArt::DrawBackground(
|
|||
{
|
||||
if ( m_themed )
|
||||
{
|
||||
RECT r;
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"Rebar");
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
RP_BACKGROUND,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
rect,
|
||||
RP_BACKGROUND
|
||||
);
|
||||
}
|
||||
else
|
||||
wxAuiGenericToolBarArt::DrawBackground(dc, wnd, rect);
|
||||
|
|
@ -111,9 +94,6 @@ void wxAuiMSWToolBarArt::DrawButton(
|
|||
{
|
||||
if ( m_themed )
|
||||
{
|
||||
RECT r;
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"Toolbar");
|
||||
|
||||
int btnState;
|
||||
|
|
@ -131,13 +111,12 @@ void wxAuiMSWToolBarArt::DrawButton(
|
|||
else
|
||||
btnState = TS_NORMAL;
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
rect,
|
||||
TP_BUTTON,
|
||||
btnState,
|
||||
&r,
|
||||
nullptr);
|
||||
btnState
|
||||
);
|
||||
|
||||
int textWidth = 0, textHeight = 0;
|
||||
|
||||
|
|
@ -237,11 +216,6 @@ void wxAuiMSWToolBarArt::DrawDropDownButton(
|
|||
dc.GetTextExtent(item.GetLabel(), &textWidth, &ty);
|
||||
}
|
||||
|
||||
RECT btnR;
|
||||
wxCopyRectToRECT(buttonRect, btnR);
|
||||
RECT dropDownR;
|
||||
wxCopyRectToRECT(dropDownRect, dropDownR);
|
||||
|
||||
int btnState;
|
||||
if ( item.GetState() & wxAUI_BUTTON_STATE_DISABLED )
|
||||
btnState = TS_DISABLED;
|
||||
|
|
@ -252,21 +226,23 @@ void wxAuiMSWToolBarArt::DrawDropDownButton(
|
|||
else
|
||||
btnState = TS_NORMAL;
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
TP_SPLITBUTTON,
|
||||
btnState,
|
||||
&btnR,
|
||||
nullptr);
|
||||
{
|
||||
auto tempHDC = dc.GetTempHDC();
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(tempHDC),
|
||||
buttonRect,
|
||||
TP_SPLITBUTTON,
|
||||
btnState
|
||||
);
|
||||
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(tempHDC),
|
||||
dropDownRect,
|
||||
TP_SPLITBUTTONDROPDOWN,
|
||||
btnState,
|
||||
&dropDownR,
|
||||
nullptr);
|
||||
btnState
|
||||
);
|
||||
} // End of tempHDC scope.
|
||||
|
||||
const wxBitmap& bmp = item.GetCurrentBitmapFor(wnd);
|
||||
if ( !bmp.IsOk() )
|
||||
|
|
@ -332,18 +308,13 @@ void wxAuiMSWToolBarArt::DrawSeparator(
|
|||
{
|
||||
if ( m_themed )
|
||||
{
|
||||
RECT r;
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"Toolbar");
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
(m_flags & wxAUI_TB_VERTICAL) ? TP_SEPARATORVERT : TP_SEPARATOR,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
rect,
|
||||
(m_flags & wxAUI_TB_VERTICAL) ? TP_SEPARATORVERT : TP_SEPARATOR
|
||||
);
|
||||
}
|
||||
else
|
||||
wxAuiGenericToolBarArt::DrawSeparator(dc, wnd, rect);
|
||||
|
|
@ -356,18 +327,13 @@ void wxAuiMSWToolBarArt::DrawGripper(
|
|||
{
|
||||
if ( m_themed )
|
||||
{
|
||||
RECT r;
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"Rebar");
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
(m_flags & wxAUI_TB_VERTICAL) ? RP_GRIPPERVERT : RP_GRIPPER,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
rect,
|
||||
(m_flags & wxAUI_TB_VERTICAL) ? RP_GRIPPERVERT : RP_GRIPPER
|
||||
);
|
||||
}
|
||||
else
|
||||
wxAuiGenericToolBarArt::DrawGripper(dc, wnd, rect);
|
||||
|
|
@ -381,26 +347,22 @@ void wxAuiMSWToolBarArt::DrawOverflowButton(
|
|||
{
|
||||
if ( m_themed )
|
||||
{
|
||||
RECT r;
|
||||
wxCopyRectToRECT(rect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"Rebar");
|
||||
|
||||
int chevState;
|
||||
if ( state & wxAUI_BUTTON_STATE_PRESSED )
|
||||
chevState = CHEVS_PRESSED;
|
||||
else if ( state & wxAUI_BUTTON_STATE_HOVER )
|
||||
chevState = CHEVS_HOT;
|
||||
chevState = CHEVS_HOT;
|
||||
else
|
||||
chevState = CHEVS_NORMAL;
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
rect,
|
||||
(m_flags & wxAUI_TB_VERTICAL) ? RP_CHEVRONVERT : RP_CHEVRON,
|
||||
chevState,
|
||||
&r,
|
||||
nullptr);
|
||||
chevState
|
||||
);
|
||||
}
|
||||
else
|
||||
wxAuiGenericToolBarArt::DrawOverflowButton(dc, wnd, rect, state);
|
||||
|
|
|
|||
|
|
@ -59,18 +59,13 @@ void wxAuiMSWTabArt::DrawBorder(wxDC& dc, wxWindow* wnd, const wxRect& rect)
|
|||
dc.SetPen(wxPen(wnd->GetBackgroundColour(), GetBorderWidth(wnd)));
|
||||
dc.DrawRectangle(topDrawRect);
|
||||
|
||||
RECT r;
|
||||
wxCopyRectToRECT(drawRect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"TAB");
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
TABP_PANE,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
drawRect,
|
||||
TABP_PANE
|
||||
);
|
||||
}
|
||||
|
||||
void wxAuiMSWTabArt::DrawBackground(wxDC& dc,
|
||||
|
|
@ -99,18 +94,13 @@ void wxAuiMSWTabArt::DrawBackground(wxDC& dc,
|
|||
|
||||
drawRect.Inflate(1, 0);
|
||||
|
||||
RECT r;
|
||||
wxCopyRectToRECT(drawRect, r);
|
||||
|
||||
wxUxThemeHandle hTheme(wnd, L"TAB");
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
TABP_PANE,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
drawRect,
|
||||
TABP_PANE
|
||||
);
|
||||
}
|
||||
|
||||
void wxAuiMSWTabArt::DrawTab(wxDC& dc,
|
||||
|
|
@ -175,25 +165,23 @@ void wxAuiMSWTabArt::DrawTab(wxDC& dc,
|
|||
tabState = TIS_NORMAL;
|
||||
|
||||
wxUxThemeHandle hTabTheme(wnd, L"Tab");
|
||||
RECT tabR;
|
||||
wxCopyRectToRECT(tabRect, tabR);
|
||||
::DrawThemeBackground(hTabTheme, GetHdcOf(dc.GetTempHDC()), TABP_TABITEM,
|
||||
tabState,
|
||||
&tabR, nullptr);
|
||||
hTabTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
tabRect,
|
||||
TABP_TABITEM,
|
||||
tabState
|
||||
);
|
||||
|
||||
// Apparently, in at least some Windows 10 installations the call above
|
||||
// does not draw the left edge of the first tab and it needs to be drawn
|
||||
// separately, or it wouldn't be drawn at all.
|
||||
if ( tabX == GetIndentSize() )
|
||||
{
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTabTheme,
|
||||
hTabTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
tabRect,
|
||||
TABP_TABITEMLEFTEDGE,
|
||||
tabState,
|
||||
&tabR,
|
||||
nullptr
|
||||
tabState
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -234,9 +222,12 @@ void wxAuiMSWTabArt::DrawTab(wxDC& dc,
|
|||
m_closeBtnSize.x,
|
||||
m_closeBtnSize.y);
|
||||
|
||||
RECT btnR;
|
||||
wxCopyRectToRECT(rect, btnR);
|
||||
::DrawThemeBackground(hToolTipTheme, GetHdcOf(dc.GetTempHDC()), TTP_CLOSE, btnState, &btnR, nullptr);
|
||||
hToolTipTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
rect,
|
||||
TTP_CLOSE,
|
||||
btnState
|
||||
);
|
||||
|
||||
if ( out_button_rect )
|
||||
*out_button_rect = rect;
|
||||
|
|
@ -412,9 +403,12 @@ void wxAuiMSWTabArt::DrawButton(wxDC& dc,
|
|||
wxRect btnRect(rect);
|
||||
btnRect.width -= wnd->FromDIP(1);
|
||||
|
||||
RECT btnR;
|
||||
wxCopyRectToRECT(btnRect, btnR);
|
||||
::DrawThemeBackground(hTheme, GetHdcOf(dc.GetTempHDC()), part, btnState, &btnR, nullptr);
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
rect,
|
||||
part,
|
||||
btnState
|
||||
);
|
||||
|
||||
if ( out_rect )
|
||||
*out_rect = rect;
|
||||
|
|
@ -434,21 +428,14 @@ int wxAuiMSWTabArt::GetBestTabCtrlSize(wxWindow* wnd,
|
|||
return wxAuiGenericTabArt::GetBestTabCtrlSize(wnd, pages, requiredBmp_size);
|
||||
}
|
||||
|
||||
void wxAuiMSWTabArt::InitSizes(wxWindow* wnd, wxDC& dc)
|
||||
void wxAuiMSWTabArt::InitSizes(wxWindow* wnd, wxDC& WXUNUSED(dc))
|
||||
{
|
||||
SIZE uxSize;
|
||||
|
||||
// Borrow close button from tooltip (best fit on various backgrounds)
|
||||
wxUxThemeHandle hTooltipTheme(wnd, L"Tooltip");
|
||||
|
||||
::GetThemePartSize(hTooltipTheme, GetHdcOf(dc.GetTempHDC()),
|
||||
TTP_CLOSE, 0, nullptr, TS_TRUE, &uxSize);
|
||||
m_closeBtnSize.Set(uxSize.cx, uxSize.cy);
|
||||
m_closeBtnSize = hTooltipTheme.GetTrueSize(TTP_CLOSE);
|
||||
|
||||
wxUxThemeHandle hTabTheme(wnd, L"Tab");
|
||||
::GetThemePartSize(hTabTheme, GetHdcOf(dc.GetTempHDC()),
|
||||
TABP_TABITEM, 0, nullptr, TS_TRUE, &uxSize);
|
||||
m_tabSize.Set(uxSize.cx, uxSize.cy);
|
||||
m_tabSize = hTabTheme.GetTrueSize(TABP_TABITEM);
|
||||
}
|
||||
|
||||
bool wxAuiMSWTabArt::IsThemed() const
|
||||
|
|
|
|||
|
|
@ -1288,8 +1288,7 @@ void DrawXPBackground(wxAnyButton *button, HDC hdc, RECT& rectBtn, UINT state)
|
|||
}
|
||||
|
||||
// draw background
|
||||
::DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
|
||||
&rectBtn, nullptr);
|
||||
theme.DrawBackground(hdc, rectBtn, BP_PUSHBUTTON, iState);
|
||||
|
||||
// calculate content area margins, using the defaults in case we fail to
|
||||
// retrieve the current theme margins
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
|
|||
// Draw the control background (including the border)
|
||||
if ( m_widthCustomBorder > 0 )
|
||||
{
|
||||
::DrawThemeBackground( hTheme, hDc, comboBoxPart, bgState, rUseForBg, nullptr );
|
||||
hTheme.DrawBackground(hDc, *rUseForBg, comboBoxPart, bgState);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -462,7 +462,7 @@ void wxComboCtrl::OnPaintEvent( wxPaintEvent& WXUNUSED(event) )
|
|||
else
|
||||
butPart = CP_DROPDOWNBUTTONLEFT;
|
||||
|
||||
::DrawThemeBackground( hTheme, hDc, butPart, butState, &rButton, nullptr );
|
||||
hTheme.DrawBackground(hDc, rButton, butPart, butState);
|
||||
}
|
||||
else if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
#include "wx/msw/dc.h"
|
||||
#include "wx/msw/uxtheme.h"
|
||||
|
||||
#include "wx/msw/private/custompaint.h"
|
||||
#include "wx/msw/private/darkmode.h"
|
||||
|
||||
#include <memory>
|
||||
|
|
@ -431,32 +432,35 @@ HBRUSH GetBackgroundBrush()
|
|||
return brush ? GetHbrushOf(*brush) : 0;
|
||||
}
|
||||
|
||||
#if wxUSE_IMAGE
|
||||
|
||||
static void
|
||||
InvertBitmapPixel(unsigned char& r, unsigned char& g, unsigned char& b,
|
||||
unsigned char& WXUNUSED(a))
|
||||
{
|
||||
wxImage::RGBValue rgb(r, g, b);
|
||||
wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
|
||||
|
||||
// There is no really good way to convert normal colours to dark mode,
|
||||
// but try to do a bit better than just inverting the value because
|
||||
// this results in colours which are much too dark.
|
||||
hsv.value = sqrt(1.0 - hsv.value*hsv.value);
|
||||
|
||||
rgb = wxImage::HSVtoRGB(hsv);
|
||||
|
||||
r = rgb.red;
|
||||
g = rgb.green;
|
||||
b = rgb.blue;
|
||||
}
|
||||
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
wxBitmap InvertBitmap(const wxBitmap& bmp)
|
||||
{
|
||||
#if wxUSE_IMAGE
|
||||
wxImage image = bmp.ConvertToImage();
|
||||
|
||||
unsigned char *data = image.GetData();
|
||||
const int len = image.GetWidth()*image.GetHeight();
|
||||
for ( int i = 0; i < len; ++i, data += 3 )
|
||||
{
|
||||
wxImage::RGBValue rgb(data[0], data[1], data[2]);
|
||||
wxImage::HSVValue hsv = wxImage::RGBtoHSV(rgb);
|
||||
|
||||
// There is no really good way to convert normal colours to dark mode,
|
||||
// but try to do a bit better than just inverting the value because
|
||||
// this results in colours which are much too dark.
|
||||
hsv.value = sqrt(1.0 - hsv.value*hsv.value);
|
||||
|
||||
rgb = wxImage::HSVtoRGB(hsv);
|
||||
data[0] = rgb.red;
|
||||
data[1] = rgb.green;
|
||||
data[2] = rgb.blue;
|
||||
}
|
||||
|
||||
return wxBitmap(image);
|
||||
return wxMSWImpl::PostPaintEachPixel(bmp, InvertBitmapPixel);
|
||||
#else // !wxUSE_IMAGE
|
||||
return wxBitmap();
|
||||
return bmp;
|
||||
#endif // wxUSE_IMAGE/!wxUSE_IMAGE
|
||||
}
|
||||
|
||||
|
|
@ -466,29 +470,18 @@ bool PaintIfNecessary(HWND hwnd, WXWNDPROC defWndProc)
|
|||
if ( !wxMSWImpl::ShouldUseDarkMode() )
|
||||
return false;
|
||||
|
||||
const RECT rc = wxGetClientRect(hwnd);
|
||||
const wxSize size{rc.right - rc.left, rc.bottom - rc.top};
|
||||
|
||||
// Don't bother doing anything with the empty windows.
|
||||
if ( size == wxSize() )
|
||||
return false;
|
||||
|
||||
// Ask the control to paint itself on the given bitmap.
|
||||
wxBitmap bmp(size);
|
||||
{
|
||||
wxMemoryDC mdc(bmp);
|
||||
|
||||
WPARAM wparam = (WPARAM)GetHdcOf(mdc);
|
||||
if ( defWndProc )
|
||||
::CallWindowProc(defWndProc, hwnd, WM_PAINT, wparam, 0);
|
||||
else
|
||||
::DefWindowProc(hwnd, WM_PAINT, wparam, 0);
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
wxDCTemp dc(::BeginPaint(hwnd, &ps), size);
|
||||
dc.DrawBitmap(InvertBitmap(bmp), 0, 0);
|
||||
::EndPaint(hwnd, &ps);
|
||||
wxMSWImpl::CustomPaint
|
||||
(
|
||||
hwnd,
|
||||
[defWndProc](HWND hwnd, WPARAM wParam)
|
||||
{
|
||||
if ( defWndProc )
|
||||
::CallWindowProc(defWndProc, hwnd, WM_PAINT, wParam, 0);
|
||||
else
|
||||
::DefWindowProc(hwnd, WM_PAINT, wParam, 0);
|
||||
},
|
||||
InvertBitmap
|
||||
);
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_IMAGE
|
||||
|
|
@ -690,7 +683,7 @@ HandleMenuMessage(WXLRESULT* result,
|
|||
if ( itemState & ODS_NOACCEL)
|
||||
drawTextFlags |= DT_HIDEPREFIX;
|
||||
|
||||
wxUxThemeHandle menuTheme(GetHwndOf(w), L"Menu");
|
||||
wxUxThemeHandle menuTheme(w, L"Menu");
|
||||
::DrawThemeTextEx(menuTheme, dis.hDC, MENU_BARITEM, partState,
|
||||
buf, mii.cch, drawTextFlags, rcItem,
|
||||
&textOpts);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@
|
|||
#endif
|
||||
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/private/custompaint.h"
|
||||
#include "wx/msw/private/darkmode.h"
|
||||
#include "wx/msw/wrapcctl.h"
|
||||
|
||||
#include "wx/evtloop.h"
|
||||
#include "wx/scopedptr.h"
|
||||
|
|
@ -76,6 +78,70 @@ wxDEFINE_TIED_SCOPED_PTR_TYPE(wxDialogModalData)
|
|||
// implementation
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Gripper subclass proc
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace wxMSWImpl
|
||||
{
|
||||
|
||||
LRESULT CALLBACK
|
||||
GripperProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam,
|
||||
UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
wxDialog* const self = reinterpret_cast<wxDialog*>(dwRefData);
|
||||
|
||||
switch ( nMsg )
|
||||
{
|
||||
case WM_PAINT:
|
||||
{
|
||||
const auto bg = self->GetBackgroundColour();
|
||||
|
||||
wxMSWImpl::CustomPaint
|
||||
(
|
||||
hwnd,
|
||||
[](HWND hwnd, WPARAM wParam)
|
||||
{
|
||||
::DefSubclassProc(hwnd, WM_PAINT, wParam, 0);
|
||||
},
|
||||
[bg](const wxBitmap& bmp)
|
||||
{
|
||||
return wxMSWImpl::PostPaintEachPixel
|
||||
(
|
||||
bmp,
|
||||
[bg](unsigned char& r,
|
||||
unsigned char& g,
|
||||
unsigned char& b,
|
||||
unsigned char& a)
|
||||
{
|
||||
// Replace all background pixels, which
|
||||
// are transparent, with the colour we
|
||||
// want to use.
|
||||
if ( a == wxALPHA_TRANSPARENT )
|
||||
{
|
||||
r = bg.Red();
|
||||
g = bg.Green();
|
||||
b = bg.Blue();
|
||||
|
||||
a = wxALPHA_OPAQUE;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
::RemoveWindowSubclass(hwnd, GripperProc, uIdSubclass);
|
||||
break;
|
||||
}
|
||||
|
||||
return ::DefSubclassProc(hwnd, nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace wxMSWImpl
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxDialog construction
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -243,6 +309,13 @@ void wxDialog::CreateGripper()
|
|||
);
|
||||
|
||||
wxMSWDarkMode::AllowForWindow((HWND)m_hGripper);
|
||||
|
||||
// Whether we use the dark mode or not, handle WM_PAINT for the gripper
|
||||
// ourselves, as even in the light mode its background is wrong if the
|
||||
// dialog doesn't use the default background colour -- and in dark mode
|
||||
// it's wrong even by default.
|
||||
::SetWindowSubclass(m_hGripper, wxMSWImpl::GripperProc,
|
||||
0, wxPtrToUInt(this));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ wxVisualAttributes wxListCtrl::GetDefaultAttributes() const
|
|||
// Note that we intentionally do not use this window HWND for the
|
||||
// theme, as it doesn't have dark values for it -- but does have them
|
||||
// when we use null window.
|
||||
wxUxThemeHandle theme{HWND(0), L"ItemsView"};
|
||||
auto theme = wxUxThemeHandle::NewAtStdDPI(L"ItemsView");
|
||||
|
||||
wxColour col = theme.GetColour(0, TMT_TEXTCOLOR);
|
||||
if ( col.IsOk() )
|
||||
|
|
|
|||
|
|
@ -958,25 +958,19 @@ bool wxMenuItem::OnDrawItem(wxDC& dc, const wxRect& rc,
|
|||
if ( ::IsThemeBackgroundPartiallyTransparent(hTheme,
|
||||
MENU_POPUPITEM, state) )
|
||||
{
|
||||
::DrawThemeBackground(hTheme, hdc,
|
||||
MENU_POPUPBACKGROUND,
|
||||
0, &rect, nullptr);
|
||||
hTheme.DrawBackground(hdc, rect, MENU_POPUPBACKGROUND);
|
||||
}
|
||||
|
||||
::DrawThemeBackground(hTheme, hdc, MENU_POPUPGUTTER,
|
||||
0, &rcGutter, nullptr);
|
||||
hTheme.DrawBackground(hdc, rcGutter, MENU_POPUPGUTTER);
|
||||
|
||||
if ( IsSeparator() )
|
||||
{
|
||||
rcSeparator.left = rcGutter.right;
|
||||
::DrawThemeBackground(hTheme, hdc, MENU_POPUPSEPARATOR,
|
||||
0, &rcSeparator, nullptr);
|
||||
hTheme.DrawBackground(hdc, rcSeparator, MENU_POPUPSEPARATOR);
|
||||
return true;
|
||||
}
|
||||
|
||||
::DrawThemeBackground(hTheme, hdc, MENU_POPUPITEM,
|
||||
state, &rcSelection, nullptr);
|
||||
|
||||
hTheme.DrawBackground(hdc, rcSelection, MENU_POPUPITEM, state);
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
|
@ -1192,8 +1186,7 @@ void wxMenuItem::DrawStdCheckMark(WXHDC hdc_, const RECT* rc, wxODStatus stat)
|
|||
? MCB_DISABLED
|
||||
: MCB_NORMAL;
|
||||
|
||||
::DrawThemeBackground(hTheme, hdc, MENU_POPUPCHECKBACKGROUND,
|
||||
stateCheckBg, &rcBg, nullptr);
|
||||
hTheme.DrawBackground(hdc, rcBg, MENU_POPUPCHECKBACKGROUND, stateCheckBg);
|
||||
|
||||
POPUPCHECKSTATES stateCheck;
|
||||
if ( GetKind() == wxITEM_CHECK )
|
||||
|
|
@ -1207,8 +1200,7 @@ void wxMenuItem::DrawStdCheckMark(WXHDC hdc_, const RECT* rc, wxODStatus stat)
|
|||
: MC_BULLETNORMAL;
|
||||
}
|
||||
|
||||
::DrawThemeBackground(hTheme, hdc, MENU_POPUPCHECK,
|
||||
stateCheck, rc, nullptr);
|
||||
hTheme.DrawBackground(hdc, *rc, MENU_POPUPCHECK, stateCheck);
|
||||
}
|
||||
else
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
|
|
|||
|
|
@ -1651,7 +1651,7 @@ WXHBRUSH wxNotebook::QueryBgBitmap()
|
|||
RECT rcBg;
|
||||
::GetThemeBackgroundContentRect(theme,
|
||||
(HDC) hDC,
|
||||
9, /* TABP_PANE */
|
||||
TABP_PANE,
|
||||
0,
|
||||
&rc,
|
||||
&rcBg);
|
||||
|
|
@ -1663,7 +1663,7 @@ WXHBRUSH wxNotebook::QueryBgBitmap()
|
|||
(
|
||||
theme,
|
||||
(HDC) hDC,
|
||||
9 /* TABP_PANE */,
|
||||
TABP_PANE,
|
||||
0,
|
||||
&rcBg,
|
||||
&rc
|
||||
|
|
@ -1674,15 +1674,7 @@ WXHBRUSH wxNotebook::QueryBgBitmap()
|
|||
|
||||
{
|
||||
SelectInHDC selectBmp(hDCMem, hBmp);
|
||||
::DrawThemeBackground
|
||||
(
|
||||
theme,
|
||||
hDCMem,
|
||||
9 /* TABP_PANE */,
|
||||
0,
|
||||
&rc,
|
||||
nullptr
|
||||
);
|
||||
theme.DrawBackground(hDCMem, rc, TABP_PANE);
|
||||
} // deselect bitmap from the memory HDC before using it
|
||||
|
||||
return (WXHBRUSH)::CreatePatternBrush(hBmp);
|
||||
|
|
@ -1738,20 +1730,13 @@ bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
|
|||
(
|
||||
theme,
|
||||
(HDC) hDC,
|
||||
9 /* TABP_PANE */,
|
||||
TABP_PANE,
|
||||
0,
|
||||
&rc,
|
||||
&rc
|
||||
);
|
||||
::DrawThemeBackground
|
||||
(
|
||||
theme,
|
||||
(HDC) hDC,
|
||||
9 /* TABP_PANE */,
|
||||
0,
|
||||
&rc,
|
||||
nullptr
|
||||
);
|
||||
|
||||
theme.DrawBackground((HDC) hDC, rc, TABP_PANE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ private:
|
|||
// wrapper around DrawThemeBackground() translating flags to NORMAL/HOT/
|
||||
// PUSHED/DISABLED states (and so suitable for drawing anything
|
||||
// button-like)
|
||||
void DoDrawButtonLike(HTHEME htheme,
|
||||
void DoDrawButtonLike(wxUxThemeHandle& hTheme,
|
||||
int part,
|
||||
wxDC& dc,
|
||||
const wxRect& rect,
|
||||
|
|
@ -644,16 +644,7 @@ wxRendererXP::DrawComboBoxDropButton(wxWindow * win,
|
|||
else
|
||||
state = CBXS_NORMAL;
|
||||
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
CP_DROPDOWNBUTTON,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), r, CP_DROPDOWNBUTTON, state);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -681,15 +672,8 @@ wxRendererXP::DrawHeaderButton(wxWindow *win,
|
|||
state = HIS_HOT;
|
||||
else
|
||||
state = HIS_NORMAL;
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
HP_HEADERITEM,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), r, HP_HEADERITEM, state);
|
||||
|
||||
// NOTE: Using the theme to draw HP_HEADERSORTARROW doesn't do anything.
|
||||
// Why? If this can be fixed then draw the sort arrows using the theme
|
||||
|
|
@ -718,15 +702,8 @@ wxRendererXP::DrawTreeItemButton(wxWindow *win,
|
|||
RECT r = ConvertToRECT(dc, rect);
|
||||
|
||||
int state = flags & wxCONTROL_EXPANDED ? GLPS_OPENED : GLPS_CLOSED;
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
TVP_GLYPH,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), r, TVP_GLYPH, state);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -764,21 +741,13 @@ wxRendererXP::DoDrawCheckMark(int kind,
|
|||
if ( flags & wxCONTROL_DISABLED )
|
||||
state = MC_CHECKMARKDISABLED;
|
||||
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
kind,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), r, kind, state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
wxRendererXP::DoDrawButtonLike(HTHEME htheme,
|
||||
wxRendererXP::DoDrawButtonLike(wxUxThemeHandle& hTheme,
|
||||
int part,
|
||||
wxDC& dc,
|
||||
const wxRect& rect,
|
||||
|
|
@ -820,15 +789,7 @@ wxRendererXP::DoDrawButtonLike(HTHEME htheme,
|
|||
else if ( part == BP_PUSHBUTTON && (flags & wxCONTROL_ISDEFAULT) )
|
||||
state = PBS_DEFAULTED;
|
||||
|
||||
::DrawThemeBackground
|
||||
(
|
||||
htheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
part,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), r, part, state);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -885,9 +846,7 @@ wxSize wxRendererXP::GetCheckBoxSize(wxWindow* win, int flags)
|
|||
{
|
||||
if (::IsThemePartDefined(hTheme, BP_CHECKBOX, 0))
|
||||
{
|
||||
SIZE checkSize;
|
||||
if (::GetThemePartSize(hTheme, nullptr, BP_CHECKBOX, CBS_UNCHECKEDNORMAL, nullptr, TS_DRAW, &checkSize) == S_OK)
|
||||
return wxSize(checkSize.cx, checkSize.cy);
|
||||
return hTheme.GetDrawSize(BP_CHECKBOX, CBS_UNCHECKEDNORMAL);
|
||||
}
|
||||
}
|
||||
return m_rendererNative.GetCheckBoxSize(win, flags);
|
||||
|
|
@ -902,9 +861,7 @@ wxSize wxRendererXP::GetCheckMarkSize(wxWindow* win)
|
|||
{
|
||||
if (::IsThemePartDefined(hTheme, MENU_POPUPCHECK, 0))
|
||||
{
|
||||
SIZE checkSize;
|
||||
if (::GetThemePartSize(hTheme, nullptr, MENU_POPUPCHECK, MC_CHECKMARKNORMAL, nullptr, TS_DRAW, &checkSize) == S_OK)
|
||||
return wxSize(checkSize.cx, checkSize.cy);
|
||||
return hTheme.GetDrawSize(MENU_POPUPCHECK, MC_CHECKMARKNORMAL);
|
||||
}
|
||||
}
|
||||
return m_rendererNative.GetCheckMarkSize(win);
|
||||
|
|
@ -919,11 +876,7 @@ wxSize wxRendererXP::GetExpanderSize(wxWindow* win)
|
|||
{
|
||||
if ( ::IsThemePartDefined(hTheme, TVP_GLYPH, 0) )
|
||||
{
|
||||
SIZE expSize;
|
||||
if (::GetThemePartSize(hTheme, nullptr, TVP_GLYPH, GLPS_CLOSED, nullptr,
|
||||
TS_DRAW, &expSize) == S_OK)
|
||||
return wxSize(expSize.cx, expSize.cy);
|
||||
|
||||
return hTheme.GetDrawSize(TVP_GLYPH, GLPS_CLOSED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -948,15 +901,8 @@ DoDrawCollapseButton(wxWindow* win, HDC hdc, RECT r, int flags)
|
|||
if ( flags & wxCONTROL_EXPANDED )
|
||||
state += 3;
|
||||
|
||||
::DrawThemeBackground
|
||||
(
|
||||
hTheme,
|
||||
hdc,
|
||||
TDLG_EXPANDOBUTTON,
|
||||
state,
|
||||
&r,
|
||||
nullptr
|
||||
);
|
||||
hTheme.DrawBackground(hdc, r, TDLG_EXPANDOBUTTON, state);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1014,19 +960,10 @@ wxSize wxRendererXP::GetCollapseButtonSize(wxWindow *win, wxDC& dc)
|
|||
|
||||
if ( ::IsThemePartDefined(hTheme, TDLG_EXPANDOBUTTON, 0) )
|
||||
{
|
||||
SIZE s;
|
||||
::GetThemePartSize(hTheme,
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
TDLG_EXPANDOBUTTON,
|
||||
TDLGEBS_NORMAL,
|
||||
nullptr,
|
||||
TS_TRUE,
|
||||
&s);
|
||||
|
||||
return wxSize(s.cx, s.cy);
|
||||
return hTheme.GetTrueSize(TDLG_EXPANDOBUTTON, TDLGEBS_NORMAL);
|
||||
}
|
||||
else
|
||||
return m_rendererNative.GetCollapseButtonSize(win, dc);
|
||||
|
||||
return m_rendererNative.GetCollapseButtonSize(win, dc);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1046,7 +983,7 @@ wxRendererXP::DrawItemSelectionRect(wxWindow *win,
|
|||
if ( ::IsThemeBackgroundPartiallyTransparent(hTheme, LVP_LISTITEM, itemState) )
|
||||
::DrawThemeParentBackground(GetHwndOf(win), GetHdcOf(dc.GetTempHDC()), &rc);
|
||||
|
||||
::DrawThemeBackground(hTheme, GetHdcOf(dc.GetTempHDC()), LVP_LISTITEM, itemState, &rc, 0);
|
||||
hTheme.DrawBackground(GetHdcOf(dc.GetTempHDC()), rc, LVP_LISTITEM, itemState);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1292,13 +1229,11 @@ void wxRendererXP::DrawGauge(wxWindow* win,
|
|||
|
||||
RECT r = ConvertToRECT(dc, rect);
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
flags & wxCONTROL_SPECIAL ? PP_BARVERT : PP_BAR,
|
||||
0,
|
||||
&r,
|
||||
nullptr);
|
||||
r,
|
||||
flags & wxCONTROL_SPECIAL ? PP_BARVERT : PP_BAR
|
||||
);
|
||||
|
||||
RECT contentRect;
|
||||
::GetThemeBackgroundContentRect(
|
||||
|
|
@ -1325,13 +1260,11 @@ void wxRendererXP::DrawGauge(wxWindow* win,
|
|||
max);
|
||||
}
|
||||
|
||||
::DrawThemeBackground(
|
||||
hTheme,
|
||||
hTheme.DrawBackground(
|
||||
GetHdcOf(dc.GetTempHDC()),
|
||||
flags & wxCONTROL_SPECIAL ? PP_CHUNKVERT : PP_CHUNK,
|
||||
0,
|
||||
&contentRect,
|
||||
nullptr);
|
||||
contentRect,
|
||||
flags & wxCONTROL_SPECIAL ? PP_CHUNKVERT : PP_CHUNK
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#endif
|
||||
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/private/custompaint.h"
|
||||
#include "wx/msw/private/darkmode.h"
|
||||
|
||||
#include "wx/tooltip.h"
|
||||
|
|
@ -203,7 +204,7 @@ void wxStatusBar::MSWUpdateFieldsWidths()
|
|||
|
||||
// update the field widths in the native control:
|
||||
|
||||
int *pWidths = new int[count];
|
||||
std::vector<int> pWidths(count);
|
||||
|
||||
int nCurPos = 0;
|
||||
int i;
|
||||
|
|
@ -218,7 +219,7 @@ void wxStatusBar::MSWUpdateFieldsWidths()
|
|||
// separator line just before it.
|
||||
pWidths[count - 1] += gripWidth;
|
||||
|
||||
if ( !StatusBar_SetParts(GetHwnd(), count, pWidths) )
|
||||
if ( !StatusBar_SetParts(GetHwnd(), count, &pWidths[0]) )
|
||||
{
|
||||
wxLogLastError("StatusBar_SetParts");
|
||||
}
|
||||
|
|
@ -228,8 +229,6 @@ void wxStatusBar::MSWUpdateFieldsWidths()
|
|||
{
|
||||
DoUpdateStatusText(i);
|
||||
}
|
||||
|
||||
delete [] pWidths;
|
||||
}
|
||||
|
||||
void wxStatusBar::DoUpdateStatusText(int nField)
|
||||
|
|
@ -573,17 +572,12 @@ wxStatusBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
|||
// resizing. It is possible to send this message to any window.
|
||||
if ( wParam == HTBOTTOMRIGHT )
|
||||
{
|
||||
wxWindow *win;
|
||||
|
||||
for ( win = GetParent(); win; win = win->GetParent() )
|
||||
if ( wxWindow *win = wxGetTopLevelParent(this) )
|
||||
{
|
||||
if ( win->IsTopLevel() )
|
||||
{
|
||||
SendMessage(GetHwndOf(win), WM_NCLBUTTONDOWN,
|
||||
wParam, lParam);
|
||||
SendMessage(GetHwndOf(win), WM_NCLBUTTONDOWN,
|
||||
wParam, lParam);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -605,6 +599,51 @@ wxStatusBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
|||
}
|
||||
}
|
||||
|
||||
#if wxUSE_UXTHEME
|
||||
// We need to paint the size grip ourselves in dark mode as the default one
|
||||
// is simply invisible.
|
||||
if ( nMsg == WM_PAINT &&
|
||||
(::GetWindowLong(GetHwnd(), GWL_STYLE) & SBARS_SIZEGRIP) &&
|
||||
wxMSWDarkMode::IsActive() )
|
||||
{
|
||||
wxMSWImpl::CustomPaint
|
||||
(
|
||||
GetHwnd(),
|
||||
[this](HWND hwnd, WPARAM wParam)
|
||||
{
|
||||
m_oldWndProc(hwnd, WM_PAINT, wParam, 0);
|
||||
},
|
||||
[this](const wxBitmap& bmpOrig)
|
||||
{
|
||||
wxBitmap bmp(bmpOrig);
|
||||
wxMemoryDC dc(bmp);
|
||||
|
||||
// Note that we must _not_ open theme data for this window: it
|
||||
// uses "ExplorerStatusBar" theme which doesn't draw SP_GRIPPER
|
||||
// correctly (which is why we have to draw it ourselves).
|
||||
auto theme = wxUxThemeHandle::NewAtDPI(0, L"Status", GetDPI().y);
|
||||
if ( !theme )
|
||||
return bmp;
|
||||
|
||||
const wxRect rectTotal(bmp.GetSize());
|
||||
|
||||
const wxSize sizeGrip = theme.GetDrawSize(SP_GRIPPER);
|
||||
|
||||
// Draw the grip in the lower right corner of the window.
|
||||
//
|
||||
// TODO-RTL: Is this correct for RTL layout?
|
||||
wxRect rect(sizeGrip);
|
||||
rect.x = rectTotal.width - sizeGrip.x;
|
||||
rect.y = rectTotal.height - sizeGrip.y;
|
||||
|
||||
theme.DrawBackground(dc.GetHDC(), rect, SP_GRIPPER);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
);
|
||||
}
|
||||
#endif // wxUSE_UXTHEME
|
||||
|
||||
return wxStatusBarBase::MSWWindowProc(nMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
|
@ -653,7 +692,8 @@ bool wxStatusBar::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM* W
|
|||
|
||||
bool wxStatusBar::MSWGetDarkModeSupport(MSWDarkModeSupport& support) const
|
||||
{
|
||||
// This is not documented anywhere but seems to work.
|
||||
// This is not documented anywhere but seems to work (except for the size
|
||||
// grip which we draw ourselves in our WM_PAINT handler).
|
||||
//
|
||||
// Note that we should _not_ set the theme name to "Explorer", this ID only
|
||||
// works if we do _not_ do it.
|
||||
|
|
@ -677,7 +717,7 @@ wxStatusBar::GetClassDefaultAttributes(wxWindowVariant variant)
|
|||
if ( wxMSWDarkMode::IsActive() )
|
||||
{
|
||||
// It looks like we don't have to use a valid HWND here.
|
||||
wxUxThemeHandle theme{HWND(0), L"ExplorerStatusBar"};
|
||||
auto theme = wxUxThemeHandle::NewAtStdDPI(L"ExplorerStatusBar");
|
||||
|
||||
wxColour col = theme.GetColour(0, TMT_TEXTCOLOR);
|
||||
if ( col.IsOk() )
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@
|
|||
#include "wx/module.h"
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/dynlib.h"
|
||||
|
||||
#include "wx/msw/uxtheme.h"
|
||||
|
||||
bool wxUxThemeIsActive()
|
||||
|
|
@ -37,6 +39,33 @@ bool wxUxThemeIsActive()
|
|||
return ::IsAppThemed() && ::IsThemeActive();
|
||||
}
|
||||
|
||||
/* static */
|
||||
HTHEME
|
||||
wxUxThemeHandle::DoOpenThemeData(HWND hwnd, const wchar_t *classes, int dpi)
|
||||
{
|
||||
// If DPI is the default one, we can use the old function.
|
||||
if ( dpi != STD_DPI )
|
||||
{
|
||||
// We need to use OpenThemeDataForDpi() which is not available under
|
||||
// all supported systems, so try to load it dynamically if not done yet.
|
||||
typedef HTHEME (WINAPI *OpenThemeDataForDpi_t)(HWND, LPCWSTR, UINT);
|
||||
static OpenThemeDataForDpi_t s_pfnOpenThemeDataForDpi = nullptr;
|
||||
static bool s_initDone = false;
|
||||
|
||||
if ( !s_initDone )
|
||||
{
|
||||
wxLoadedDLL dllUxTheme(wxS("uxtheme.dll"));
|
||||
wxDL_INIT_FUNC(s_pfn, OpenThemeDataForDpi, dllUxTheme);
|
||||
s_initDone = true;
|
||||
}
|
||||
|
||||
if ( s_pfnOpenThemeDataForDpi )
|
||||
return s_pfnOpenThemeDataForDpi(hwnd, classes, dpi);
|
||||
}
|
||||
|
||||
return ::OpenThemeData(hwnd, classes);
|
||||
}
|
||||
|
||||
wxColour wxUxThemeHandle::GetColour(int part, int prop, int state) const
|
||||
{
|
||||
COLORREF col;
|
||||
|
|
@ -53,6 +82,46 @@ wxColour wxUxThemeHandle::GetColour(int part, int prop, int state) const
|
|||
|
||||
return wxRGBToColour(col);
|
||||
}
|
||||
|
||||
wxSize wxUxThemeHandle::DoGetSize(int part, int state, THEMESIZE ts) const
|
||||
{
|
||||
SIZE size;
|
||||
HRESULT hr = ::GetThemePartSize(m_hTheme, nullptr, part, state, nullptr, ts,
|
||||
&size);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
wxLogApiError(
|
||||
wxString::Format("GetThemePartSize(%i, %i)", part, state),
|
||||
hr
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
return wxSize{size.cx, size.cy};
|
||||
}
|
||||
|
||||
void
|
||||
wxUxThemeHandle::DrawBackground(HDC hdc, const RECT& rc, int part, int state)
|
||||
{
|
||||
HRESULT hr = ::DrawThemeBackground(m_hTheme, hdc, part, state, &rc, nullptr);
|
||||
if ( FAILED(hr) )
|
||||
{
|
||||
wxLogApiError(
|
||||
wxString::Format("DrawThemeBackground(%i, %i)", part, state),
|
||||
hr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
wxUxThemeHandle::DrawBackground(HDC hdc, const wxRect& rect, int part, int state)
|
||||
{
|
||||
RECT rc;
|
||||
wxCopyRectToRECT(rect, rc);
|
||||
|
||||
DrawBackground(hdc, rc, part, state);
|
||||
}
|
||||
|
||||
#else
|
||||
bool wxUxThemeIsActive()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3970,7 +3970,7 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
|||
}
|
||||
|
||||
// Draw the border
|
||||
::DrawThemeBackground(hTheme, GetHdcOf(*impl), EP_EDITTEXT, nState, &rcBorder, nullptr);
|
||||
hTheme.DrawBackground(GetHdcOf(*impl), rcBorder, EP_EDITTEXT, nState);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue