diff --git a/include/wx/gtk/private/image.h b/include/wx/gtk/private/image.h index c346cd7919..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,18 +17,34 @@ 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; wxDECLARE_NO_COPY_CLASS(wxGtkImage); + + // This class is constructed by New() and destroyed by its GObject + // finalizer, so neither its ctor nor dtor can ever be used. wxGtkImage() wxMEMBER_DELETE; ~wxGtkImage() wxMEMBER_DELETE; }; diff --git a/include/wx/tbarbase.h b/include/wx/tbarbase.h index c489d4c068..b6addcc4cf 100644 --- a/include/wx/tbarbase.h +++ b/include/wx/tbarbase.h @@ -146,6 +146,9 @@ public: { return m_kind == wxITEM_CHECK || m_kind == wxITEM_RADIO; } // attributes + wxBitmapBundle GetNormalBitmapBundle() const { return m_bmpNormal; } + wxBitmapBundle GetDisabledBitmapBundle() const { return m_bmpDisabled; } + wxBitmap GetNormalBitmap(const wxSize& size = wxDefaultSize) const { return m_bmpNormal.GetBitmap(size); } wxBitmap GetDisabledBitmap(const wxSize& size = wxDefaultSize) const diff --git a/interface/wx/toolbar.h b/interface/wx/toolbar.h index 35474cf509..19cf6a4506 100644 --- a/interface/wx/toolbar.h +++ b/interface/wx/toolbar.h @@ -112,6 +112,26 @@ public: bool IsToggled() const; bool CanBeToggled() const; + /** + Return the bundle containing normal tool bitmaps. + + This bundle may be invalid if the tool doesn't show a bitmap. + + @since 3.1.6 + */ + wxBitmapBundle GetNormalBitmapBundle() const; + + /** + Return the bundle containing disabled tool bitmaps. + + This bundle may be invalid if the tool doesn't show a bitmap or doesn't + have a specific disabled bitmap creates one automatically from the + normal bitmap. + + @since 3.1.6 + */ + wxBitmapBundle GetDisabledBitmapBundle() const; + wxBitmap GetNormalBitmap() const; wxBitmap GetDisabledBitmap() const; diff --git a/src/gtk/image_gtk.cpp b/src/gtk/image_gtk.cpp index 348637df82..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" @@ -15,40 +14,70 @@ namespace { + +#ifdef __WXGTK3__ + // Default provider for HiDPI common case struct BitmapProviderDefault: wxGtkImage::BitmapProvider { -#ifdef __WXGTK3__ 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; - wxBitmap m_bitmap; - wxBitmap m_bitmapDisabled; -#else - BitmapProviderDefault(wxWindow*) { } - virtual wxBitmap Get() const wxOVERRIDE { return wxBitmap(); } -#endif + + // All the bitmaps we use. + wxBitmapBundle m_bitmapBundle; + + // 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; }; -#ifdef __WXGTK3__ -wxBitmap BitmapProviderDefault::Get() const +double BitmapProviderDefault::GetScale() const { - return (m_win == NULL || m_win->IsEnabled()) ? m_bitmap : m_bitmapDisabled; + return m_win ? m_win->GetDPIScaleFactor() : 1.0; } -void BitmapProviderDefault::Set(const wxBitmap& bitmap) +wxBitmap BitmapProviderDefault::Get() const { - m_bitmap.UnRef(); - m_bitmapDisabled.UnRef(); - if (bitmap.IsOk() && bitmap.GetScaleFactor() > 1) + if ( m_win && !m_win->IsEnabled() ) { - m_bitmap = bitmap; - if (m_win) - m_bitmapDisabled = bitmap.CreateDisabled(); + if ( !m_bitmapDisabled.IsOk() && m_bitmapBundle.IsOk() ) + m_bitmapDisabled = GetAtScale(m_bitmapBundle).CreateDisabled(); + + return m_bitmapDisabled; } + + // 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(); } -#endif // __WXGTK3__ + +void BitmapProviderDefault::Set(const wxBitmapBundle& bitmapBundle) +{ + m_bitmapBundle = bitmapBundle; + + // Ensure it's recreated if needed later. + m_bitmapDisabled.UnRef(); +} + +#else // !__WXGTK3__ + +// Trivial version for GTK < 3 which doesn't provide any high DPI support. +struct BitmapProviderDefault: wxGtkImage::BitmapProvider +{ + BitmapProviderDefault(wxWindow*) { } + virtual double GetScale() const wxOVERRIDE { return 1.0; } + virtual wxBitmap Get() const wxOVERRIDE { return wxBitmap(); } +}; + +#endif // __WXGTK3__/!__WXGTK3__ + } // namespace extern "C" { @@ -85,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; @@ -119,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 @@ -129,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..e2f1c121ae 100644 --- a/src/gtk/toolbar.cpp +++ b/src/gtk/toolbar.cpp @@ -176,36 +176,41 @@ 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__ - wxBitmap bitmap(m_tool->GetNormalBitmap()); - if (m_tool->IsEnabled()) + if (!m_tool->IsEnabled()) { - if (bitmap.IsOk() && bitmap.GetScaleFactor() <= 1) - bitmap.UnRef(); - } - else - { - wxBitmap disabled(m_tool->GetDisabledBitmap()); + wxBitmap disabled(GetAtScale(m_tool->GetDisabledBitmapBundle())); // if no disabled bitmap and normal bitmap is scaled - if (!disabled.IsOk() && bitmap.IsOk() && bitmap.GetScaleFactor() > 1) + if (!disabled.IsOk() && IsScaled()) { // make scaled disabled bitmap from normal one - disabled = bitmap.CreateDisabled(); + wxBitmap bitmap(GetAtScale(m_tool->GetNormalBitmapBundle())); + if (bitmap.IsOk()) + disabled = bitmap.CreateDisabled(); } - bitmap = disabled; + return disabled; } + + if (IsScaled()) + return GetAtScale(m_tool->GetNormalBitmapBundle()); #else - wxBitmap bitmap; if (!m_tool->IsEnabled()) - bitmap = m_tool->GetDisabledBitmap(); + return m_tool->GetDisabledBitmap(); #endif - return bitmap; + return wxBitmap(); } } // namespace