From 399b0ff9ae70adf9e3e1339cbebfc03d29c53ecb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Sat, 16 Oct 2021 19:56:01 +0200 Subject: [PATCH] Use wxBitmapBundle instead of bitmap scale factor in wxGtkImage Minimal changes to the code to allow using bigger bitmaps from wxBitmapBundle in high DPI instead of having to create individual bitmaps with scale factor greater than 1. Notice that this is not actually used anywhere in wxGTK yet, but will be soon. --- include/wx/gtk/private/image.h | 19 ++++++++- src/gtk/image_gtk.cpp | 78 ++++++++++++++++++++-------------- src/gtk/toolbar.cpp | 7 +++ 3 files changed, 69 insertions(+), 35 deletions(-) diff --git a/include/wx/gtk/private/image.h b/include/wx/gtk/private/image.h index ce664c6d86..24baebfdd3 100644 --- a/include/wx/gtk/private/image.h +++ b/include/wx/gtk/private/image.h @@ -5,6 +5,9 @@ // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// +#include "wx/bmpbndl.h" +#include "wx/math.h" + // Class that can be used in place of GtkImage, to allow drawing of alternate // bitmaps, such as HiDPI or disabled. @@ -14,14 +17,26 @@ public: struct BitmapProvider { virtual ~BitmapProvider() { } + + virtual double GetScale() const = 0; virtual wxBitmap Get() const = 0; - virtual void Set(const wxBitmap&) { } + virtual void Set(const wxBitmapBundle&) { } + + // Simple helpers used in implementation. + bool IsScaled() const { return !wxIsSameDouble(GetScale(), 1); } + wxBitmap GetAtScale(const wxBitmapBundle& b) const + { + return b.GetBitmap(b.GetDefaultSize()*GetScale()); + } }; static GType Type(); static GtkWidget* New(BitmapProvider* provider); static GtkWidget* New(wxWindow* win = NULL); - void Set(const wxBitmap& bitmap); + + // Use bitmaps from the given bundle, the logical bitmap size is the + // default size of the bundle. + void Set(const wxBitmapBundle& bitmapBundle); // This pointer is never null and is owned by this class. BitmapProvider* m_provider; diff --git a/src/gtk/image_gtk.cpp b/src/gtk/image_gtk.cpp index eea80ff277..98ef9a8589 100644 --- a/src/gtk/image_gtk.cpp +++ b/src/gtk/image_gtk.cpp @@ -7,7 +7,6 @@ #include "wx/wxprec.h" -#include "wx/bitmap.h" #include "wx/window.h" #include "wx/gtk/private/wrapgtk.h" @@ -22,45 +21,49 @@ namespace struct BitmapProviderDefault: wxGtkImage::BitmapProvider { BitmapProviderDefault(wxWindow* win) : m_win(win) { } + + virtual double GetScale() const wxOVERRIDE; virtual wxBitmap Get() const wxOVERRIDE; - virtual void Set(const wxBitmap& bitmap) wxOVERRIDE; + virtual void Set(const wxBitmapBundle& bitmap) wxOVERRIDE; + // This pointer can be null if there is no associated window. wxWindow* const m_win; - // The bitmap stored here is only valid if it uses scale factor > 1, - // otherwise we leave it invalid to indicate the drawing the bitmap should - // be left to GtkImage itself. - wxBitmap m_bitmap; + // All the bitmaps we use. + wxBitmapBundle m_bitmapBundle; - // This bitmap is created on demand from m_bitmap when necessary (and is - // mutable because this is done in const Get()). + // This bitmap is created on demand from m_bitmapBundle when necessary (and + // is mutable because this is done in const Get()). mutable wxBitmap m_bitmapDisabled; }; +double BitmapProviderDefault::GetScale() const +{ + return m_win ? m_win->GetDPIScaleFactor() : 1.0; +} + wxBitmap BitmapProviderDefault::Get() const { if ( m_win && !m_win->IsEnabled() ) { - if ( !m_bitmapDisabled.IsOk() && m_bitmap.IsOk() ) - m_bitmapDisabled = m_bitmap.CreateDisabled(); + if ( !m_bitmapDisabled.IsOk() && m_bitmapBundle.IsOk() ) + m_bitmapDisabled = GetAtScale(m_bitmapBundle).CreateDisabled(); return m_bitmapDisabled; } - return m_bitmap; + // We currently don't return the bitmap we use from here when scale is 1, + // as then we can just let GtkImage draw the bitmap it has. + return IsScaled() ? GetAtScale(m_bitmapBundle) : wxBitmap(); } -void BitmapProviderDefault::Set(const wxBitmap& bitmap) +void BitmapProviderDefault::Set(const wxBitmapBundle& bitmapBundle) { - m_bitmap.UnRef(); + m_bitmapBundle = bitmapBundle; // Ensure it's recreated if needed later. m_bitmapDisabled.UnRef(); - if (bitmap.IsOk() && bitmap.GetScaleFactor() > 1) - { - m_bitmap = bitmap; - } } #else // !__WXGTK3__ @@ -69,6 +72,7 @@ void BitmapProviderDefault::Set(const wxBitmap& bitmap) struct BitmapProviderDefault: wxGtkImage::BitmapProvider { BitmapProviderDefault(wxWindow*) { } + virtual double GetScale() const wxOVERRIDE { return 1.0; } virtual wxBitmap Get() const wxOVERRIDE { return wxBitmap(); } }; @@ -110,27 +114,20 @@ GtkWidget* wxGtkImage::New(wxWindow* win) return New(new BitmapProviderDefault(win)); } -void wxGtkImage::Set(const wxBitmap& bitmap) +void wxGtkImage::Set(const wxBitmapBundle& bitmapBundle) { - m_provider->Set(bitmap); + m_provider->Set(bitmapBundle); + + // Always set the default bitmap to use the correct size, even if we draw a + // different bitmap below. + wxBitmap bitmap = bitmapBundle.GetBitmap(wxDefaultSize); GdkPixbuf* pixbuf = NULL; - GdkPixbuf* pixbufNew = NULL; if (bitmap.IsOk()) { - if (bitmap.GetScaleFactor() <= 1) - pixbuf = bitmap.GetPixbuf(); - else - { - // Placeholder pixbuf for correct size - pixbufNew = - pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, - int(bitmap.GetScaledWidth()), int(bitmap.GetScaledHeight())); - } + pixbuf = bitmap.GetPixbuf(); } gtk_image_set_from_pixbuf(GTK_IMAGE(this), pixbuf); - if (pixbufNew) - g_object_unref(pixbufNew); } static GtkWidgetClass* wxGtkImageParentClass; @@ -144,9 +141,13 @@ static gboolean wxGtkImageDraw(GtkWidget* widget, GdkEventExpose* event) #endif { wxGtkImage* image = WX_GTK_IMAGE(widget); + const wxBitmap bitmap(image->m_provider->Get()); if (!bitmap.IsOk()) { + // Just let GtkImage draw the bitmap in standard DPI. Arguably, we + // should still be drawing it ourselves even in this case just for + // consistency, but for now keep the original behaviour. #ifdef __WXGTK3__ return wxGtkImageParentClass->draw(widget, cr); #else @@ -154,13 +155,24 @@ static gboolean wxGtkImageDraw(GtkWidget* widget, GdkEventExpose* event) #endif } + const double scaleFactor = image->m_provider->GetScale(); + GtkAllocation alloc; gtk_widget_get_allocation(widget, &alloc); - int x = (alloc.width - int(bitmap.GetScaledWidth() )) / 2; - int y = (alloc.height - int(bitmap.GetScaledHeight())) / 2; + int x = (alloc.width - int(bitmap.GetWidth() /scaleFactor)) / 2; + int y = (alloc.height - int(bitmap.GetHeight()/scaleFactor)) / 2; #ifdef __WXGTK3__ gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, alloc.width, alloc.height); + + if (!wxIsSameDouble(scaleFactor, 1)) + { + cairo_translate(cr, x, y); + const double scale = 1 / scaleFactor; + cairo_scale(cr, scale, scale); + x = 0; + y = 0; + } bitmap.Draw(cr, x, y); #else x += alloc.x; diff --git a/src/gtk/toolbar.cpp b/src/gtk/toolbar.cpp index 9429a5fb33..fdb45ed270 100644 --- a/src/gtk/toolbar.cpp +++ b/src/gtk/toolbar.cpp @@ -176,10 +176,17 @@ namespace struct BitmapProvider: wxGtkImage::BitmapProvider { BitmapProvider(wxToolBarTool* tool) : m_tool(tool) { } + + virtual double GetScale() const wxOVERRIDE; virtual wxBitmap Get() const wxOVERRIDE; wxToolBarTool* const m_tool; }; +double BitmapProvider::GetScale() const +{ + return m_tool->GetToolBar()->GetDPIScaleFactor(); +} + wxBitmap BitmapProvider::Get() const { #ifdef __WXGTK3__