Factor out CustomPaint() function from dark mode code
No real changes yet, just make it possible to use the function customizing the default WM_PAINT handle from other places too.
This commit is contained in:
parent
f2f2868de5
commit
3bf953bcc3
2 changed files with 120 additions and 45 deletions
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_
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue