Bitmaps returned from this function must have the appropriate scale
factor, e.g. 2 in standard high DPI case, in order to be drawn at
correct size in the ports where logical pixels are different from the
physical ones, such as wxOSX and wxGTK3.
Notably, this allows wxGenericStaticBitmap to work correctly in high DPI
in these ports too.
This also allows to undo some of the changes done in 399b0ff9ae
(Use
wxBitmapBundle instead of bitmap scale factor in wxGtkImage, 2021-10-16)
to wxGtkImage code and keep using the same code that had been used
before.
196 lines
5.3 KiB
C++
196 lines
5.3 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/gtk/image_gtk.cpp
|
|
// Author: Paul Cornett
|
|
// Copyright: (c) 2020 Paul Cornett
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "wx/wxprec.h"
|
|
|
|
#include "wx/window.h"
|
|
|
|
#include "wx/gtk/private/wrapgtk.h"
|
|
#include "wx/gtk/private/image.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
#ifdef __WXGTK3__
|
|
|
|
// Default provider for HiDPI common case
|
|
struct BitmapProviderDefault: wxGtkImage::BitmapProvider
|
|
{
|
|
BitmapProviderDefault(wxWindow* win) : m_win(win) { }
|
|
|
|
virtual double GetScale() const wxOVERRIDE;
|
|
virtual wxBitmap Get() const wxOVERRIDE;
|
|
virtual void Set(const wxBitmapBundle& bitmap) wxOVERRIDE;
|
|
|
|
|
|
// This pointer can be null if there is no associated window.
|
|
wxWindow* const m_win;
|
|
|
|
// 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;
|
|
};
|
|
|
|
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_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();
|
|
}
|
|
|
|
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" {
|
|
static void wxGtkImageClassInit(void* g_class, void* class_data);
|
|
}
|
|
|
|
GType wxGtkImage::Type()
|
|
{
|
|
static GType type;
|
|
if (type == 0)
|
|
{
|
|
const GTypeInfo info = {
|
|
sizeof(GtkImageClass),
|
|
NULL, NULL,
|
|
wxGtkImageClassInit, NULL, NULL,
|
|
sizeof(wxGtkImage), 0, NULL,
|
|
NULL
|
|
};
|
|
type = g_type_register_static(
|
|
GTK_TYPE_IMAGE, "wxGtkImage", &info, GTypeFlags(0));
|
|
}
|
|
return type;
|
|
}
|
|
|
|
GtkWidget* wxGtkImage::New(BitmapProvider* provider)
|
|
{
|
|
wxGtkImage* image = WX_GTK_IMAGE(g_object_new(Type(), NULL));
|
|
image->m_provider = provider;
|
|
return GTK_WIDGET(image);
|
|
}
|
|
|
|
GtkWidget* wxGtkImage::New(wxWindow* win)
|
|
{
|
|
return New(new BitmapProviderDefault(win));
|
|
}
|
|
|
|
void wxGtkImage::Set(const wxBitmapBundle& bitmapBundle)
|
|
{
|
|
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;
|
|
if (bitmap.IsOk())
|
|
{
|
|
pixbuf = bitmap.GetPixbuf();
|
|
}
|
|
gtk_image_set_from_pixbuf(GTK_IMAGE(this), pixbuf);
|
|
}
|
|
|
|
static GtkWidgetClass* wxGtkImageParentClass;
|
|
|
|
extern "C"
|
|
{
|
|
#ifdef __WXGTK3__
|
|
static gboolean wxGtkImageDraw(GtkWidget* widget, cairo_t* cr)
|
|
#else
|
|
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
|
|
return wxGtkImageParentClass->expose_event(widget, event);
|
|
#endif
|
|
}
|
|
|
|
GtkAllocation alloc;
|
|
gtk_widget_get_allocation(widget, &alloc);
|
|
int x = (alloc.width - int(bitmap.GetScaledWidth() )) / 2;
|
|
int y = (alloc.height - int(bitmap.GetScaledHeight())) / 2;
|
|
#ifdef __WXGTK3__
|
|
gtk_render_background(gtk_widget_get_style_context(widget),
|
|
cr, 0, 0, alloc.width, alloc.height);
|
|
bitmap.Draw(cr, x, y);
|
|
#else
|
|
x += alloc.x;
|
|
y += alloc.y;
|
|
gdk_draw_pixbuf(
|
|
gtk_widget_get_window(widget), gtk_widget_get_style(widget)->black_gc, bitmap.GetPixbuf(),
|
|
0, 0, x, y,
|
|
-1, -1, GDK_RGB_DITHER_NORMAL, 0, 0);
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
static void wxGtkImageFinalize(GObject* object)
|
|
{
|
|
wxGtkImage* image = WX_GTK_IMAGE(object);
|
|
delete image->m_provider;
|
|
image->m_provider = NULL;
|
|
G_OBJECT_CLASS(wxGtkImageParentClass)->finalize(object);
|
|
}
|
|
|
|
static void wxGtkImageClassInit(void* g_class, void* /*class_data*/)
|
|
{
|
|
#ifdef __WXGTK3__
|
|
GTK_WIDGET_CLASS(g_class)->draw = wxGtkImageDraw;
|
|
#else
|
|
GTK_WIDGET_CLASS(g_class)->expose_event = wxGtkImageDraw;
|
|
#endif
|
|
G_OBJECT_CLASS(g_class)->finalize = wxGtkImageFinalize;
|
|
wxGtkImageParentClass = GTK_WIDGET_CLASS(g_type_class_peek_parent(g_class));
|
|
}
|
|
} // extern "C"
|