Merge branch 'msw-spin-appearance'
Fixes for wxSpinCtrl appearance in wxMSW. See #23696.
This commit is contained in:
commit
44b99195bc
5 changed files with 123 additions and 31 deletions
|
|
@ -48,7 +48,6 @@ public:
|
|||
virtual void SetRange(int minVal, int maxVal) override;
|
||||
|
||||
// implementation
|
||||
virtual bool MSWCommand(WXUINT param, WXWORD id) override;
|
||||
virtual bool MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) override;
|
||||
virtual bool MSWOnScroll(int orientation, WXWORD wParam,
|
||||
WXWORD pos, WXHWND control) override;
|
||||
|
|
@ -61,8 +60,6 @@ public:
|
|||
virtual void SetIncrement(int value) override;
|
||||
virtual int GetIncrement() const override;
|
||||
|
||||
virtual bool MSWShouldUseAutoDarkMode() const override;
|
||||
|
||||
protected:
|
||||
virtual wxSize DoGetBestSize() const override;
|
||||
|
||||
|
|
@ -70,6 +67,8 @@ protected:
|
|||
virtual void NormalizeValue();
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxSpinButton);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -213,13 +213,6 @@ 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);
|
||||
|
|
|
|||
|
|
@ -23,13 +23,17 @@
|
|||
#ifndef WX_PRECOMP
|
||||
#include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
|
||||
#include "wx/app.h"
|
||||
#include "wx/dcclient.h"
|
||||
#include "wx/dcmemory.h"
|
||||
#endif
|
||||
|
||||
#if wxUSE_SPINBTN
|
||||
|
||||
#include "wx/spinbutt.h"
|
||||
|
||||
#include "wx/msw/dc.h"
|
||||
#include "wx/msw/private.h"
|
||||
#include "wx/msw/private/darkmode.h"
|
||||
|
||||
#ifndef UDM_SETRANGE32
|
||||
#define UDM_SETRANGE32 (WM_USER+111)
|
||||
|
|
@ -130,6 +134,8 @@ bool wxSpinButton::Create(wxWindow *parent,
|
|||
|
||||
SubclassWin(m_hWnd);
|
||||
|
||||
Bind(wxEVT_PAINT, &wxSpinButton::OnPaint, this);
|
||||
|
||||
SetInitialSize(size);
|
||||
|
||||
return true;
|
||||
|
|
@ -139,13 +145,6 @@ 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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -166,7 +165,107 @@ wxSize wxSpinButton::DoGetBestSize() const
|
|||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Attributes
|
||||
// painting
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxSpinButton::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
if ( wxMSWDarkMode::IsActive() )
|
||||
{
|
||||
// Unfortunately PaintIfNecessary() can't be used here as we need to
|
||||
// handle the extra border below, so duplicate what it does here.
|
||||
const RECT rc = wxGetClientRect(GetHwnd());
|
||||
const wxSize size{rc.right - rc.left, rc.bottom - rc.top};
|
||||
|
||||
if ( size == wxSize() )
|
||||
return;
|
||||
|
||||
wxBitmap bmp(size);
|
||||
{
|
||||
wxMemoryDC mdc(bmp);
|
||||
|
||||
::CallWindowProc(m_oldWndProc,
|
||||
GetHwnd(), WM_PAINT, (WPARAM)GetHdcOf(mdc), 0);
|
||||
}
|
||||
|
||||
#if wxUSE_IMAGE
|
||||
// When using a buddy control, the spin button tries to mimic being a
|
||||
// part of it by adding an extra border, not used for standalone
|
||||
// controls. This doesn't work very well even in light mode in modern
|
||||
// Windows (it was apparently done for the classic 3D appearance and
|
||||
// never updated since then), but looks completely horrible in dark
|
||||
// mode, so we must get rid of this border by overdrawing it.
|
||||
const bool drawBorder = ::SendMessage(GetHwnd(), UDM_GETBUDDY, 0, 0);
|
||||
wxImage::RGBValue border;
|
||||
if ( drawBorder )
|
||||
{
|
||||
const auto col = wxMSWDarkMode::GetBorderPen().GetColour();
|
||||
border.red = col.GetRed();
|
||||
border.green = col.GetGreen();
|
||||
border.blue = col.GetBlue();
|
||||
}
|
||||
|
||||
wxImage image = bmp.ConvertToImage();
|
||||
|
||||
const int width = image.GetWidth();
|
||||
const int height = image.GetHeight();
|
||||
unsigned char *data = image.GetData();
|
||||
unsigned char *alpha = image.GetAlpha();
|
||||
for ( int y = 0; y < height; ++y )
|
||||
{
|
||||
for ( int x = 0; x < width; ++x )
|
||||
{
|
||||
wxImage::RGBValue rgb(data[0], data[1], data[2]);
|
||||
|
||||
if ( drawBorder &&
|
||||
(y == 0 || y == height - 1 || x == width - 1) )
|
||||
{
|
||||
rgb = border;
|
||||
if ( alpha )
|
||||
*alpha = wxALPHA_OPAQUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This uses a slightly different formula than the one in
|
||||
// InvertBitmapPixel() because the one there results in the
|
||||
// lines being too bright.
|
||||
auto hsv = wxImage::RGBtoHSV(rgb);
|
||||
hsv.value = 1.0 - hsv.value;
|
||||
rgb = wxImage::HSVtoRGB(hsv);
|
||||
}
|
||||
|
||||
data[0] = rgb.red;
|
||||
data[1] = rgb.green;
|
||||
data[2] = rgb.blue;
|
||||
data += 3;
|
||||
|
||||
if ( alpha )
|
||||
alpha++;
|
||||
}
|
||||
}
|
||||
|
||||
bmp = wxBitmap(image);
|
||||
#endif // wxUSE_IMAGE
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
wxDCTemp dc(::BeginPaint(GetHwnd(), &ps), size);
|
||||
dc.DrawBitmap(bmp, 0, 0);
|
||||
::EndPaint(GetHwnd(), &ps);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to always paint this control explicitly instead of letting
|
||||
// DefWndProc() do it, as this avoids whichever optimization the latter
|
||||
// function does when WS_EX_COMPOSITED is on that result in not drawing
|
||||
// parts of the control at all (see #23656).
|
||||
wxPaintDC dc(this);
|
||||
|
||||
wxSpinButtonBase::OnPaint(event);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// value and range
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int wxSpinButton::GetValue() const
|
||||
|
|
@ -231,6 +330,10 @@ void wxSpinButton::SetRange(int minVal, int maxVal)
|
|||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event generation
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
bool wxSpinButton::MSWOnScroll(int WXUNUSED(orientation), WXWORD wParam,
|
||||
WXWORD WXUNUSED(pos), WXHWND control)
|
||||
{
|
||||
|
|
@ -289,11 +392,9 @@ bool wxSpinButton::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM *
|
|||
return processed;
|
||||
}
|
||||
|
||||
bool wxSpinButton::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD WXUNUSED(id))
|
||||
{
|
||||
// No command messages
|
||||
return false;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
// increment
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void wxSpinButton::SetIncrement(int value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -281,8 +281,9 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
|||
// set style for the base class
|
||||
style |= wxSP_VERTICAL;
|
||||
|
||||
// the border is only used for the text control part
|
||||
if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
|
||||
style |= wxBORDER_SUNKEN;
|
||||
style |= DoTranslateBorder(wxBORDER_THEME);
|
||||
|
||||
SetWindowStyle(style);
|
||||
|
||||
|
|
@ -327,8 +328,10 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
|||
}
|
||||
|
||||
|
||||
// create the spin button
|
||||
if ( !wxSpinButton::Create(parent, id, pos, wxSize(0, 0), style, name) )
|
||||
// create the spin button without any border as it doesn't make sense for
|
||||
// it (even if it doesn't seem to be actually taken into account anyhow)
|
||||
if ( !wxSpinButton::Create(parent, id, pos, wxSize(0, 0),
|
||||
(style & ~wxBORDER_MASK) | wxBORDER_NONE, name) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3197,11 +3197,7 @@ wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
|
|||
}
|
||||
else // no DC given
|
||||
{
|
||||
if ( MSWShouldUseAutoDarkMode() &&
|
||||
wxMSWDarkMode::PaintIfNecessary(GetHwnd(), m_oldWndProc) )
|
||||
processed = true;
|
||||
else
|
||||
processed = HandlePaint();
|
||||
processed = HandlePaint();
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue