From ee93f4cae82cc56b22b3d15026eaea64281665b2 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 23 Dec 2021 20:57:49 +0100 Subject: [PATCH 1/5] Initialize all bitmaps in wxODButtonImageData This is the same initialization as wxXPButtonImageData does. --- src/msw/anybutton.cpp | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index b62d516aa0..2c03b60368 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -181,12 +181,8 @@ public: wxODButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) : wxButtonImageData(btn, bitmapBundle) { - SetBitmap(GetBitmapFromBundle(bitmapBundle), - wxAnyButton::State_Normal); -#if wxUSE_IMAGE - SetBitmap(GetBitmapFromBundle(bitmapBundle).ConvertToDisabled(), - wxAnyButton::State_Disabled); -#endif + InitImageList(); + m_dir = wxLEFT; // we use margins when we have both bitmap and text, but when we have @@ -229,6 +225,27 @@ public: } private: + void InitImageList() + { + const wxBitmap bitmap = m_bitmapBundles[wxAnyButton::State_Normal].GetBitmap(m_bitmapSize); + + for ( int n = 0; n < wxAnyButton::State_Max; n++ ) + { + wxBitmap stateBitmap = m_bitmapBundles[n].GetBitmap(m_bitmapSize); + if ( !stateBitmap.IsOk() ) + { +#if wxUSE_IMAGE + if ( n == wxAnyButton::State_Disabled ) + stateBitmap = bitmap.ConvertToDisabled(); + else +#endif // wxUSE_IMAGE + stateBitmap = bitmap; + } + + SetBitmap(stateBitmap, (wxAnyButton::State)n); + } + } + // just store the values passed to us to be able to retrieve them later // from the drawing code wxBitmap m_bitmaps[wxAnyButton::State_Max]; From 971e50a45c770ff0698134367e6ecf563b3f2058 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 23 Dec 2021 21:05:17 +0100 Subject: [PATCH 2/5] Update bitmap shown by the buttons in wxMSW on DPI change This was already done for buttons using wxXPButtonImageData to store the image data, also do it for buttons that use wxODButtonImageData. When the DPI changes, recreate the bitmaps with the size corresponding to the new DPI. Move m_btn to wxButtonImageData so it can be used for both ImageData implementations. --- src/msw/anybutton.cpp | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 2c03b60368..1a84453c86 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -106,14 +106,25 @@ class wxButtonImageData: public wxObject { public: wxButtonImageData(wxWindow* btn, const wxBitmapBundle& normalBundle) + : m_btn(btn) { m_bitmapSize = normalBundle.GetPreferredSizeFor(btn); m_bitmapBundles[wxAnyButton::State_Normal] = normalBundle; + + // React to DPI changes in the future. + m_btn->Bind(wxEVT_DPI_CHANGED, &wxButtonImageData::OnDPIChanged, this); } virtual ~wxButtonImageData() { } + virtual void OnDPIChanged(wxDPIChangedEvent& event) + { + event.Skip(); + + m_bitmapSize = m_bitmapBundles[wxAnyButton::State_Normal].GetPreferredSizeFor(m_btn); + } + // Bitmap can be set either explicitly, when the bitmap for the given state // is specified by the application, or implicitly, when the bitmap for some // state is set as a side effect of setting another bitmap. @@ -165,6 +176,9 @@ protected: wxBitmapBundle m_bitmapBundles[wxAnyButton::State_Max]; + // the button we're associated with + wxWindow* const m_btn; + wxDECLARE_NO_COPY_CLASS(wxButtonImageData); }; @@ -246,6 +260,13 @@ private: } } + void OnDPIChanged(wxDPIChangedEvent& event) wxOVERRIDE + { + wxButtonImageData::OnDPIChanged(event); + + InitImageList(); + } + // just store the values passed to us to be able to retrieve them later // from the drawing code wxBitmap m_bitmaps[wxAnyButton::State_Max]; @@ -270,8 +291,7 @@ public: // we must be constructed with the size of our images as we need to create // the image list wxXPButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) - : wxButtonImageData(btn, bitmapBundle), - m_btn(btn) + : wxButtonImageData(btn, bitmapBundle) { InitImageList(); @@ -282,9 +302,6 @@ public: m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT; UpdateImageInfo(); - - // React to DPI changes in the future. - btn->Bind(wxEVT_DPI_CHANGED, &wxXPButtonImageData::OnDPIChanged, this); } virtual wxBitmap GetBitmap(wxAnyButton::State which) const wxOVERRIDE @@ -426,13 +443,9 @@ private: } } - void OnDPIChanged(wxDPIChangedEvent& event) + void OnDPIChanged(wxDPIChangedEvent& event) wxOVERRIDE { - event.Skip(); - - // We need to recreate the image list using the new size and re-add all - // bitmaps to it. - m_bitmapSize = m_bitmapBundles[wxAnyButton::State_Normal].GetPreferredSizeFor(m_btn); + wxButtonImageData::OnDPIChanged(event); m_iml.Destroy(); InitImageList(); @@ -447,10 +460,6 @@ private: // store the rest of the data in BCM_SETIMAGELIST-friendly form BUTTON_IMAGELIST m_data; - // the button we're associated with - wxWindow* const m_btn; - - wxDECLARE_NO_COPY_CLASS(wxXPButtonImageData); wxDECLARE_ABSTRACT_CLASS(wxXPButtonImageData); }; From fe50693304569db902717460e94cb9b82877801c Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 23 Dec 2021 21:13:44 +0100 Subject: [PATCH 3/5] Unbind from event handler when wxButtonImageData is destroyed ImageData of a button can be reset. When this happens, make sure to unbind the ImageData from the buttons event handler so no invalid access occurs when the DPI changes. --- src/msw/anybutton.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 1a84453c86..9e871efbae 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -116,7 +116,10 @@ public: m_btn->Bind(wxEVT_DPI_CHANGED, &wxButtonImageData::OnDPIChanged, this); } - virtual ~wxButtonImageData() { } + virtual ~wxButtonImageData() + { + m_btn->Unbind(wxEVT_DPI_CHANGED, &wxButtonImageData::OnDPIChanged, this); + } virtual void OnDPIChanged(wxDPIChangedEvent& event) { From c6b745655fa811e067170900073d051ad4a39ee1 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 23 Dec 2021 21:21:53 +0100 Subject: [PATCH 4/5] Prevent asserts when setting bitmap buttons at a different DPI Closes #19353 --- src/msw/anybutton.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 9e871efbae..57a0d2fa7b 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -846,7 +846,8 @@ void wxAnyButton::DoSetBitmap(const wxBitmapBundle& bitmapBundle, State which) // Check if we already had bitmaps of different size. if ( m_imageData && - bitmapBundle.GetDefaultSize() != m_imageData->GetBitmapSize() ) + bitmapBundle.GetDefaultSize() != + m_imageData->GetBitmapBundle(State_Normal).GetDefaultSize() ) { wxASSERT_MSG( which == State_Normal, "Must set normal bitmap with the new size first" ); From 2855f6f0ad447fb33ab3aaa7a89cafe9bcb28fd1 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Thu, 23 Dec 2021 23:40:04 +0100 Subject: [PATCH 5/5] Use correct state bitmap when creating image list Regression of 2a0719818a. --- src/msw/anybutton.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 57a0d2fa7b..fd05bd5c24 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -420,7 +420,7 @@ private: stateBitmap = bitmap; } - m_iml.Add(bitmap); + m_iml.Add(stateBitmap); } // In addition to the states supported by wxWidgets such as normal,