Add MSWShouldUseAutoDarkMode() and use it for wxSpinButton
This control doesn't seem to support dark mode natively, whichever theme is used for it, so paint it in dark mode ourselves simply by inverting its colours -- this is not great, but passable and better than leaving it with a light background. As this probably won't be the only control which will need this, implement it at wxWindow level and allow the derived classes to opt-in this "automatic dark mode support" by simply overriding the new MSWShouldUseAutoDarkMode() function.
This commit is contained in:
parent
9106a8306e
commit
cb85871831
6 changed files with 90 additions and 1 deletions
|
|
@ -35,6 +35,14 @@ wxColour GetColour(wxSystemColour index);
|
|||
// Return the background brush to be used by default in dark mode.
|
||||
HBRUSH GetBackgroundBrush();
|
||||
|
||||
// If dark mode is active, paint the given window using inverted colours.
|
||||
// Otherwise just return false without doing anything.
|
||||
//
|
||||
// This 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.
|
||||
bool PaintIfNecessary(wxWindow* w);
|
||||
|
||||
} // namespace wxMSWDarkMode
|
||||
|
||||
#endif // _WX_MSW_PRIVATE_DARKMODE_H_
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ public:
|
|||
virtual void SetIncrement(int value) override;
|
||||
virtual int GetIncrement() const override;
|
||||
|
||||
virtual bool MSWShouldUseAutoDarkMode() const override;
|
||||
|
||||
protected:
|
||||
virtual wxSize DoGetBestSize() const override;
|
||||
|
||||
|
|
|
|||
|
|
@ -211,6 +211,13 @@ public:
|
|||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
||||
// Override this to return true to automatically invert the window colours
|
||||
// in dark mode.
|
||||
//
|
||||
// This doesn't result in visually great results, but may still be better
|
||||
// than using light background.
|
||||
virtual bool MSWShouldUseAutoDarkMode() const { return false; }
|
||||
|
||||
public:
|
||||
// Windows subclassing
|
||||
void SubclassWin(WXHWND hWnd);
|
||||
|
|
|
|||
|
|
@ -34,12 +34,16 @@
|
|||
|
||||
#ifndef WX_PRECOMP
|
||||
#include "wx/app.h"
|
||||
#include "wx/bitmap.h"
|
||||
#include "wx/dcmemory.h"
|
||||
#include "wx/image.h"
|
||||
#include "wx/log.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "wx/dynlib.h"
|
||||
#include "wx/module.h"
|
||||
|
||||
#include "wx/msw/dc.h"
|
||||
#include "wx/msw/uxtheme.h"
|
||||
|
||||
static const char* TRACE_DARKMODE = "msw-darkmode";
|
||||
|
|
@ -335,6 +339,57 @@ HBRUSH GetBackgroundBrush()
|
|||
return brush ? GetHbrushOf(*brush) : 0;
|
||||
}
|
||||
|
||||
bool PaintIfNecessary(wxWindow* w)
|
||||
{
|
||||
#if wxUSE_IMAGE
|
||||
if ( !wxMSWImpl::ShouldUseDarkMode() )
|
||||
return false;
|
||||
|
||||
const wxSize size = w->GetClientSize();
|
||||
|
||||
// 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);
|
||||
w->MSWDefWindowProc(WM_PAINT, (WPARAM)GetHdcOf(mdc), 0);
|
||||
}
|
||||
|
||||
wxImage image = bmp.ConvertToImage();
|
||||
|
||||
unsigned char *data = image.GetData();
|
||||
for ( int i = 0; i < size.x*size.y; ++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;
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
wxDCTemp dc(::BeginPaint(GetHwndOf(w), &ps), size);
|
||||
dc.DrawBitmap(wxBitmap(image), 0, 0);
|
||||
::EndPaint(GetHwndOf(w), &ps);
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_IMAGE
|
||||
wxUnusedVar(w);
|
||||
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace wxMSWDarkMode
|
||||
|
||||
#else // !wxUSE_DARK_MODE
|
||||
|
|
@ -370,6 +425,11 @@ HBRUSH GetBackgroundBrush()
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool PaintIfNecessary(wxWindow* WXUNUSED(w))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace wxMSWDarkMode
|
||||
|
||||
#endif // wxUSE_DARK_MODE/!wxUSE_DARK_MODE
|
||||
|
|
|
|||
|
|
@ -139,6 +139,13 @@ wxSpinButton::~wxSpinButton()
|
|||
{
|
||||
}
|
||||
|
||||
bool wxSpinButton::MSWShouldUseAutoDarkMode() const
|
||||
{
|
||||
// Native control doesn't seem to have any support for dark theme, so
|
||||
// invert it in dark mode -- this is not great, but better than nothing.
|
||||
return true;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// size calculation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@
|
|||
#endif
|
||||
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/private/darkmode.h"
|
||||
#include "wx/msw/private/dpiaware.h"
|
||||
#include "wx/msw/private/keyboard.h"
|
||||
#include "wx/msw/private/paint.h"
|
||||
|
|
@ -3132,7 +3133,11 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
|||
}
|
||||
else // no DC given
|
||||
{
|
||||
processed = HandlePaint();
|
||||
if ( MSWShouldUseAutoDarkMode() &&
|
||||
wxMSWDarkMode::PaintIfNecessary(this) )
|
||||
processed = true;
|
||||
else
|
||||
processed = HandlePaint();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue