From b376d1402bdc48614888704cf191f82a630d93c0 Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Wed, 16 Sep 2020 11:33:13 -0700 Subject: [PATCH] Add support for HiDPI bitmaps to wxDataViewBitmapRenderer with GTK3 --- src/gtk/dataview.cpp | 153 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 124 insertions(+), 29 deletions(-) diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 0e8cabd13d..9393eccbf5 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -2464,28 +2464,126 @@ GtkCellRendererText *wxDataViewTextRenderer::GtkGetTextRenderer() const // wxDataViewBitmapRenderer // --------------------------------------------------------- -namespace -{ +#ifdef __WXGTK3__ +// Derive a type from GtkCellRendererPixbuf to allow drawing HiDPI bitmaps -// set "pixbuf" property on the given renderer -void SetPixbufProp(GtkCellRenderer *renderer, GdkPixbuf *pixbuf) -{ - GValue gvalue = G_VALUE_INIT; - g_value_init( &gvalue, G_TYPE_OBJECT ); - g_value_set_object( &gvalue, pixbuf ); - g_object_set_property( G_OBJECT(renderer), "pixbuf", &gvalue ); - g_value_unset( &gvalue ); +extern "C" { +static void wxCellRendererPixbufClassInit(void* g_class, void* class_data); } +#define WX_CELL_RENDERER_PIXBUF(obj) G_TYPE_CHECK_INSTANCE_CAST(obj, wxCellRendererPixbuf::Type(), wxCellRendererPixbuf) + +namespace +{ +class wxCellRendererPixbuf: GtkCellRendererPixbuf +{ +public: + static GType Type(); + static GtkCellRenderer* New(); + void Set(const wxBitmap& bitmap); + + wxBitmap* m_bitmap; + + wxDECLARE_NO_COPY_CLASS(wxCellRendererPixbuf); + wxCellRendererPixbuf() wxMEMBER_DELETE; + ~wxCellRendererPixbuf() wxMEMBER_DELETE; +}; + +GtkCellRendererClass* wxCellRendererPixbufParentClass; + +GType wxCellRendererPixbuf::Type() +{ + static GType type; + if (type == 0) + { + type = g_type_register_static_simple( + GTK_TYPE_CELL_RENDERER_PIXBUF, + "wxCellRendererPixbuf", + sizeof(GtkCellRendererPixbufClass), + wxCellRendererPixbufClassInit, + sizeof(wxCellRendererPixbuf), + NULL, GTypeFlags(0)); + } + return type; +} + +GtkCellRenderer* wxCellRendererPixbuf::New() +{ + wxCellRendererPixbuf* crp = WX_CELL_RENDERER_PIXBUF(g_object_new(Type(), NULL)); + crp->m_bitmap = new wxBitmap; + return GTK_CELL_RENDERER(crp); +} + +void wxCellRendererPixbuf::Set(const wxBitmap& bitmap) +{ + *m_bitmap = bitmap; + + GdkPixbuf* pixbuf = NULL; + GdkPixbuf* pixbufNew = NULL; + if (bitmap.IsOk()) + { + if (bitmap.GetScaleFactor() <= 1) + { + pixbuf = bitmap.GetPixbuf(); + m_bitmap->UnRef(); + } + else + { + pixbufNew = + pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, + int(bitmap.GetScaledWidth()), int(bitmap.GetScaledHeight())); + } + } + g_object_set(G_OBJECT(this), "pixbuf", pixbuf, NULL); + if (pixbufNew) + g_object_unref(pixbufNew); +} } // anonymous namespace +extern "C" { +static void +wxCellRendererPixbufRender(GtkCellRenderer* cell, cairo_t* cr, GtkWidget* widget, + const GdkRectangle* background_area, const GdkRectangle* cell_area, GtkCellRendererState flags) +{ + const wxBitmap& bitmap = *WX_CELL_RENDERER_PIXBUF(cell)->m_bitmap; + if (!bitmap.IsOk()) + wxCellRendererPixbufParentClass->render(cell, cr, widget, background_area, cell_area, flags); + else + { + const int x = (cell_area->width - int(bitmap.GetScaledWidth() )) / 2; + const int y = (cell_area->height - int(bitmap.GetScaledHeight())) / 2; + bitmap.Draw(cr, cell_area->x + x, cell_area->y + y); + } +} + +static void wxCellRendererPixbufFinalize(GObject* object) +{ + wxCellRendererPixbuf* crp = WX_CELL_RENDERER_PIXBUF(object); + delete crp->m_bitmap; + crp->m_bitmap = NULL; + G_OBJECT_CLASS(wxCellRendererPixbufParentClass)->finalize(object); +} + +static void wxCellRendererPixbufClassInit(void* g_class, void* /*class_data*/) +{ + GTK_CELL_RENDERER_CLASS(g_class)->render = wxCellRendererPixbufRender; + G_OBJECT_CLASS(g_class)->finalize = wxCellRendererPixbufFinalize; + wxCellRendererPixbufParentClass = GTK_CELL_RENDERER_CLASS(g_type_class_peek_parent(g_class)); +} +} // extern "C" +#endif // __WXGTK3__ + wxIMPLEMENT_CLASS(wxDataViewBitmapRenderer, wxDataViewRenderer); wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, wxDataViewCellMode mode, int align ) : wxDataViewRenderer( varianttype, mode, align ) { +#ifdef __WXGTK3__ + m_renderer = wxCellRendererPixbuf::New(); +#else m_renderer = gtk_cell_renderer_pixbuf_new(); +#endif SetMode(mode); SetAlignment(align); @@ -2493,26 +2591,15 @@ wxDataViewBitmapRenderer::wxDataViewBitmapRenderer( const wxString &varianttype, bool wxDataViewBitmapRenderer::SetValue( const wxVariant &value ) { - if (value.GetType() == wxT("wxBitmap")) - { - wxBitmap bitmap; + wxBitmap bitmap; + if (value.GetType() == wxS("wxBitmap") || value.GetType() == wxS("wxIcon")) bitmap << value; - // GetPixbuf() may create a Pixbuf representation in the wxBitmap - // object (and it will stay there and remain owned by wxBitmap) - SetPixbufProp(m_renderer, bitmap.IsOk() ? bitmap.GetPixbuf() : NULL); - } - else if (value.GetType() == wxT("wxIcon")) - { - wxIcon icon; - icon << value; - - SetPixbufProp(m_renderer, icon.IsOk() ? icon.GetPixbuf() : NULL); - } - else - { - SetPixbufProp(m_renderer, NULL); - } +#ifdef __WXGTK3__ + WX_CELL_RENDERER_PIXBUF(m_renderer)->Set(bitmap); +#else + g_object_set(G_OBJECT(m_renderer), "pixbuf", bitmap.IsOk() ? bitmap.GetPixbuf() : NULL, NULL); +#endif return true; } @@ -3033,7 +3120,11 @@ wxDataViewIconTextRenderer::wxDataViewIconTextRenderer ) : wxDataViewTextRenderer(varianttype, mode, align) { +#ifdef __WXGTK3__ + m_rendererIcon = wxCellRendererPixbuf::New(); +#else m_rendererIcon = gtk_cell_renderer_pixbuf_new(); +#endif } wxDataViewIconTextRenderer::~wxDataViewIconTextRenderer() @@ -3056,7 +3147,11 @@ bool wxDataViewIconTextRenderer::SetValue( const wxVariant &value ) SetTextValue(m_value.GetText()); const wxIcon& icon = m_value.GetIcon(); - SetPixbufProp(m_rendererIcon, icon.IsOk() ? icon.GetPixbuf() : NULL); +#ifdef __WXGTK3__ + WX_CELL_RENDERER_PIXBUF(m_rendererIcon)->Set(icon); +#else + g_object_set(G_OBJECT(m_rendererIcon), "pixbuf", icon.IsOk() ? icon.GetPixbuf() : NULL, NULL); +#endif return true; }