Merge branch 'gtk-image-bundle'

Use wxBitmapBundle in wxGtkImage and select the appropriately-sized
bitmaps depending on DPI in wxGTK wxToolBar.

See https://github.com/wxWidgets/wxWidgets/pull/2547
This commit is contained in:
Vadim Zeitlin
2021-10-17 23:19:00 +02:00
5 changed files with 136 additions and 52 deletions

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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