From 630e6b898fa4d3a20ea424aef33b31757e41dc23 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 5 Oct 2021 22:42:16 +0100 Subject: [PATCH 1/8] Add conversion ctor from wxIcon to wxBitmapBundle too Existing code may call functions taking wxBitmap with wxIcon, due to an existing conversion from wxIcon to wxBitmap, so we need to provide a similar conversion to wxBitmapBundle for compatibility. --- include/wx/bmpbndl.h | 3 +++ interface/wx/bmpbndl.h | 8 ++++++++ src/common/bmpbndl.cpp | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/include/wx/bmpbndl.h b/include/wx/bmpbndl.h index 8e4d9f68ab..f5db5ab140 100644 --- a/include/wx/bmpbndl.h +++ b/include/wx/bmpbndl.h @@ -41,6 +41,9 @@ public: // using wxBitmap. wxBitmapBundle(const wxBitmap& bitmap); + // This is similar to above and also exists only for compatibility. + wxBitmapBundle(const wxIcon& icon); + // Another conversion ctor from a single image: this one is needed to allow // passing wxImage to the functions that used to take wxBitmap but now take // wxBitmapBundle. diff --git a/interface/wx/bmpbndl.h b/interface/wx/bmpbndl.h index bd9d4cb5e3..c17273ef04 100644 --- a/interface/wx/bmpbndl.h +++ b/interface/wx/bmpbndl.h @@ -108,6 +108,14 @@ public: */ wxBitmapBundle(const wxBitmap& bitmap); + /** + Conversion constructor from a single icon. + + This constructor does the same thing as FromBitmap() and only exists + for interoperability with the existing code using wxIcon. + */ + wxBitmapBundle(const wxIcon& icon); + /** Conversion constructor from a single image. diff --git a/src/common/bmpbndl.cpp b/src/common/bmpbndl.cpp index 61ed5f731e..0628b5ecd0 100644 --- a/src/common/bmpbndl.cpp +++ b/src/common/bmpbndl.cpp @@ -22,6 +22,7 @@ #endif // WX_PRECOMP #include "wx/bmpbndl.h" +#include "wx/icon.h" #include "wx/private/bmpbndl.h" @@ -257,6 +258,11 @@ wxBitmapBundle::wxBitmapBundle(const wxBitmap& bitmap) { } +wxBitmapBundle::wxBitmapBundle(const wxIcon& icon) + : m_impl(icon.IsOk() ? new wxBitmapBundleImplSet(wxBitmap(icon)) : NULL) +{ +} + wxBitmapBundle::wxBitmapBundle(const wxImage& image) : m_impl(image.IsOk() ? new wxBitmapBundleImplSet(wxBitmap(image)) : NULL) { From 5965bc191085af05fc588ed6a7d3ee593298c07d Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 5 Oct 2021 22:50:48 +0100 Subject: [PATCH 2/8] Remove unused parts of wxMSW wxBitmapButton implementation Nothing here, including the event table for this class using non-existing wxBitmapButton::OnSysColourChanged (which is just the same as wxWindow::OnSysColourChanged, in fact), was needed any longer ever since the changes of a6fd73d33a (implement wxBitmapButton as just a wrapper for wxButton under MSW, 2009-06-15), so simply remove all the unused stuff. --- include/wx/msw/bmpbuttn.h | 1 - src/msw/bmpbuttn.cpp | 21 +-------------------- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/include/wx/msw/bmpbuttn.h b/include/wx/msw/bmpbuttn.h index a083428948..b894bc47f3 100644 --- a/include/wx/msw/bmpbuttn.h +++ b/include/wx/msw/bmpbuttn.h @@ -45,7 +45,6 @@ public: wxWindowID winid, const wxString& name = wxString()); protected: - wxDECLARE_EVENT_TABLE(); wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxBitmapButton); }; diff --git a/src/msw/bmpbuttn.cpp b/src/msw/bmpbuttn.cpp index 45eed2db05..093544d159 100644 --- a/src/msw/bmpbuttn.cpp +++ b/src/msw/bmpbuttn.cpp @@ -16,29 +16,10 @@ #include "wx/bmpbuttn.h" -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/dcmemory.h" - #include "wx/image.h" -#endif - -#include "wx/msw/private.h" -#include "wx/msw/dc.h" // for wxDCTemp - -#include "wx/msw/uxtheme.h" - -#ifndef ODS_NOFOCUSRECT - #define ODS_NOFOCUSRECT 0x0200 -#endif - // ---------------------------------------------------------------------------- -// macros +// wxBitmapButton implementation // ---------------------------------------------------------------------------- -wxBEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase) - EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged) -wxEND_EVENT_TABLE() - /* TODO PROPERTIES : From 2910327ef318f655171bb8c0b0db3a0529a9da0a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 18 Oct 2021 11:48:11 +0200 Subject: [PATCH 3/8] Don't crash in wxOSXGetImageFromBundle() if the bundle is invalid Just return a null image instead, as this function can be called when we don't have any bitmaps too -- as it happens in the Button::Bitmap unit test, for example. --- src/osx/core/bmpbndl.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/osx/core/bmpbndl.mm b/src/osx/core/bmpbndl.mm index d41db453c6..7fdb89a78a 100644 --- a/src/osx/core/bmpbndl.mm +++ b/src/osx/core/bmpbndl.mm @@ -171,6 +171,9 @@ wxBitmapBundle wxBitmapBundle::FromResources(const wxString& name) WXImage wxOSXGetImageFromBundle(const wxBitmapBundle& bundle) { + if (!bundle.IsOk()) + return NULL; + WXImage image = bundle.GetImpl()->OSXGetImage(); if (image == 0) From 4e5d2d97e2ca57b0657f1338a8bd0a2638355d7b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 10 Oct 2021 19:32:43 +0100 Subject: [PATCH 4/8] Allow using wxBitmapBundle for wxButton bitmaps Take wxBitmapBundle in wxButton::SetBitmapLabel() and related functions in order to be able to associate several bitmaps to be used in different resolutions with the button, instead of just a single bitmap. --- include/wx/anybutton.h | 17 ++-- include/wx/bmpbuttn.h | 9 ++- include/wx/gtk/anybutton.h | 6 +- include/wx/gtk/bmpbuttn.h | 4 +- include/wx/gtk1/bmpbuttn.h | 6 +- include/wx/motif/bmpbuttn.h | 10 ++- include/wx/msw/anybutton.h | 2 +- include/wx/msw/bmpbuttn.h | 4 +- include/wx/osx/anybutton.h | 4 +- include/wx/osx/bmpbuttn.h | 4 +- include/wx/osx/cocoa/private.h | 6 +- include/wx/osx/core/private.h | 10 +-- include/wx/osx/iphone/private.h | 2 +- include/wx/qt/anybutton.h | 6 +- include/wx/qt/bmpbuttn.h | 4 +- include/wx/univ/bmpbuttn.h | 4 +- include/wx/univ/button.h | 8 +- interface/wx/anybutton.h | 19 +++-- samples/widgets/button.cpp | 8 +- src/gtk/anybutton.cpp | 6 +- src/gtk/bmpbuttn.cpp | 2 +- src/gtk1/bmpbuttn.cpp | 4 +- src/motif/bmpbuttn.cpp | 41 +++++----- src/msw/anybutton.cpp | 134 +++++++++++++++++++------------- src/msw/bmpbuttn.cpp | 2 +- src/osx/anybutton_osx.cpp | 14 ++-- src/osx/bmpbuttn_osx.cpp | 2 +- src/osx/cocoa/button.mm | 15 ++-- src/osx/cocoa/tglbtn.mm | 7 +- src/osx/cocoa/window.mm | 6 +- src/osx/iphone/button.mm | 5 +- src/osx/iphone/window.mm | 2 +- src/qt/anybutton.cpp | 13 +++- src/qt/bmpbuttn.cpp | 4 +- src/univ/bmpbuttn.cpp | 2 +- src/univ/button.cpp | 6 +- 36 files changed, 223 insertions(+), 175 deletions(-) diff --git a/include/wx/anybutton.h b/include/wx/anybutton.h index 828ce7d690..5467e472ba 100644 --- a/include/wx/anybutton.h +++ b/include/wx/anybutton.h @@ -41,7 +41,7 @@ #define wxBU_NOTEXT 0x0002 -#include "wx/bitmap.h" +#include "wx/bmpbndl.h" #include "wx/control.h" // ---------------------------------------------------------------------------- @@ -55,7 +55,7 @@ public: // show the image in the button in addition to the label: this method is // supported on all (major) platforms - void SetBitmap(const wxBitmap& bitmap, wxDirection dir = wxLEFT) + void SetBitmap(const wxBitmapBundle& bitmap, wxDirection dir = wxLEFT) { SetBitmapLabel(bitmap); SetBitmapPosition(dir); @@ -71,15 +71,15 @@ public: // SetBitmapXXX() methods (except for SetBitmapLabel() which is a synonym // for it anyhow) and that all bitmaps passed to these functions should be // of the same size. - void SetBitmapLabel(const wxBitmap& bitmap) + void SetBitmapLabel(const wxBitmapBundle& bitmap) { DoSetBitmap(bitmap, State_Normal); } - void SetBitmapPressed(const wxBitmap& bitmap) + void SetBitmapPressed(const wxBitmapBundle& bitmap) { DoSetBitmap(bitmap, State_Pressed); } - void SetBitmapDisabled(const wxBitmap& bitmap) + void SetBitmapDisabled(const wxBitmapBundle& bitmap) { DoSetBitmap(bitmap, State_Disabled); } - void SetBitmapCurrent(const wxBitmap& bitmap) + void SetBitmapCurrent(const wxBitmapBundle& bitmap) { DoSetBitmap(bitmap, State_Current); } - void SetBitmapFocus(const wxBitmap& bitmap) + void SetBitmapFocus(const wxBitmapBundle& bitmap) { DoSetBitmap(bitmap, State_Focused); } wxBitmap GetBitmapLabel() const { return DoGetBitmap(State_Normal); } @@ -113,6 +113,7 @@ public: // backwards compatible names for pressed/current bitmaps: they're not // deprecated as there is nothing really wrong with using them and no real // advantage to using the new names but the new names are still preferred + // (and need to be used when using wxBitmapBundle and not just wxBitmap) wxBitmap GetBitmapSelected() const { return GetBitmapPressed(); } wxBitmap GetBitmapHover() const { return GetBitmapCurrent(); } @@ -161,7 +162,7 @@ protected: virtual wxBitmap DoGetBitmap(State WXUNUSED(which)) const { return wxBitmap(); } - virtual void DoSetBitmap(const wxBitmap& WXUNUSED(bitmap), + virtual void DoSetBitmap(const wxBitmapBundle& WXUNUSED(bitmap), State WXUNUSED(which)) { } diff --git a/include/wx/bmpbuttn.h b/include/wx/bmpbuttn.h index 8a40d9891c..676dd294ed 100644 --- a/include/wx/bmpbuttn.h +++ b/include/wx/bmpbuttn.h @@ -99,8 +99,9 @@ protected: // function called when any of the bitmaps changes virtual void OnSetBitmap() { InvalidateBestSize(); Refresh(); } - virtual wxBitmap DoGetBitmap(State which) const { return m_bitmaps[which]; } - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) + virtual wxBitmap DoGetBitmap(State which) const + { return m_bitmaps[which].GetBitmap(wxDefaultSize); } + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which) { m_bitmaps[which] = bitmap; OnSetBitmap(); } virtual wxSize DoGetBitmapMargins() const @@ -114,8 +115,8 @@ protected: m_marginY = y; } - // the bitmaps for various states - wxBitmap m_bitmaps[State_Max]; + // the bitmap bundles for various states + wxBitmapBundle m_bitmaps[State_Max]; // the margins around the bitmap int m_marginX, diff --git a/include/wx/gtk/anybutton.h b/include/wx/gtk/anybutton.h index a49759d2e0..d62e849857 100644 --- a/include/wx/gtk/anybutton.h +++ b/include/wx/gtk/anybutton.h @@ -42,7 +42,7 @@ protected: virtual void DoEnable(bool enable) wxOVERRIDE; virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which) wxOVERRIDE; virtual void DoSetBitmapPosition(wxDirection dir) wxOVERRIDE; // update the bitmap to correspond to the current button state @@ -60,13 +60,13 @@ private: State GTKGetCurrentBitmapState() const; // show the given bitmap (must be valid) - void GTKDoShowBitmap(const wxBitmap& bitmap); + void GTKDoShowBitmap(const wxBitmapBundle& bitmap); // the bitmaps for the different state of the buttons, all of them may be // invalid and the button only shows a bitmap at all if State_Normal bitmap // is valid - wxBitmap m_bitmaps[State_Max]; + wxBitmapBundle m_bitmaps[State_Max]; // true iff mouse is currently over the button bool m_isCurrent; diff --git a/include/wx/gtk/bmpbuttn.h b/include/wx/gtk/bmpbuttn.h index 46d8836a84..37d7d31758 100644 --- a/include/wx/gtk/bmpbuttn.h +++ b/include/wx/gtk/bmpbuttn.h @@ -20,7 +20,7 @@ public: wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -32,7 +32,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, diff --git a/include/wx/gtk1/bmpbuttn.h b/include/wx/gtk1/bmpbuttn.h index 9d81994eb0..9700224a45 100644 --- a/include/wx/gtk1/bmpbuttn.h +++ b/include/wx/gtk1/bmpbuttn.h @@ -21,7 +21,7 @@ public: wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -35,7 +35,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -47,7 +47,7 @@ public: const wxString& name = wxString()); void SetLabel( const wxString &label ); - virtual void SetLabel( const wxBitmap& bitmap ) { SetBitmapLabel(bitmap); } + virtual void SetLabel( const wxBitmapBundle& bitmap ) { SetBitmapLabel(bitmap); } virtual bool Enable(bool enable = TRUE); diff --git a/include/wx/motif/bmpbuttn.h b/include/wx/motif/bmpbuttn.h index 16ccf4869e..8f8bb57106 100644 --- a/include/wx/motif/bmpbuttn.h +++ b/include/wx/motif/bmpbuttn.h @@ -20,7 +20,8 @@ class WXDLLIMPEXP_CORE wxBitmapButton: public wxBitmapButtonBase public: wxBitmapButton(); virtual ~wxBitmapButton(); - wxBitmapButton(wxWindow *parent, wxWindowID id, const wxBitmap& bitmap, + wxBitmapButton(wxWindow *parent, wxWindowID id, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxValidator& validator = wxDefaultValidator, @@ -29,7 +30,8 @@ public: Create(parent, id, bitmap, pos, size, style, validator, name); } - bool Create(wxWindow *parent, wxWindowID id, const wxBitmap& bitmap, + bool Create(wxWindow *parent, wxWindowID id, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxValidator& validator = wxDefaultValidator, @@ -44,12 +46,12 @@ public: protected: virtual wxSize DoGetBestSize() const; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which); + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which); virtual void OnSetBitmap(); // original bitmaps may be different from the ones we were initialized with // if they were changed to reflect button background colour - wxBitmap m_bitmapsOriginal[State_Max]; + wxBitmapBundle m_bitmapsOriginal[State_Max]; wxBitmapCache m_bitmapCache; diff --git a/include/wx/msw/anybutton.h b/include/wx/msw/anybutton.h index 78b746718c..d6def3d6fd 100644 --- a/include/wx/msw/anybutton.h +++ b/include/wx/msw/anybutton.h @@ -45,7 +45,7 @@ protected: virtual wxSize DoGetBestSize() const wxOVERRIDE; virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which) wxOVERRIDE; virtual wxSize DoGetBitmapMargins() const wxOVERRIDE; virtual void DoSetBitmapMargins(wxCoord x, wxCoord y) wxOVERRIDE; virtual void DoSetBitmapPosition(wxDirection dir) wxOVERRIDE; diff --git a/include/wx/msw/bmpbuttn.h b/include/wx/msw/bmpbuttn.h index b894bc47f3..f4fbcd6215 100644 --- a/include/wx/msw/bmpbuttn.h +++ b/include/wx/msw/bmpbuttn.h @@ -22,7 +22,7 @@ public: wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -34,7 +34,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, diff --git a/include/wx/osx/anybutton.h b/include/wx/osx/anybutton.h index 31b579a440..e8d1ef03e4 100644 --- a/include/wx/osx/anybutton.h +++ b/include/wx/osx/anybutton.h @@ -27,7 +27,7 @@ protected: void OnLeaveWindow( wxMouseEvent& event); virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; + virtual void DoSetBitmap(const wxBitmapBundle& bitmapBundle, State which) wxOVERRIDE; virtual void DoSetBitmapPosition(wxDirection dir) wxOVERRIDE; virtual void DoSetBitmapMargins(int x, int y) wxOVERRIDE @@ -49,7 +49,7 @@ protected: // the bitmaps for the different state of the buttons, all of them may be // invalid and the button only shows a bitmap at all if State_Normal bitmap // is valid - wxBitmap m_bitmaps[State_Max]; + wxBitmapBundle m_bitmaps[State_Max]; wxDECLARE_NO_COPY_CLASS(wxAnyButton); wxDECLARE_EVENT_TABLE(); diff --git a/include/wx/osx/bmpbuttn.h b/include/wx/osx/bmpbuttn.h index 7ea895ffe3..4fca97487e 100644 --- a/include/wx/osx/bmpbuttn.h +++ b/include/wx/osx/bmpbuttn.h @@ -22,7 +22,7 @@ public: { } - wxBitmapButton(wxWindow *parent, wxWindowID id, const wxBitmap& bitmap, + wxBitmapButton(wxWindow *parent, wxWindowID id, const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxValidator& validator = wxDefaultValidator, @@ -31,7 +31,7 @@ public: Create(parent, id, bitmap, pos, size, style, validator, name); } - bool Create(wxWindow *parent, wxWindowID id, const wxBitmap& bitmap, + bool Create(wxWindow *parent, wxWindowID id, const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxValidator& validator = wxDefaultValidator, diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index c00166e1ae..48d4675acb 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -140,7 +140,7 @@ public : wxInt32 GetValue() const wxOVERRIDE; void SetValue( wxInt32 v ) wxOVERRIDE; wxBitmap GetBitmap() const wxOVERRIDE; - void SetBitmap( const wxBitmap& bitmap ) wxOVERRIDE; + void SetBitmap( const wxBitmapBundle& bitmap ) wxOVERRIDE; void SetBitmapPosition( wxDirection dir ) wxOVERRIDE; void SetupTabs( const wxNotebook ¬ebook ) wxOVERRIDE; void GetBestRect( wxRect *r ) const wxOVERRIDE; @@ -356,12 +356,12 @@ class wxButtonCocoaImpl : public wxWidgetCocoaImpl, public wxButtonImpl { public: wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v); - virtual void SetBitmap(const wxBitmap& bitmap) wxOVERRIDE; + virtual void SetBitmap(const wxBitmapBundle& bitmap) wxOVERRIDE; #if wxUSE_MARKUP virtual void SetLabelMarkup(const wxString& markup) wxOVERRIDE; #endif // wxUSE_MARKUP - void SetPressedBitmap( const wxBitmap& bitmap ) wxOVERRIDE; + void SetPressedBitmap( const wxBitmapBundle& bitmap ) wxOVERRIDE; void GetLayoutInset(int &left, int &top, int &right, int &bottom) const wxOVERRIDE; void SetAcceleratorFromLabel(const wxString& label); diff --git a/include/wx/osx/core/private.h b/include/wx/osx/core/private.h index db904c8207..6dcb3f7311 100644 --- a/include/wx/osx/core/private.h +++ b/include/wx/osx/core/private.h @@ -74,7 +74,7 @@ WXDLLIMPEXP_BASE CFURLRef wxOSXCreateURLFromFileSystemPath( const wxString& path #include #endif -#include "wx/bitmap.h" +#include "wx/bmpbndl.h" #include "wx/window.h" class wxTextProofOptions; @@ -337,7 +337,7 @@ public : virtual wxInt32 GetValue() const = 0; virtual void SetValue( wxInt32 v ) = 0; virtual wxBitmap GetBitmap() const = 0; - virtual void SetBitmap( const wxBitmap& bitmap ) = 0; + virtual void SetBitmap( const wxBitmapBundle& bitmap ) = 0; virtual void SetBitmapPosition( wxDirection dir ) = 0; virtual void SetupTabs( const wxNotebook& WXUNUSED(notebook) ) {} virtual int TabHitTest( const wxPoint & WXUNUSED(pt), long *flags ) {*flags=1; return -1;} @@ -491,7 +491,7 @@ public : static wxWidgetImplType* CreateBitmapToggleButton( wxWindowMac* wxpeer, wxWindowMac* parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -500,7 +500,7 @@ public : static wxWidgetImplType* CreateBitmapButton( wxWindowMac* wxpeer, wxWindowMac* parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -828,7 +828,7 @@ class wxButtonImpl wxButtonImpl(){} virtual ~wxButtonImpl(){} - virtual void SetPressedBitmap( const wxBitmap& bitmap ) = 0; + virtual void SetPressedBitmap( const wxBitmapBundle& bitmap ) = 0; } ; // diff --git a/include/wx/osx/iphone/private.h b/include/wx/osx/iphone/private.h index 1acf0dd175..e4225e8086 100644 --- a/include/wx/osx/iphone/private.h +++ b/include/wx/osx/iphone/private.h @@ -90,7 +90,7 @@ public : void SetValue( wxInt32 v ); virtual wxBitmap GetBitmap() const; - virtual void SetBitmap( const wxBitmap& bitmap ); + virtual void SetBitmap( const wxBitmapBundle& bitmap ); virtual void SetBitmapPosition( wxDirection dir ); void SetupTabs( const wxNotebook ¬ebook ); diff --git a/include/wx/qt/anybutton.h b/include/wx/qt/anybutton.h index 23f409c8bd..b5d0ac6e87 100644 --- a/include/wx/qt/anybutton.h +++ b/include/wx/qt/anybutton.h @@ -33,18 +33,18 @@ public: protected: virtual wxBitmap DoGetBitmap(State state) const wxOVERRIDE; - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which) wxOVERRIDE; QPushButton *m_qtPushButton; void QtCreate(wxWindow *parent); - void QtSetBitmap( const wxBitmap &bitmap ); + void QtSetBitmap( const wxBitmapBundle &bitmap ); private: State QtGetCurrentState() const; typedef wxAnyButtonBase base_type; - wxBitmap m_bitmaps[State_Max]; + wxBitmapBundle m_bitmaps[State_Max]; wxDECLARE_NO_COPY_CLASS(wxAnyButton); }; diff --git a/include/wx/qt/bmpbuttn.h b/include/wx/qt/bmpbuttn.h index 15baae446a..5cb5244012 100644 --- a/include/wx/qt/bmpbuttn.h +++ b/include/wx/qt/bmpbuttn.h @@ -15,7 +15,7 @@ public: wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -24,7 +24,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, diff --git a/include/wx/univ/bmpbuttn.h b/include/wx/univ/bmpbuttn.h index 685302d432..052a6d4680 100644 --- a/include/wx/univ/bmpbuttn.h +++ b/include/wx/univ/bmpbuttn.h @@ -18,7 +18,7 @@ public: wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, @@ -30,7 +30,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, diff --git a/include/wx/univ/button.h b/include/wx/univ/button.h index 14684580da..89b40da933 100644 --- a/include/wx/univ/button.h +++ b/include/wx/univ/button.h @@ -11,8 +11,6 @@ #ifndef _WX_UNIV_BUTTON_H_ #define _WX_UNIV_BUTTON_H_ -#include "wx/bitmap.h" - // ---------------------------------------------------------------------------- // the actions supported by this control // ---------------------------------------------------------------------------- @@ -32,7 +30,7 @@ public: wxButton() { Init(); } wxButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxString& label = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -74,7 +72,7 @@ public: bool Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxString& label = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, @@ -97,7 +95,7 @@ public: protected: - virtual void DoSetBitmap(const wxBitmap& bitmap, State which) wxOVERRIDE; + virtual void DoSetBitmap(const wxBitmapBundle& bitmap, State which) wxOVERRIDE; virtual wxBitmap DoGetBitmap(State which) const wxOVERRIDE; virtual void DoSetBitmapMargins(wxCoord x, wxCoord y) wxOVERRIDE; diff --git a/interface/wx/anybutton.h b/interface/wx/anybutton.h index 29c0eb12ce..b2f19d4eff 100644 --- a/interface/wx/anybutton.h +++ b/interface/wx/anybutton.h @@ -105,8 +105,11 @@ public: states. @param bitmap - The bitmap to display in the button. If the bitmap is invalid, any - currently shown bitmaps are removed from the button. + The bitmap bundle containing the resolution-dependent bitmaps to + display in the button. At default DPI, the size of the bitmap is + determined by the default bundle size, i.e. the value returned from + wxBitmapBundle::GetDefaultSize(). If the bitmap bundle is invalid, + any currently shown bitmaps are removed from the button. @param dir The position of the bitmap inside the button. By default it is positioned to the left of the text, near to the left button border. @@ -116,7 +119,7 @@ public: @since 2.9.1 */ - void SetBitmap(const wxBitmap& bitmap, wxDirection dir = wxLEFT); + void SetBitmap(const wxBitmapBundle& bitmap, wxDirection dir = wxLEFT); /** Sets the bitmap to be shown when the mouse is over the button. @@ -129,7 +132,7 @@ public: @since 2.9.1 (available as wxBitmapButton::SetBitmapHover() in previous versions) */ - void SetBitmapCurrent(const wxBitmap& bitmap); + void SetBitmapCurrent(const wxBitmapBundle& bitmap); /** Sets the bitmap for the disabled button appearance. @@ -145,7 +148,7 @@ public: @since 2.9.1 (available in wxBitmapButton only in previous versions) */ - void SetBitmapDisabled(const wxBitmap& bitmap); + void SetBitmapDisabled(const wxBitmapBundle& bitmap); /** Sets the bitmap for the button appearance when it has the keyboard @@ -159,7 +162,7 @@ public: @since 2.9.1 (available in wxBitmapButton only in previous versions) */ - void SetBitmapFocus(const wxBitmap& bitmap); + void SetBitmapFocus(const wxBitmapBundle& bitmap); /** Sets the bitmap label for the button. @@ -171,7 +174,7 @@ public: @since 2.9.1 (available in wxBitmapButton only in previous versions) */ - void SetBitmapLabel(const wxBitmap& bitmap); + void SetBitmapLabel(const wxBitmapBundle& bitmap); /** Sets the bitmap for the selected (depressed) button appearance. @@ -179,7 +182,7 @@ public: @since 2.9.1 (available as wxBitmapButton::SetBitmapSelected() in previous versions) */ - void SetBitmapPressed(const wxBitmap& bitmap); + void SetBitmapPressed(const wxBitmapBundle& bitmap); /** diff --git a/samples/widgets/button.cpp b/samples/widgets/button.cpp index 7f4bbf5ba9..a1e6036237 100644 --- a/samples/widgets/button.cpp +++ b/samples/widgets/button.cpp @@ -111,8 +111,8 @@ protected: // (re)create the wxButton void CreateButton(); - // helper function: create a bitmap for wxBitmapButton - wxBitmap CreateBitmap(const wxString& label, const wxArtID& type); + // helper function: create a bitmap bundle for wxBitmapButton + wxBitmapBundle CreateBitmap(const wxString& label, const wxArtID& type); // the controls @@ -691,7 +691,8 @@ void ButtonWidgetsPage::OnButton(wxCommandEvent& WXUNUSED(event)) // bitmap button stuff // ---------------------------------------------------------------------------- -wxBitmap ButtonWidgetsPage::CreateBitmap(const wxString& label, const wxArtID& type) +wxBitmapBundle +ButtonWidgetsPage::CreateBitmap(const wxString& label, const wxArtID& type) { wxBitmap bmp(FromDIP(wxSize(180, 70))); // shouldn't hardcode but it's simpler like this wxMemoryDC dc; @@ -708,4 +709,3 @@ wxBitmap ButtonWidgetsPage::CreateBitmap(const wxString& label, const wxArtID& t return bmp; } - diff --git a/src/gtk/anybutton.cpp b/src/gtk/anybutton.cpp index cbf60116c7..69943f0311 100644 --- a/src/gtk/anybutton.cpp +++ b/src/gtk/anybutton.cpp @@ -182,7 +182,7 @@ void wxAnyButton::GTKUpdateBitmap() } } -void wxAnyButton::GTKDoShowBitmap(const wxBitmap& bitmap) +void wxAnyButton::GTKDoShowBitmap(const wxBitmapBundle& bitmap) { wxCHECK_RET(bitmap.IsOk(), "invalid bitmap"); @@ -197,10 +197,10 @@ void wxAnyButton::GTKDoShowBitmap(const wxBitmap& bitmap) wxBitmap wxAnyButton::DoGetBitmap(State which) const { - return m_bitmaps[which]; + return m_bitmaps[which].GetBitmap(wxDefaultSize); } -void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxAnyButton::DoSetBitmap(const wxBitmapBundle& bitmap, State which) { switch ( which ) { diff --git a/src/gtk/bmpbuttn.cpp b/src/gtk/bmpbuttn.cpp index cf429bd2fe..37af76b837 100644 --- a/src/gtk/bmpbuttn.cpp +++ b/src/gtk/bmpbuttn.cpp @@ -15,7 +15,7 @@ bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, diff --git a/src/gtk1/bmpbuttn.cpp b/src/gtk1/bmpbuttn.cpp index 88ba005345..696c4a3e9d 100644 --- a/src/gtk1/bmpbuttn.cpp +++ b/src/gtk1/bmpbuttn.cpp @@ -121,7 +121,7 @@ void wxBitmapButton::Init() bool wxBitmapButton::Create( wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -138,7 +138,7 @@ bool wxBitmapButton::Create( wxWindow *parent, return false; } - m_bitmaps[State_Normal] = bitmap; + m_bitmaps[State_Normal] = bitmap.GetBitmap(wxDefaultSize); m_widget = gtk_button_new(); diff --git a/src/motif/bmpbuttn.cpp b/src/motif/bmpbuttn.cpp index d4403a2e16..fa6465c965 100644 --- a/src/motif/bmpbuttn.cpp +++ b/src/motif/bmpbuttn.cpp @@ -36,7 +36,7 @@ wxBitmapButton::wxBitmapButton() } bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, @@ -103,7 +103,7 @@ wxBitmapButton::~wxBitmapButton() (Pixmap) m_insensPixmap); } -void wxBitmapButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxBitmapButton::DoSetBitmap(const wxBitmapBundle& bitmap, State which) { m_bitmapsOriginal[which] = bitmap; @@ -114,7 +114,9 @@ void wxBitmapButton::OnSetBitmap() { wxBitmapButtonBase::OnSetBitmap(); - if ( m_bitmapsOriginal[State_Normal].IsOk() ) + wxBitmap + normalBitmap = m_bitmapsOriginal[State_Normal].GetBitmap(wxDefaultSize); + if ( normalBitmap.IsOk() ) { Pixmap pixmap = 0; Pixmap insensPixmap = 0; @@ -122,7 +124,7 @@ void wxBitmapButton::OnSetBitmap() // Must re-make the bitmap to have its transparent areas drawn // in the current widget background colour. - if ( m_bitmapsOriginal[State_Normal].GetMask() ) + if ( normalBitmap.GetMask() ) { WXPixel backgroundPixel; XtVaGetValues((Widget) m_mainWidget, @@ -132,22 +134,23 @@ void wxBitmapButton::OnSetBitmap() wxColour col; col.SetPixel(backgroundPixel); - wxBitmap newBitmap = - wxCreateMaskedBitmap(m_bitmapsOriginal[State_Normal], col); + wxBitmap newBitmap = wxCreateMaskedBitmap(normalBitmap, col); m_bitmaps[State_Normal] = newBitmap; - m_bitmapCache.SetBitmap( m_bitmaps[State_Normal] ); + m_bitmapCache.SetBitmap( newBitmap ); - pixmap = (Pixmap) m_bitmaps[State_Normal].GetDrawable(); + pixmap = (Pixmap) newBitmap.GetDrawable(); } else { - m_bitmapCache.SetBitmap( m_bitmaps[State_Normal] ); + m_bitmapCache.SetBitmap( normalBitmap ); pixmap = (Pixmap) m_bitmapCache.GetLabelPixmap(m_mainWidget); } - if (m_bitmapsOriginal[State_Disabled].IsOk()) + wxBitmap + disabledBitmap = m_bitmapsOriginal[State_Disabled].GetBitmap(wxDefaultSize); + if (disabledBitmap.IsOk()) { - if (m_bitmapsOriginal[State_Disabled].GetMask()) + if (disabledBitmap.GetMask()) { WXPixel backgroundPixel; XtVaGetValues((Widget) m_mainWidget, @@ -157,11 +160,10 @@ void wxBitmapButton::OnSetBitmap() wxColour col; col.SetPixel(backgroundPixel); - wxBitmap newBitmap = - wxCreateMaskedBitmap(m_bitmapsOriginal[State_Disabled], col); + wxBitmap newBitmap = wxCreateMaskedBitmap(disabledBitmap, col); m_bitmaps[State_Disabled] = newBitmap; - insensPixmap = (Pixmap) m_bitmaps[State_Disabled].GetDrawable(); + insensPixmap = (Pixmap) newBitmap.GetDrawable(); } else insensPixmap = (Pixmap) m_bitmapCache.GetInsensPixmap(m_mainWidget); @@ -170,9 +172,11 @@ void wxBitmapButton::OnSetBitmap() insensPixmap = (Pixmap) m_bitmapCache.GetInsensPixmap(m_mainWidget); // Now make the bitmap representing the armed state - if (m_bitmapsOriginal[State_Pressed].IsOk()) + wxBitmap + pressedBitmap = m_bitmapsOriginal[State_Pressed].GetBitmap(wxDefaultSize); + if (pressedBitmap.IsOk()) { - if (m_bitmapsOriginal[State_Pressed].GetMask()) + if (pressedBitmap.GetMask()) { WXPixel backgroundPixel; XtVaGetValues((Widget) m_mainWidget, @@ -182,11 +186,10 @@ void wxBitmapButton::OnSetBitmap() wxColour col; col.SetPixel(backgroundPixel); - wxBitmap newBitmap = - wxCreateMaskedBitmap(m_bitmapsOriginal[State_Pressed], col); + wxBitmap newBitmap = wxCreateMaskedBitmap(pressedBitmap, col); m_bitmaps[State_Pressed] = newBitmap; - armPixmap = (Pixmap) m_bitmaps[State_Pressed].GetDrawable(); + armPixmap = (Pixmap) newBitmap.GetDrawable(); } else armPixmap = (Pixmap) m_bitmapCache.GetArmPixmap(m_mainWidget); diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 21c9bd0823..2e8c268437 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -97,18 +97,17 @@ extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp // ---------------------------------------------------------------------------- // we use different data classes for owner drawn buttons and for themed XP ones +// +// Each class stores the bitmap bundles possibly containing images of multiple +// sizes, but only stores bitmaps of the specific size used by the button right +// now. class wxButtonImageData: public wxObject { public: - wxButtonImageData() + explicit wxButtonImageData(const wxSize& bitmapSize) + : m_bitmapSize(bitmapSize) { - for ( int n = 0; n < wxAnyButton::State_Max; ++n ) - { - // The normal bitmap is always set explicitly when the image data - // is created, but the others ones are not (yet). - m_bitmapSetExplicitly[n] = n == wxAnyButton::State_Normal; - } } virtual ~wxButtonImageData() { } @@ -117,30 +116,42 @@ public: // is specified by the application, or implicitly, when the bitmap for some // state is set as a side effect of setting another bitmap. // - // These functions check the flags stored in the base class remembering - // whether each bitmap is implicit or explicit and behave accordingly. - wxBitmap GetExplicitBitmap(wxAnyButton::State which) const + // When setting a bitmap explicitly, we update the entire bundle, while + // setting it implicitly only updates the currently used bitmap. + wxBitmapBundle GetBitmapBundle(wxAnyButton::State which) const { - return m_bitmapSetExplicitly[which] ? GetBitmap(which) : wxBitmap(); + return m_bitmapBundles[which]; } - void SetExplicitBitmap(const wxBitmap& bitmap, wxAnyButton::State which) + void SetBitmapBundle(const wxBitmapBundle& bitmapBundle, wxAnyButton::State which) { - SetBitmap(bitmap, which); - m_bitmapSetExplicitly[which] = true; + m_bitmapBundles[which] = bitmapBundle; + + SetBitmapFromBundle(bitmapBundle, which); } - wxBitmap GetImplicitBitmap(wxAnyButton::State which) const + // Actually get or update the bitmap being currently used (even if it is + // used implicitly, i.e. as consequence of setting a bitmap for another + // state). + virtual wxBitmap GetBitmap(wxAnyButton::State which) const = 0; + virtual void SetBitmap(const wxBitmap& bitmap, wxAnyButton::State which) = 0; + + // Helper: get the bitmap of the currently used size from the bundle. + wxBitmap GetBitmapFromBundle(const wxBitmapBundle& bitmapBundle) const { - return GetBitmap(which); + return bitmapBundle.GetBitmap(GetBitmapSize()); } - void SetImplicitBitmap(const wxBitmap& bitmap, wxAnyButton::State which) + // And another helper to call SetBitmap() with the result. + void SetBitmapFromBundle(const wxBitmapBundle& bitmapBundle, wxAnyButton::State which) { - SetBitmap(bitmap, which); - m_bitmapSetExplicitly[which] = false; + SetBitmap(GetBitmapFromBundle(bitmapBundle), which); } + + // Return the currently used bitmap size. + wxSize GetBitmapSize() const { return m_bitmapSize; } + virtual wxSize GetBitmapMargins() const = 0; virtual void SetBitmapMargins(wxCoord x, wxCoord y) = 0; @@ -148,12 +159,9 @@ public: virtual void SetBitmapPosition(wxDirection dir) = 0; private: - // These functions are private to force using explicit/implicit versions of - // them in the code to make it clear which bitmap is needed. - virtual wxBitmap GetBitmap(wxAnyButton::State which) const = 0; - virtual void SetBitmap(const wxBitmap& bitmap, wxAnyButton::State which) = 0; + wxSize m_bitmapSize; - bool m_bitmapSetExplicitly[wxAnyButton::State_Max]; + wxBitmapBundle m_bitmapBundles[wxAnyButton::State_Max]; wxDECLARE_NO_COPY_CLASS(wxButtonImageData); }; @@ -168,11 +176,13 @@ const int OD_BUTTON_MARGIN = 4; class wxODButtonImageData : public wxButtonImageData { public: - wxODButtonImageData(wxAnyButton *btn, const wxBitmap& bitmap) + wxODButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) + : wxButtonImageData(bitmapBundle.GetDefaultSize()) { - SetExplicitBitmap(bitmap, wxAnyButton::State_Normal); + SetBitmapBundle(bitmapBundle, wxAnyButton::State_Normal); #if wxUSE_IMAGE - SetBitmap(bitmap.ConvertToDisabled(), wxAnyButton::State_Disabled); + SetBitmap(GetBitmapFromBundle(bitmapBundle).ConvertToDisabled(), + wxAnyButton::State_Disabled); #endif m_dir = wxLEFT; @@ -239,13 +249,20 @@ class wxXPButtonImageData : public wxButtonImageData public: // we must be constructed with the size of our images as we need to create // the image list - wxXPButtonImageData(wxAnyButton *btn, const wxBitmap& bitmap) - : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), - !bitmap.HasAlpha() /* use mask only if no alpha */, - wxAnyButton::State_Max + 1 /* see "pulse" comment below */), + wxXPButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) + : wxButtonImageData(bitmapBundle.GetDefaultSize()), m_hwndBtn(GetHwndOf(btn)) { // initialize all bitmaps except for the disabled one to normal state + const wxBitmap bitmap = bitmapBundle.GetBitmap(wxDefaultSize); + m_iml.Create + ( + bitmap.GetWidth(), + bitmap.GetHeight(), + !bitmap.HasAlpha() /* use mask only if no alpha */, + wxAnyButton::State_Max + 1 /* see "pulse" comment below */ + ); + for ( int n = 0; n < wxAnyButton::State_Max; n++ ) { #if wxUSE_IMAGE @@ -266,8 +283,8 @@ public: // just disappears during half of the time if the latter is not set so // we absolutely must set it. // - // This also explains why we need to allocate an extra slot in the - // image list ctor above, the slot State_Max is used for this one. + // This also explains why we need to allocate an extra slot when creating + // the image list above, the slot State_Max is used for this one. m_iml.Add(bitmap); m_data.himl = GetHimagelistOf(&m_iml); @@ -546,7 +563,7 @@ void wxAnyButton::AdjustForBitmapSize(wxSize &size) const wxCHECK_RET( m_imageData, wxT("shouldn't be called if no image") ); // account for the bitmap size, including the user-specified margins - const wxSize sizeBmp = m_imageData->GetImplicitBitmap(State_Normal).GetSize() + const wxSize sizeBmp = m_imageData->GetBitmapSize() + 2*m_imageData->GetBitmapMargins(); const wxDirection dirBmp = m_imageData->GetBitmapPosition(); if ( dirBmp == wxLEFT || dirBmp == wxRIGHT ) @@ -701,7 +718,7 @@ WXLRESULT wxAnyButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPar if ( IsEnabled() && ( wxUxThemeIsActive() || - (m_imageData && m_imageData->GetImplicitBitmap(State_Current).IsOk()) + (m_imageData && m_imageData->GetBitmap(State_Current).IsOk()) ) ) { @@ -719,12 +736,22 @@ WXLRESULT wxAnyButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPar wxBitmap wxAnyButton::DoGetBitmap(State which) const { - return m_imageData ? m_imageData->GetExplicitBitmap(which) : wxBitmap(); + if ( !m_imageData ) + return wxBitmap(); + + const wxBitmapBundle& bitmapBundle = m_imageData->GetBitmapBundle(which); + if ( !bitmapBundle.IsOk() ) + return wxBitmap(); + + // Not really sure if it's better to use the default or current size here, + // but then this accessor is not that useful anyhow, so it probably doesn't + // matter much. + return bitmapBundle.GetBitmap(m_imageData->GetBitmapSize()); } -void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxAnyButton::DoSetBitmap(const wxBitmapBundle& bitmapBundle, State which) { - if ( !bitmap.IsOk() ) + if ( !bitmapBundle.IsOk() ) { if ( m_imageData ) { @@ -737,9 +764,12 @@ void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) } else { + // Invalidate the current bundle, if any. + m_imageData->SetBitmapBundle(bitmapBundle, which); + // Replace the removed bitmap with the normal one. - wxBitmap bmpNormal = m_imageData->GetImplicitBitmap(State_Normal); - m_imageData->SetImplicitBitmap(which == State_Disabled + wxBitmap bmpNormal = m_imageData->GetBitmap(State_Normal); + m_imageData->SetBitmap(which == State_Disabled ? bmpNormal.ConvertToDisabled() : bmpNormal, which); @@ -755,7 +785,7 @@ void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) // Check if we already had bitmaps of different size. if ( m_imageData && - bitmap.GetSize() != m_imageData->GetImplicitBitmap(State_Normal).GetSize() ) + bitmapBundle.GetDefaultSize() != m_imageData->GetBitmapSize() ) { wxASSERT_MSG( which == State_Normal, "Must set normal bitmap with the new size first" ); @@ -783,7 +813,7 @@ void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) // strategy for bitmap-only buttons if ( ShowsLabel() && wxUxThemeIsActive() ) { - m_imageData = new wxXPButtonImageData(this, bitmap); + m_imageData = new wxXPButtonImageData(this, bitmapBundle); if ( oldData ) { @@ -802,13 +832,13 @@ void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) else #endif // wxUSE_UXTHEME { - m_imageData = new wxODButtonImageData(this, bitmap); + m_imageData = new wxODButtonImageData(this, bitmapBundle); MakeOwnerDrawn(); } } else { - m_imageData->SetExplicitBitmap(bitmap, which); + m_imageData->SetBitmapBundle(bitmapBundle, which); // if the focus bitmap is specified but current one isn't, use // the focus bitmap for hovering as well if this is consistent @@ -818,9 +848,9 @@ void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) // and also makes it much easier to do "the right thing" for // all platforms (some of them, such as Windows, have "hot" // buttons while others don't) - if ( which == State_Focused && !m_imageData->GetExplicitBitmap(State_Current).IsOk() ) + if ( which == State_Focused && !m_imageData->GetBitmapBundle(State_Current).IsOk() ) { - m_imageData->SetImplicitBitmap(bitmap, State_Current); + m_imageData->SetBitmapFromBundle(bitmapBundle, State_Current); } } @@ -1267,16 +1297,16 @@ void wxAnyButton::MakeOwnerDrawn() // if necessary. if ( m_imageData && wxDynamicCast(m_imageData, wxODButtonImageData) == NULL ) { - wxODButtonImageData* newData = new wxODButtonImageData(this, m_imageData->GetImplicitBitmap(State_Normal)); + wxODButtonImageData* newData = new wxODButtonImageData(this, m_imageData->GetBitmapBundle(State_Normal)); for ( int n = 0; n < State_Max; n++ ) { State st = static_cast(n); - wxBitmap bmp = m_imageData->GetExplicitBitmap(st); + wxBitmapBundle bmp = m_imageData->GetBitmapBundle(st); if ( bmp.IsOk() ) - newData->SetExplicitBitmap(bmp, st); + newData->SetBitmapBundle(bmp, st); else - newData->SetImplicitBitmap(m_imageData->GetImplicitBitmap(st), st); + newData->SetBitmap(m_imageData->GetBitmap(st), st); } newData->SetBitmapPosition(m_imageData->GetBitmapPosition()); wxSize margs = m_imageData->GetBitmapMargins(); @@ -1436,9 +1466,9 @@ bool wxAnyButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis) // draw the image, if any if ( m_imageData ) { - wxBitmap bmp = m_imageData->GetImplicitBitmap(GetButtonState(this, state)); + wxBitmap bmp = m_imageData->GetBitmap(GetButtonState(this, state)); if ( !bmp.IsOk() ) - bmp = m_imageData->GetImplicitBitmap(State_Normal); + bmp = m_imageData->GetBitmap(State_Normal); const wxSize sizeBmp = bmp.GetSize(); const wxSize margin = m_imageData->GetBitmapMargins(); diff --git a/src/msw/bmpbuttn.cpp b/src/msw/bmpbuttn.cpp index 093544d159..3750ee0d28 100644 --- a/src/msw/bmpbuttn.cpp +++ b/src/msw/bmpbuttn.cpp @@ -32,7 +32,7 @@ bitmap "disabled" , bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, diff --git a/src/osx/anybutton_osx.cpp b/src/osx/anybutton_osx.cpp index 8fc481a544..79eb9d0d60 100644 --- a/src/osx/anybutton_osx.cpp +++ b/src/osx/anybutton_osx.cpp @@ -43,20 +43,20 @@ void wxAnyButton::SetLabel(const wxString& label) wxBitmap wxAnyButton::DoGetBitmap(State which) const { - return m_bitmaps[which]; + return m_bitmaps[which].GetBitmap(wxDefaultSize); } -void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxAnyButton::DoSetBitmap(const wxBitmapBundle& bitmapBundle, State which) { - m_bitmaps[which] = bitmap; + m_bitmaps[which] = bitmapBundle; if ( which == State_Normal ) - GetPeer()->SetBitmap(bitmap); + GetPeer()->SetBitmap(bitmapBundle); else if ( which == State_Pressed ) { wxButtonImpl* bi = dynamic_cast (GetPeer()); if ( bi ) - bi->SetPressedBitmap(bitmap); + bi->SetPressedBitmap(bitmapBundle); } InvalidateBestSize(); } @@ -84,11 +84,11 @@ bool wxAnyButton::DoSetLabelMarkup(const wxString& markup) void wxAnyButton::OnEnterWindow( wxMouseEvent& WXUNUSED(event)) { if ( DoGetBitmap( State_Current ).IsOk() ) - GetPeer()->SetBitmap( DoGetBitmap( State_Current ) ); + GetPeer()->SetBitmap( m_bitmaps[State_Current] ); } void wxAnyButton::OnLeaveWindow( wxMouseEvent& WXUNUSED(event)) { if ( DoGetBitmap( State_Current ).IsOk() ) - GetPeer()->SetBitmap( DoGetBitmap( State_Normal ) ); + GetPeer()->SetBitmap( m_bitmaps[State_Normal] ); } diff --git a/src/osx/bmpbuttn_osx.cpp b/src/osx/bmpbuttn_osx.cpp index ada2af4f89..fe99a7fbc9 100644 --- a/src/osx/bmpbuttn_osx.cpp +++ b/src/osx/bmpbuttn_osx.cpp @@ -25,7 +25,7 @@ bool wxBitmapButton::Create( wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, diff --git a/src/osx/cocoa/button.mm b/src/osx/cocoa/button.mm index 5976163c8b..f0e9030307 100644 --- a/src/osx/cocoa/button.mm +++ b/src/osx/cocoa/button.mm @@ -19,6 +19,7 @@ #include "wx/tglbtn.h" #include "wx/osx/private.h" +#include "wx/private/bmpbndl.h" #if wxUSE_MARKUP #include "wx/osx/cocoa/private/markuptoattr.h" @@ -88,7 +89,7 @@ wxButtonCocoaImpl::wxButtonCocoaImpl(wxWindowMac *wxpeer, wxNSButton *v) SetNeedsFrame(false); } -void wxButtonCocoaImpl::SetBitmap(const wxBitmap& bitmap) +void wxButtonCocoaImpl::SetBitmap(const wxBitmapBundle& bitmap) { // switch bezel style for plain pushbuttons if ( bitmap.IsOk() ) @@ -123,10 +124,10 @@ void wxButtonCocoaImpl::SetLabelMarkup(const wxString& markup) } #endif // wxUSE_MARKUP -void wxButtonCocoaImpl::SetPressedBitmap( const wxBitmap& bitmap ) +void wxButtonCocoaImpl::SetPressedBitmap( const wxBitmapBundle& bitmap ) { NSButton* button = GetNSButton(); - [button setAlternateImage: bitmap.GetNSImage()]; + [button setAlternateImage: wxOSXGetImageFromBundle(bitmap)]; #if wxUSE_TOGGLEBTN if ( GetWXPeer()->IsKindOf(wxCLASSINFO(wxToggleButton)) ) { @@ -227,7 +228,7 @@ SetBezelStyleFromBorderFlags(NSButton *v, long style, wxWindowID winid, const wxString& label = wxString(), - const wxBitmap& bitmap = wxBitmap()) + const wxBitmapBundle& bitmap = wxBitmapBundle()) { // We can't display a custom label inside a button with help bezel style so // we only use it if we are using the default label. wxButton itself checks @@ -245,7 +246,7 @@ SetBezelStyleFromBorderFlags(NSButton *v, // single or multi line. const bool isSimpleText = (label.find_first_of("\n\r") == wxString::npos) - && (!bitmap.IsOk() || bitmap.GetHeight() < 20); + && (!bitmap.IsOk() || bitmap.GetDefaultSize().y < 20); NSBezelStyle bezel; switch ( style & wxBORDER_MASK ) @@ -353,7 +354,7 @@ void wxWidgetCocoaImpl::PerformClick() wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), wxWindowID winid, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -365,7 +366,7 @@ wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, SetBezelStyleFromBorderFlags(v, style, winid, wxString(), bitmap); if (bitmap.IsOk()) - [v setImage:bitmap.GetNSImage() ]; + [v setImage: wxOSXGetImageFromBundle(bitmap) ]; [v setButtonType:NSMomentaryPushInButton]; wxWidgetCocoaImpl* c = new wxButtonCocoaImpl( wxpeer, v ); diff --git a/src/osx/cocoa/tglbtn.mm b/src/osx/cocoa/tglbtn.mm index 3dd6dedd87..a8dd889d0b 100644 --- a/src/osx/cocoa/tglbtn.mm +++ b/src/osx/cocoa/tglbtn.mm @@ -23,6 +23,7 @@ #include "wx/tglbtn.h" #include "wx/osx/private.h" +#include "wx/private/bmpbndl.h" // from button.mm @@ -30,7 +31,7 @@ extern "C" void SetBezelStyleFromBorderFlags(NSButton *v, long style, wxWindowID winid = wxID_ANY, const wxString& label = wxString(), - const wxBitmap& bitmap = wxBitmap()); + const wxBitmapBundle& bitmap = wxBitmapBundle()); wxWidgetImplType* wxWidgetImpl::CreateToggleButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), @@ -54,7 +55,7 @@ wxWidgetImplType* wxWidgetImpl::CreateToggleButton( wxWindowMac* wxpeer, wxWidgetImplType* wxWidgetImpl::CreateBitmapToggleButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), wxWindowID winid, - const wxBitmap& label, + const wxBitmapBundle& label, const wxPoint& pos, const wxSize& size, long style, @@ -66,7 +67,7 @@ wxWidgetImplType* wxWidgetImpl::CreateBitmapToggleButton( wxWindowMac* wxpeer, SetBezelStyleFromBorderFlags(v, style, winid, wxString(), label); if (label.IsOk()) - [v setImage:label.GetNSImage() ]; + [v setImage: wxOSXGetImageFromBundle(label) ]; [v setButtonType:NSOnOffButton]; wxWidgetCocoaImpl* c = new wxButtonCocoaImpl( wxpeer, v ); diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index 8858d3aaee..7f34361392 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -25,6 +25,8 @@ #include "wx/osx/private/datatransfer.h" #endif +#include "wx/private/bmpbndl.h" + #include "wx/evtloop.h" #if wxUSE_CARET @@ -3440,11 +3442,11 @@ wxBitmap wxWidgetCocoaImpl::GetBitmap() const return bmp; } -void wxWidgetCocoaImpl::SetBitmap( const wxBitmap& bitmap ) +void wxWidgetCocoaImpl::SetBitmap( const wxBitmapBundle& bitmap ) { if ( [m_osxView respondsToSelector:@selector(setImage:)] ) { - [m_osxView setImage:bitmap.GetNSImage()]; + [m_osxView setImage: wxOSXGetImageFromBundle(bitmap)]; [m_osxView setNeedsDisplay:YES]; } } diff --git a/src/osx/iphone/button.mm b/src/osx/iphone/button.mm index 4fe7f56de3..07ec3f50d0 100644 --- a/src/osx/iphone/button.mm +++ b/src/osx/iphone/button.mm @@ -21,6 +21,7 @@ #include "wx/stockitem.h" #include "wx/osx/private.h" +#include "wx/private/bmpbndl.h" @implementation wxUIButton @@ -98,7 +99,7 @@ wxWidgetImplType* wxWidgetImpl::CreateDisclosureTriangle( wxWindowMac* wxpeer, wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, wxWindowMac* WXUNUSED(parent), wxWindowID winid, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -111,7 +112,7 @@ wxWidgetImplType* wxWidgetImpl::CreateBitmapButton( wxWindowMac* wxpeer, v.frame = r; if (bitmap.IsOk()) - [v setImage:bitmap.GetUIImage() forState:UIControlStateNormal]; + [v setImage: wxOSXGetImageFromBundle(bitmap) forState:UIControlStateNormal]; wxWidgetIPhoneImpl* c = new wxWidgetIPhoneImpl( wxpeer, v ); return c; diff --git a/src/osx/iphone/window.mm b/src/osx/iphone/window.mm index 16bb437522..88b7bd5040 100644 --- a/src/osx/iphone/window.mm +++ b/src/osx/iphone/window.mm @@ -475,7 +475,7 @@ void wxWidgetIPhoneImpl::SetValue( wxInt32 v ) { } -void wxWidgetIPhoneImpl::SetBitmap( const wxBitmap& bitmap ) +void wxWidgetIPhoneImpl::SetBitmap( const wxBitmapBundle& bitmap ) { } diff --git a/src/qt/anybutton.cpp b/src/qt/anybutton.cpp index 6a5f142b4f..5b21721194 100644 --- a/src/qt/anybutton.cpp +++ b/src/qt/anybutton.cpp @@ -90,10 +90,15 @@ void wxAnyButton::QtCreate(wxWindow *parent) m_qtPushButton->setAutoDefault(false); } -void wxAnyButton::QtSetBitmap( const wxBitmap &bitmap ) +void wxAnyButton::QtSetBitmap( const wxBitmapBundle &bitmapBundle ) { wxCHECK_RET(m_qtPushButton, "Invalid button."); + if ( !bitmapBundle.IsOk() ) + return; + + wxBitmap bitmap = bitmapBundle.GetBitmap(bitmapBundle.GetDefaultSize()*GetDPIScaleFactor()); + // load the bitmap and resize the button: QPixmap *pixmap = bitmap.GetHandle(); if ( pixmap != NULL ) @@ -117,10 +122,10 @@ QWidget *wxAnyButton::GetHandle() const wxBitmap wxAnyButton::DoGetBitmap(State state) const { - return state < State_Max ? m_bitmaps[state] : wxNullBitmap; + return state < State_Max ? m_bitmaps[state].GetBitmap(wxDefaultSize) : wxNullBitmap; } -void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxAnyButton::DoSetBitmap(const wxBitmapBundle& bitmap, State which) { wxCHECK_RET(which < State_Max, "Invalid state"); @@ -166,7 +171,7 @@ void wxAnyButton::QtUpdateState() State state = QtGetCurrentState(); // Update the bitmap - const wxBitmap& bmp = m_bitmaps[state]; + const wxBitmapBundle& bmp = m_bitmaps[state]; QtSetBitmap(bmp.IsOk() ? bmp : m_bitmaps[State_Normal]); } diff --git a/src/qt/bmpbuttn.cpp b/src/qt/bmpbuttn.cpp index c9417e3cb6..27c02debb5 100644 --- a/src/qt/bmpbuttn.cpp +++ b/src/qt/bmpbuttn.cpp @@ -17,7 +17,7 @@ wxBitmapButton::wxBitmapButton() wxBitmapButton::wxBitmapButton(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, @@ -30,7 +30,7 @@ wxBitmapButton::wxBitmapButton(wxWindow *parent, bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint& pos, const wxSize& size, long style, diff --git a/src/univ/bmpbuttn.cpp b/src/univ/bmpbuttn.cpp index cbb4b09ac0..e675ddbde0 100644 --- a/src/univ/bmpbuttn.cpp +++ b/src/univ/bmpbuttn.cpp @@ -45,7 +45,7 @@ wxEND_EVENT_TABLE() bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxPoint &pos, const wxSize &size, long style, diff --git a/src/univ/button.cpp b/src/univ/button.cpp index bb9f522992..0954093f00 100644 --- a/src/univ/button.cpp +++ b/src/univ/button.cpp @@ -54,7 +54,7 @@ void wxButton::Init() bool wxButton::Create(wxWindow *parent, wxWindowID id, - const wxBitmap& bitmap, + const wxBitmapBundle& bitmap, const wxString &lbl, const wxPoint &pos, const wxSize &size, @@ -148,12 +148,12 @@ wxBitmap wxButton::DoGetBitmap(State WXUNUSED(which)) const return m_bitmap; } -void wxButton::DoSetBitmap(const wxBitmap& bitmap, State which) +void wxButton::DoSetBitmap(const wxBitmapBundle& bitmap, State which) { // we support only one bitmap right now, although this wouldn't be // difficult to change if ( which == State_Normal ) - m_bitmap = bitmap; + m_bitmap = bitmap.GetBitmap(wxDefaultSize); // TODO-HIDPI SetBitmapMargins(DEFAULT_BTN_MARGIN_X, DEFAULT_BTN_MARGIN_Y); } From 2a0719818af652700a935eb72b92b1aa7e6d99a8 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Oct 2021 01:02:08 +0100 Subject: [PATCH 5/8] Update bitmap shown by the buttons in wxMSW on DPI change Recreate wxImageList used for the bitmaps internally with the bitmaps of the size corresponding to the new DPI. This commit is best viewed with --color-moved git option. --- src/msw/anybutton.cpp | 113 +++++++++++++++++++++++++++--------------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 2e8c268437..3661da374c 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -105,9 +105,10 @@ extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp class wxButtonImageData: public wxObject { public: - explicit wxButtonImageData(const wxSize& bitmapSize) - : m_bitmapSize(bitmapSize) + explicit wxButtonImageData(const wxBitmapBundle& normalBundle) + : m_bitmapSize(normalBundle.GetDefaultSize()) { + m_bitmapBundles[wxAnyButton::State_Normal] = normalBundle; } virtual ~wxButtonImageData() { } @@ -158,7 +159,7 @@ public: virtual wxDirection GetBitmapPosition() const = 0; virtual void SetBitmapPosition(wxDirection dir) = 0; -private: +protected: wxSize m_bitmapSize; wxBitmapBundle m_bitmapBundles[wxAnyButton::State_Max]; @@ -177,9 +178,10 @@ class wxODButtonImageData : public wxButtonImageData { public: wxODButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) - : wxButtonImageData(bitmapBundle.GetDefaultSize()) + : wxButtonImageData(bitmapBundle) { - SetBitmapBundle(bitmapBundle, wxAnyButton::State_Normal); + SetBitmap(GetBitmapFromBundle(bitmapBundle), + wxAnyButton::State_Normal); #if wxUSE_IMAGE SetBitmap(GetBitmapFromBundle(bitmapBundle).ConvertToDisabled(), wxAnyButton::State_Disabled); @@ -250,44 +252,10 @@ 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(bitmapBundle.GetDefaultSize()), + : wxButtonImageData(bitmapBundle), m_hwndBtn(GetHwndOf(btn)) { - // initialize all bitmaps except for the disabled one to normal state - const wxBitmap bitmap = bitmapBundle.GetBitmap(wxDefaultSize); - m_iml.Create - ( - bitmap.GetWidth(), - bitmap.GetHeight(), - !bitmap.HasAlpha() /* use mask only if no alpha */, - wxAnyButton::State_Max + 1 /* see "pulse" comment below */ - ); - - for ( int n = 0; n < wxAnyButton::State_Max; n++ ) - { -#if wxUSE_IMAGE - m_iml.Add(n == wxAnyButton::State_Disabled ? bitmap.ConvertToDisabled() - : bitmap); -#else - m_iml.Add(bitmap); -#endif - } - - // In addition to the states supported by wxWidgets such as normal, - // hot, pressed, disabled and focused, we need to add bitmap for - // another state when running under Windows 7 -- the so called "stylus - // hot" state corresponding to PBS_STYLUSHOT constant. While it's - // documented in MSDN as being only used with tablets, it is a lie as - // a focused button actually alternates between the image list elements - // with PBS_DEFAULTED and PBS_STYLUSHOT indices and, in particular, - // just disappears during half of the time if the latter is not set so - // we absolutely must set it. - // - // This also explains why we need to allocate an extra slot when creating - // the image list above, the slot State_Max is used for this one. - m_iml.Add(bitmap); - - m_data.himl = GetHimagelistOf(&m_iml); + InitImageList(); // no margins by default ::SetRectEmpty(&m_data.margin); @@ -296,6 +264,9 @@ 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 @@ -383,6 +354,52 @@ public: } private: + void InitImageList() + { + const wxBitmap + bitmap = m_bitmapBundles[wxAnyButton::State_Normal].GetBitmap(m_bitmapSize); + + m_iml.Create + ( + bitmap.GetWidth(), + bitmap.GetHeight(), + !bitmap.HasAlpha() /* use mask only if no alpha */, + wxAnyButton::State_Max + 1 /* see "pulse" comment below */ + ); + + m_data.himl = GetHimagelistOf(&m_iml); + + 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; + } + + m_iml.Add(bitmap); + } + + // In addition to the states supported by wxWidgets such as normal, + // hot, pressed, disabled and focused, we need to add bitmap for + // another state when running under Windows 7 -- the so called "stylus + // hot" state corresponding to PBS_STYLUSHOT constant. While it's + // documented in MSDN as being only used with tablets, it is a lie as + // a focused button actually alternates between the image list elements + // with PBS_DEFAULTED and PBS_STYLUSHOT indices and, in particular, + // just disappears during half of the time if the latter is not set so + // we absolutely must set it. + // + // This also explains why we need to allocate an extra slot when creating + // the image list above, the slot State_Max is used for this one. + m_iml.Add(bitmap); + } + void UpdateImageInfo() { if ( !::SendMessage(m_hwndBtn, BCM_SETIMAGELIST, 0, (LPARAM)&m_data) ) @@ -391,6 +408,20 @@ private: } } + void OnDPIChanged(wxDPIChangedEvent& event) + { + event.Skip(); + + // We need to recreate the image list using the new size and re-add all + // bitmaps to it. + m_bitmapSize = event.Scale(m_bitmapSize); + + m_iml.Destroy(); + InitImageList(); + + UpdateImageInfo(); + } + // we store image list separately to be able to use convenient wxImageList // methods instead of working with raw HIMAGELIST wxImageList m_iml; From 62b6539eea352b65a62eab1908719bc12804c44a Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Oct 2021 17:23:37 +0100 Subject: [PATCH 6/8] Select the button size appropriate for the current DPI initially Don't just update the bitmaps size when we receive the DPI changed event, but also use size appropriate for the current DPI initially. --- src/msw/anybutton.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/msw/anybutton.cpp b/src/msw/anybutton.cpp index 3661da374c..0364d24ee5 100644 --- a/src/msw/anybutton.cpp +++ b/src/msw/anybutton.cpp @@ -105,9 +105,10 @@ extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp class wxButtonImageData: public wxObject { public: - explicit wxButtonImageData(const wxBitmapBundle& normalBundle) - : m_bitmapSize(normalBundle.GetDefaultSize()) + wxButtonImageData(wxWindow* btn, const wxBitmapBundle& normalBundle) { + m_bitmapSize = normalBundle.GetDefaultSize() * btn->GetDPIScaleFactor(); + m_bitmapBundles[wxAnyButton::State_Normal] = normalBundle; } @@ -178,7 +179,7 @@ class wxODButtonImageData : public wxButtonImageData { public: wxODButtonImageData(wxAnyButton *btn, const wxBitmapBundle& bitmapBundle) - : wxButtonImageData(bitmapBundle) + : wxButtonImageData(btn, bitmapBundle) { SetBitmap(GetBitmapFromBundle(bitmapBundle), wxAnyButton::State_Normal); @@ -252,7 +253,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(bitmapBundle), + : wxButtonImageData(btn, bitmapBundle), m_hwndBtn(GetHwndOf(btn)) { InitImageList(); From 04a8e0e5bda4123e8c556551a1acc96bfcf32e84 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Oct 2021 18:28:52 +0100 Subject: [PATCH 7/8] Use bitmap bundle rather than scaled bitmap size in wxToolBar Get the minimum size needed for the bitmaps from wxBitmapBundle. --- src/common/tbarbase.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/common/tbarbase.cpp b/src/common/tbarbase.cpp index 251600f652..9d2cbbbcbe 100644 --- a/src/common/tbarbase.cpp +++ b/src/common/tbarbase.cpp @@ -444,13 +444,14 @@ void wxToolBarBase::AdjustToolBitmapSize() wxSize sizeActual(sizeOrig); + const double scale = GetDPIScaleFactor(); for ( wxToolBarToolsList::const_iterator i = m_tools.begin(); i != m_tools.end(); ++i ) { - const wxBitmap& bmp = (*i)->GetNormalBitmap(); + const wxBitmapBundle& bmp = (*i)->GetNormalBitmapBundle(); if ( bmp.IsOk() ) - sizeActual.IncTo(bmp.GetScaledSize()); + sizeActual.IncTo(bmp.GetDefaultSize()*scale); } if ( sizeActual != sizeOrig ) From 5bb6046ca90eb282ad8a8527b4e6153f8c9a9490 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sun, 17 Oct 2021 18:29:48 +0100 Subject: [PATCH 8/8] Document remaining problems when changing DPI of wxMSW toolbar Unfortunately even using CallAfter() doesn't allow to completely repair the toolbar display after moving it to a display with a different fractional scaling, e.g. from 125% to 175%. There are still some minor but visible display artefacts in this case that we can't get rid of even by resizing the window containing the toolbar programmatically -- even though doing it interactively does help. --- src/msw/toolbar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/msw/toolbar.cpp b/src/msw/toolbar.cpp index fe7b8f49d2..b9d38736c8 100644 --- a/src/msw/toolbar.cpp +++ b/src/msw/toolbar.cpp @@ -1991,7 +1991,10 @@ void wxToolBar::OnDPIChanged(wxDPIChangedEvent& event) // work. E.g. when switching from 125% to 150%. All the sizes are set // correctly, but after all dpi events are handled, 5px of the toolbar are // gone and a dark-gray bar appears. After resizing the window, the gray - // bar disapears as well. + // bar disappears as well, but unfortunately calling PostSizeEventToParent() + // either from here or even from RealizeHelper() itself doesn't work and + // there are still minor but visible cosmetic problems when moving the + // toolbar from 125% to 175% display. CallAfter(&wxToolBar::RealizeHelper); }