1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <vcl/svapp.hxx>
11 #include "customcellrenderer.hxx"
12 #if !GTK_CHECK_VERSION(4, 0, 0)
13 #include <gtk/gtk-a11y.h>
18 struct _CustomCellRendererClass
: public GtkCellRendererTextClass
25 PROP_INSTANCE_TREE_VIEW
= 10001
29 G_DEFINE_TYPE(CustomCellRenderer
, custom_cell_renderer
, GTK_TYPE_CELL_RENDERER_TEXT
)
31 static void custom_cell_renderer_init(CustomCellRenderer
* self
)
34 SolarMutexGuard aGuard
;
35 new (&self
->device
) VclPtr
<VirtualDevice
>;
38 // prevent loplugin:unreffun firing on macro generated function
39 (void)custom_cell_renderer_get_instance_private(self
);
42 static void custom_cell_renderer_get_property(GObject
* object
, guint param_id
, GValue
* value
,
45 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
50 g_value_set_string(value
, cellsurface
->id
);
52 case PROP_INSTANCE_TREE_VIEW
:
53 g_value_set_pointer(value
, cellsurface
->instance
);
56 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)
57 ->get_property(object
, param_id
, value
, pspec
);
62 static void custom_cell_renderer_set_property(GObject
* object
, guint param_id
, const GValue
* value
,
65 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
70 g_free(cellsurface
->id
);
71 cellsurface
->id
= g_value_dup_string(value
);
73 case PROP_INSTANCE_TREE_VIEW
:
74 cellsurface
->instance
= g_value_get_pointer(value
);
77 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)
78 ->set_property(object
, param_id
, value
, pspec
);
83 static bool custom_cell_renderer_get_preferred_size(GtkCellRenderer
* cell
,
84 GtkOrientation orientation
, gint
* minimum_size
,
87 #if GTK_CHECK_VERSION(4, 0, 0)
88 static void custom_cell_renderer_snapshot(GtkCellRenderer
* cell
, GtkSnapshot
* snapshot
,
89 GtkWidget
* widget
, const GdkRectangle
* background_area
,
90 const GdkRectangle
* cell_area
,
91 GtkCellRendererState flags
);
94 static void custom_cell_renderer_render(GtkCellRenderer
* cell
, cairo_t
* cr
, GtkWidget
* widget
,
95 const GdkRectangle
* background_area
,
96 const GdkRectangle
* cell_area
, GtkCellRendererState flags
);
98 static void custom_cell_renderer_finalize(GObject
* object
)
100 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(object
);
102 g_free(cellsurface
->id
);
105 SolarMutexGuard aGuard
;
106 cellsurface
->device
.disposeAndClear();
107 cellsurface
->device
.~VclPtr
<VirtualDevice
>();
110 G_OBJECT_CLASS(custom_cell_renderer_parent_class
)->finalize(object
);
113 static void custom_cell_renderer_get_preferred_width(GtkCellRenderer
* cell
, GtkWidget
* widget
,
114 gint
* minimum_size
, gint
* natural_size
)
116 if (!custom_cell_renderer_get_preferred_size(cell
, GTK_ORIENTATION_HORIZONTAL
, minimum_size
,
119 // fallback to parent if we're empty
120 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_parent_class
)
121 ->get_preferred_width(cell
, widget
, minimum_size
, natural_size
);
125 static void custom_cell_renderer_get_preferred_height(GtkCellRenderer
* cell
, GtkWidget
* widget
,
126 gint
* minimum_size
, gint
* natural_size
)
128 if (!custom_cell_renderer_get_preferred_size(cell
, GTK_ORIENTATION_VERTICAL
, minimum_size
,
131 // fallback to parent if we're empty
132 GTK_CELL_RENDERER_CLASS(custom_cell_renderer_parent_class
)
133 ->get_preferred_height(cell
, widget
, minimum_size
, natural_size
);
137 static void custom_cell_renderer_get_preferred_height_for_width(GtkCellRenderer
* cell
,
138 GtkWidget
* widget
, gint
/*width*/,
139 gint
* minimum_height
,
140 gint
* natural_height
)
142 gtk_cell_renderer_get_preferred_height(cell
, widget
, minimum_height
, natural_height
);
145 static void custom_cell_renderer_get_preferred_width_for_height(GtkCellRenderer
* cell
,
146 GtkWidget
* widget
, gint
/*height*/,
150 gtk_cell_renderer_get_preferred_width(cell
, widget
, minimum_width
, natural_width
);
153 void custom_cell_renderer_class_init(CustomCellRendererClass
* klass
)
155 GtkCellRendererClass
* cell_class
= GTK_CELL_RENDERER_CLASS(klass
);
156 GObjectClass
* object_class
= G_OBJECT_CLASS(klass
);
158 /* Hook up functions to set and get our custom cell renderer properties */
159 object_class
->get_property
= custom_cell_renderer_get_property
;
160 object_class
->set_property
= custom_cell_renderer_set_property
;
162 custom_cell_renderer_parent_class
= g_type_class_peek_parent(klass
);
163 object_class
->finalize
= custom_cell_renderer_finalize
;
165 cell_class
->get_preferred_width
= custom_cell_renderer_get_preferred_width
;
166 cell_class
->get_preferred_height
= custom_cell_renderer_get_preferred_height
;
167 cell_class
->get_preferred_width_for_height
168 = custom_cell_renderer_get_preferred_width_for_height
;
169 cell_class
->get_preferred_height_for_width
170 = custom_cell_renderer_get_preferred_height_for_width
;
172 #if GTK_CHECK_VERSION(4, 0, 0)
173 cell_class
->snapshot
= custom_cell_renderer_snapshot
;
175 cell_class
->render
= custom_cell_renderer_render
;
178 g_object_class_install_property(
179 object_class
, PROP_ID
,
180 g_param_spec_string("id", "ID", "The ID of the custom data", nullptr, G_PARAM_READWRITE
));
182 g_object_class_install_property(
183 object_class
, PROP_INSTANCE_TREE_VIEW
,
184 g_param_spec_pointer("instance", "Instance", "The GtkInstanceTreeView", G_PARAM_READWRITE
));
186 #if !GTK_CHECK_VERSION(4, 0, 0)
187 gtk_cell_renderer_class_set_accessible_type(cell_class
, GTK_TYPE_TEXT_CELL_ACCESSIBLE
);
191 GtkCellRenderer
* custom_cell_renderer_new()
193 return GTK_CELL_RENDERER(g_object_new(CUSTOM_TYPE_CELL_RENDERER
, nullptr));
196 bool custom_cell_renderer_get_preferred_size(GtkCellRenderer
* cell
, GtkOrientation orientation
,
197 gint
* minimum_size
, gint
* natural_size
)
199 GValue value
= G_VALUE_INIT
;
200 g_value_init(&value
, G_TYPE_STRING
);
201 g_object_get_property(G_OBJECT(cell
), "id", &value
);
203 const char* pStr
= g_value_get_string(&value
);
205 OUString
sId(pStr
, pStr
? strlen(pStr
) : 0, RTL_TEXTENCODING_UTF8
);
207 value
= G_VALUE_INIT
;
208 g_value_init(&value
, G_TYPE_POINTER
);
209 g_object_get_property(G_OBJECT(cell
), "instance", &value
);
211 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(cell
);
215 gpointer pWidget
= g_value_get_pointer(&value
);
218 SolarMutexGuard aGuard
;
219 custom_cell_renderer_ensure_device(cellsurface
, pWidget
);
220 aSize
= custom_cell_renderer_get_size(*cellsurface
->device
, sId
, pWidget
);
223 if (orientation
== GTK_ORIENTATION_HORIZONTAL
)
226 *minimum_size
= aSize
.Width();
229 *natural_size
= aSize
.Width();
234 *minimum_size
= aSize
.Height();
237 *natural_size
= aSize
.Height();
243 void custom_cell_renderer_render(GtkCellRenderer
* cell
, cairo_t
* cr
, GtkWidget
* /*widget*/,
244 const GdkRectangle
* /*background_area*/,
245 const GdkRectangle
* cell_area
, GtkCellRendererState flags
)
247 GValue value
= G_VALUE_INIT
;
248 g_value_init(&value
, G_TYPE_STRING
);
249 g_object_get_property(G_OBJECT(cell
), "id", &value
);
251 const char* pStr
= g_value_get_string(&value
);
252 OUString
sId(pStr
, pStr
? strlen(pStr
) : 0, RTL_TEXTENCODING_UTF8
);
254 value
= G_VALUE_INIT
;
255 g_value_init(&value
, G_TYPE_POINTER
);
256 g_object_get_property(G_OBJECT(cell
), "instance", &value
);
258 CustomCellRenderer
* cellsurface
= CUSTOM_CELL_RENDERER(cell
);
260 gpointer pWidget
= g_value_get_pointer(&value
);
264 SolarMutexGuard aGuard
;
266 custom_cell_renderer_ensure_device(cellsurface
, pWidget
);
268 Size
aSize(cell_area
->width
, cell_area
->height
);
269 // false to not bother setting the bg on resize as we'll do that
271 cellsurface
->device
->SetOutputSizePixel(aSize
, false);
273 cairo_surface_t
* pSurface
= get_underlying_cairo_surface(*cellsurface
->device
);
275 // fill surface as transparent so it can be blended with the potentially
276 // selected background
277 cairo_t
* tempcr
= cairo_create(pSurface
);
278 cairo_set_source_rgba(tempcr
, 0, 0, 0, 0);
279 cairo_set_operator(tempcr
, CAIRO_OPERATOR_SOURCE
);
281 cairo_destroy(tempcr
);
282 cairo_surface_flush(pSurface
);
284 custom_cell_renderer_render(*cellsurface
->device
, tools::Rectangle(Point(0, 0), aSize
),
285 static_cast<bool>(flags
& GTK_CELL_RENDERER_SELECTED
), sId
,
288 cairo_surface_mark_dirty(pSurface
);
290 cairo_set_source_surface(cr
, pSurface
, cell_area
->x
, cell_area
->y
);
294 #if GTK_CHECK_VERSION(4, 0, 0)
295 static void custom_cell_renderer_snapshot(GtkCellRenderer
* cell
, GtkSnapshot
* snapshot
,
296 GtkWidget
* widget
, const GdkRectangle
* background_area
,
297 const GdkRectangle
* cell_area
, GtkCellRendererState flags
)
299 graphene_rect_t rect
= GRAPHENE_RECT_INIT(
300 static_cast<float>(cell_area
->x
), static_cast<float>(cell_area
->y
),
301 static_cast<float>(cell_area
->width
), static_cast<float>(cell_area
->height
));
302 cairo_t
* cr
= gtk_snapshot_append_cairo(GTK_SNAPSHOT(snapshot
), &rect
);
303 custom_cell_renderer_render(cell
, cr
, widget
, background_area
, cell_area
, flags
);
309 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */