1/* gtkcellrenderer.c
2 * Copyright (C) 2000 Red Hat, Inc. Jonathan Blandford
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gtkcellrenderer.h"
21
22#include "gtkintl.h"
23#include "gtkmarshalers.h"
24#include "gtkprivate.h"
25#include "gtksnapshot.h"
26#include "gtkstylecontext.h"
27#include "gtktreeprivate.h"
28#include "gtktypebuiltins.h"
29
30/**
31 * GtkCellRenderer:
32 *
33 * An object for rendering a single cell
34 *
35 * The `GtkCellRenderer` is a base class of a set of objects used for
36 * rendering a cell to a `cairo_t`. These objects are used primarily by
37 * the `GtkTreeView` widget, though they aren’t tied to them in any
38 * specific way. It is worth noting that `GtkCellRenderer` is not a
39 * `GtkWidget` and cannot be treated as such.
40 *
41 * The primary use of a `GtkCellRenderer` is for drawing a certain graphical
42 * elements on a `cairo_t`. Typically, one cell renderer is used to
43 * draw many cells on the screen. To this extent, it isn’t expected that a
44 * CellRenderer keep any permanent state around. Instead, any state is set
45 * just prior to use using `GObject`s property system. Then, the
46 * cell is measured using gtk_cell_renderer_get_preferred_size(). Finally, the cell
47 * is rendered in the correct location using gtk_cell_renderer_snapshot().
48 *
49 * There are a number of rules that must be followed when writing a new
50 * `GtkCellRenderer`. First and foremost, it’s important that a certain set
51 * of properties will always yield a cell renderer of the same size,
52 * barring a style change. The `GtkCellRenderer` also has a number of
53 * generic properties that are expected to be honored by all children.
54 *
55 * Beyond merely rendering a cell, cell renderers can optionally
56 * provide active user interface elements. A cell renderer can be
57 * “activatable” like `GtkCellRenderer`Toggle,
58 * which toggles when it gets activated by a mouse click, or it can be
59 * “editable” like `GtkCellRenderer`Text, which
60 * allows the user to edit the text using a widget implementing the
61 * `GtkCellEditable` interface, e.g. `GtkEntry`.
62 * To make a cell renderer activatable or editable, you have to
63 * implement the `GtkCellRenderer`Class.activate or
64 * `GtkCellRenderer`Class.start_editing virtual functions, respectively.
65 *
66 * Many properties of `GtkCellRenderer` and its subclasses have a
67 * corresponding “set” property, e.g. “cell-background-set” corresponds
68 * to “cell-background”. These “set” properties reflect whether a property
69 * has been set or not. You should not set them independently.
70 */
71
72
73#define DEBUG_CELL_SIZE_REQUEST 0
74
75static void gtk_cell_renderer_init (GtkCellRenderer *cell);
76static void gtk_cell_renderer_class_init (GtkCellRendererClass *class);
77static void gtk_cell_renderer_get_property (GObject *object,
78 guint param_id,
79 GValue *value,
80 GParamSpec *pspec);
81static void gtk_cell_renderer_set_property (GObject *object,
82 guint param_id,
83 const GValue *value,
84 GParamSpec *pspec);
85static void set_cell_bg_color (GtkCellRenderer *cell,
86 GdkRGBA *rgba);
87
88static GtkSizeRequestMode gtk_cell_renderer_real_get_request_mode(GtkCellRenderer *cell);
89static void gtk_cell_renderer_real_get_preferred_width (GtkCellRenderer *cell,
90 GtkWidget *widget,
91 int *minimum_size,
92 int *natural_size);
93static void gtk_cell_renderer_real_get_preferred_height (GtkCellRenderer *cell,
94 GtkWidget *widget,
95 int *minimum_size,
96 int *natural_size);
97static void gtk_cell_renderer_real_get_preferred_height_for_width(GtkCellRenderer *cell,
98 GtkWidget *widget,
99 int width,
100 int *minimum_height,
101 int *natural_height);
102static void gtk_cell_renderer_real_get_preferred_width_for_height(GtkCellRenderer *cell,
103 GtkWidget *widget,
104 int height,
105 int *minimum_width,
106 int *natural_width);
107static void gtk_cell_renderer_real_get_aligned_area (GtkCellRenderer *cell,
108 GtkWidget *widget,
109 GtkCellRendererState flags,
110 const GdkRectangle *cell_area,
111 GdkRectangle *aligned_area);
112
113
114struct _GtkCellRendererPrivate
115{
116 float xalign;
117 float yalign;
118
119 int width;
120 int height;
121
122 guint16 xpad;
123 guint16 ypad;
124
125 guint mode : 2;
126 guint visible : 1;
127 guint is_expander : 1;
128 guint is_expanded : 1;
129 guint cell_background_set : 1;
130 guint sensitive : 1;
131 guint editing : 1;
132
133 GdkRGBA cell_background;
134};
135
136enum {
137 PROP_0,
138 PROP_MODE,
139 PROP_VISIBLE,
140 PROP_SENSITIVE,
141 PROP_XALIGN,
142 PROP_YALIGN,
143 PROP_XPAD,
144 PROP_YPAD,
145 PROP_WIDTH,
146 PROP_HEIGHT,
147 PROP_IS_EXPANDER,
148 PROP_IS_EXPANDED,
149 PROP_CELL_BACKGROUND,
150 PROP_CELL_BACKGROUND_RGBA,
151 PROP_CELL_BACKGROUND_SET,
152 PROP_EDITING
153};
154
155/* Signal IDs */
156enum {
157 EDITING_CANCELED,
158 EDITING_STARTED,
159 LAST_SIGNAL
160};
161
162static int GtkCellRenderer_private_offset;
163static guint cell_renderer_signals[LAST_SIGNAL] = { 0 };
164
165static inline gpointer
166gtk_cell_renderer_get_instance_private (GtkCellRenderer *self)
167{
168 return (G_STRUCT_MEMBER_P (self, GtkCellRenderer_private_offset));
169}
170
171static void
172gtk_cell_renderer_init (GtkCellRenderer *cell)
173{
174 GtkCellRendererPrivate *priv;
175
176 cell->priv = gtk_cell_renderer_get_instance_private (self: cell);
177 priv = cell->priv;
178
179 priv->mode = GTK_CELL_RENDERER_MODE_INERT;
180 priv->visible = TRUE;
181 priv->width = -1;
182 priv->height = -1;
183 priv->xalign = 0.5;
184 priv->yalign = 0.5;
185 priv->xpad = 0;
186 priv->ypad = 0;
187 priv->sensitive = TRUE;
188 priv->is_expander = FALSE;
189 priv->is_expanded = FALSE;
190 priv->editing = FALSE;
191}
192
193static void
194gtk_cell_renderer_class_init (GtkCellRendererClass *class)
195{
196 GObjectClass *object_class = G_OBJECT_CLASS (class);
197
198 object_class->get_property = gtk_cell_renderer_get_property;
199 object_class->set_property = gtk_cell_renderer_set_property;
200
201 class->snapshot = NULL;
202 class->get_request_mode = gtk_cell_renderer_real_get_request_mode;
203 class->get_preferred_width = gtk_cell_renderer_real_get_preferred_width;
204 class->get_preferred_height = gtk_cell_renderer_real_get_preferred_height;
205 class->get_preferred_width_for_height = gtk_cell_renderer_real_get_preferred_width_for_height;
206 class->get_preferred_height_for_width = gtk_cell_renderer_real_get_preferred_height_for_width;
207 class->get_aligned_area = gtk_cell_renderer_real_get_aligned_area;
208
209 /**
210 * GtkCellRenderer::editing-canceled:
211 * @renderer: the object which received the signal
212 *
213 * This signal gets emitted when the user cancels the process of editing a
214 * cell. For example, an editable cell renderer could be written to cancel
215 * editing when the user presses Escape.
216 *
217 * See also: gtk_cell_renderer_stop_editing().
218 */
219 cell_renderer_signals[EDITING_CANCELED] =
220 g_signal_new (I_("editing-canceled"),
221 G_OBJECT_CLASS_TYPE (object_class),
222 signal_flags: G_SIGNAL_RUN_FIRST,
223 G_STRUCT_OFFSET (GtkCellRendererClass, editing_canceled),
224 NULL, NULL,
225 NULL,
226 G_TYPE_NONE, n_params: 0);
227
228 /**
229 * GtkCellRenderer::editing-started:
230 * @renderer: the object which received the signal
231 * @editable: the `GtkCellEditable`
232 * @path: the path identifying the edited cell
233 *
234 * This signal gets emitted when a cell starts to be edited.
235 * The intended use of this signal is to do special setup
236 * on @editable, e.g. adding a `GtkEntryCompletion` or setting
237 * up additional columns in a `GtkComboBox`.
238 *
239 * See gtk_cell_editable_start_editing() for information on the lifecycle of
240 * the @editable and a way to do setup that doesn’t depend on the @renderer.
241 *
242 * Note that GTK doesn't guarantee that cell renderers will
243 * continue to use the same kind of widget for editing in future
244 * releases, therefore you should check the type of @editable
245 * before doing any specific setup, as in the following example:
246 * |[<!-- language="C" -->
247 * static void
248 * text_editing_started (GtkCellRenderer *cell,
249 * GtkCellEditable *editable,
250 * const char *path,
251 * gpointer data)
252 * {
253 * if (GTK_IS_ENTRY (editable))
254 * {
255 * GtkEntry *entry = GTK_ENTRY (editable);
256 *
257 * // ... create a GtkEntryCompletion
258 *
259 * gtk_entry_set_completion (entry, completion);
260 * }
261 * }
262 * ]|
263 */
264 cell_renderer_signals[EDITING_STARTED] =
265 g_signal_new (I_("editing-started"),
266 G_OBJECT_CLASS_TYPE (object_class),
267 signal_flags: G_SIGNAL_RUN_FIRST,
268 G_STRUCT_OFFSET (GtkCellRendererClass, editing_started),
269 NULL, NULL,
270 c_marshaller: _gtk_marshal_VOID__OBJECT_STRING,
271 G_TYPE_NONE, n_params: 2,
272 GTK_TYPE_CELL_EDITABLE,
273 G_TYPE_STRING);
274 g_signal_set_va_marshaller (cell_renderer_signals[EDITING_STARTED],
275 G_TYPE_FROM_CLASS (object_class),
276 _gtk_marshal_VOID__OBJECT_STRINGv);
277
278 g_object_class_install_property (object_class,
279 PROP_MODE,
280 g_param_spec_enum ("mode",
281 P_("mode"),
282 P_("Editable mode of the CellRenderer"),
283 GTK_TYPE_CELL_RENDERER_MODE,
284 GTK_CELL_RENDERER_MODE_INERT,
285 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
286
287 g_object_class_install_property (oclass: object_class,
288 property_id: PROP_VISIBLE,
289 pspec: g_param_spec_boolean (name: "visible",
290 P_("visible"),
291 P_("Display the cell"),
292 TRUE,
293 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
294 g_object_class_install_property (oclass: object_class,
295 property_id: PROP_SENSITIVE,
296 pspec: g_param_spec_boolean (name: "sensitive",
297 P_("Sensitive"),
298 P_("Display the cell sensitive"),
299 TRUE,
300 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
301
302 g_object_class_install_property (oclass: object_class,
303 property_id: PROP_XALIGN,
304 pspec: g_param_spec_float (name: "xalign",
305 P_("xalign"),
306 P_("The x-align"),
307 minimum: 0.0,
308 maximum: 1.0,
309 default_value: 0.5,
310 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
311
312 g_object_class_install_property (oclass: object_class,
313 property_id: PROP_YALIGN,
314 pspec: g_param_spec_float (name: "yalign",
315 P_("yalign"),
316 P_("The y-align"),
317 minimum: 0.0,
318 maximum: 1.0,
319 default_value: 0.5,
320 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
321
322 g_object_class_install_property (oclass: object_class,
323 property_id: PROP_XPAD,
324 pspec: g_param_spec_uint (name: "xpad",
325 P_("xpad"),
326 P_("The xpad"),
327 minimum: 0,
328 G_MAXUINT,
329 default_value: 0,
330 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
331
332 g_object_class_install_property (oclass: object_class,
333 property_id: PROP_YPAD,
334 pspec: g_param_spec_uint (name: "ypad",
335 P_("ypad"),
336 P_("The ypad"),
337 minimum: 0,
338 G_MAXUINT,
339 default_value: 0,
340 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
341
342 g_object_class_install_property (oclass: object_class,
343 property_id: PROP_WIDTH,
344 pspec: g_param_spec_int (name: "width",
345 P_("width"),
346 P_("The fixed width"),
347 minimum: -1,
348 G_MAXINT,
349 default_value: -1,
350 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
351
352 g_object_class_install_property (oclass: object_class,
353 property_id: PROP_HEIGHT,
354 pspec: g_param_spec_int (name: "height",
355 P_("height"),
356 P_("The fixed height"),
357 minimum: -1,
358 G_MAXINT,
359 default_value: -1,
360 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
361
362 g_object_class_install_property (oclass: object_class,
363 property_id: PROP_IS_EXPANDER,
364 pspec: g_param_spec_boolean (name: "is-expander",
365 P_("Is Expander"),
366 P_("Row has children"),
367 FALSE,
368 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
369
370
371 g_object_class_install_property (oclass: object_class,
372 property_id: PROP_IS_EXPANDED,
373 pspec: g_param_spec_boolean (name: "is-expanded",
374 P_("Is Expanded"),
375 P_("Row is an expander row, and is expanded"),
376 FALSE,
377 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
378
379 g_object_class_install_property (oclass: object_class,
380 property_id: PROP_CELL_BACKGROUND,
381 pspec: g_param_spec_string (name: "cell-background",
382 P_("Cell background color name"),
383 P_("Cell background color as a string"),
384 NULL,
385 GTK_PARAM_WRITABLE));
386
387 /**
388 * GtkCellRenderer:cell-background-rgba:
389 *
390 * Cell background as a `GdkRGBA`
391 */
392 g_object_class_install_property (oclass: object_class,
393 property_id: PROP_CELL_BACKGROUND_RGBA,
394 pspec: g_param_spec_boxed (name: "cell-background-rgba",
395 P_("Cell background RGBA color"),
396 P_("Cell background color as a GdkRGBA"),
397 GDK_TYPE_RGBA,
398 GTK_PARAM_READWRITE));
399
400 g_object_class_install_property (oclass: object_class,
401 property_id: PROP_EDITING,
402 pspec: g_param_spec_boolean (name: "editing",
403 P_("Editing"),
404 P_("Whether the cell renderer is currently in editing mode"),
405 FALSE,
406 GTK_PARAM_READABLE));
407
408
409#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY))
410
411 ADD_SET_PROP ("cell-background-set", PROP_CELL_BACKGROUND_SET,
412 P_("Cell background set"),
413 P_("Whether the cell background color is set"));
414
415 if (GtkCellRenderer_private_offset != 0)
416 g_type_class_adjust_private_offset (g_class: class, private_size_or_offset: &GtkCellRenderer_private_offset);
417}
418
419GType
420gtk_cell_renderer_get_type (void)
421{
422 static GType cell_renderer_type = 0;
423
424 if (G_UNLIKELY (cell_renderer_type == 0))
425 {
426 const GTypeInfo cell_renderer_info =
427 {
428 sizeof (GtkCellRendererClass),
429 NULL,
430 NULL,
431 (GClassInitFunc) gtk_cell_renderer_class_init,
432 NULL, /* class_finalize */
433 NULL, /* class_init */
434 sizeof (GtkWidget),
435 0, /* n_preallocs */
436 (GInstanceInitFunc) gtk_cell_renderer_init,
437 NULL, /* value_table */
438 };
439 cell_renderer_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, type_name: "GtkCellRenderer",
440 info: &cell_renderer_info, flags: G_TYPE_FLAG_ABSTRACT);
441
442 GtkCellRenderer_private_offset =
443 g_type_add_instance_private (class_type: cell_renderer_type, private_size: sizeof (GtkCellRendererPrivate));
444 }
445
446 return cell_renderer_type;
447}
448
449static void
450gtk_cell_renderer_get_property (GObject *object,
451 guint param_id,
452 GValue *value,
453 GParamSpec *pspec)
454{
455 GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
456 GtkCellRendererPrivate *priv = cell->priv;
457
458 switch (param_id)
459 {
460 case PROP_MODE:
461 g_value_set_enum (value, v_enum: priv->mode);
462 break;
463 case PROP_VISIBLE:
464 g_value_set_boolean (value, v_boolean: priv->visible);
465 break;
466 case PROP_SENSITIVE:
467 g_value_set_boolean (value, v_boolean: priv->sensitive);
468 break;
469 case PROP_EDITING:
470 g_value_set_boolean (value, v_boolean: priv->editing);
471 break;
472 case PROP_XALIGN:
473 g_value_set_float (value, v_float: priv->xalign);
474 break;
475 case PROP_YALIGN:
476 g_value_set_float (value, v_float: priv->yalign);
477 break;
478 case PROP_XPAD:
479 g_value_set_uint (value, v_uint: priv->xpad);
480 break;
481 case PROP_YPAD:
482 g_value_set_uint (value, v_uint: priv->ypad);
483 break;
484 case PROP_WIDTH:
485 g_value_set_int (value, v_int: priv->width);
486 break;
487 case PROP_HEIGHT:
488 g_value_set_int (value, v_int: priv->height);
489 break;
490 case PROP_IS_EXPANDER:
491 g_value_set_boolean (value, v_boolean: priv->is_expander);
492 break;
493 case PROP_IS_EXPANDED:
494 g_value_set_boolean (value, v_boolean: priv->is_expanded);
495 break;
496 case PROP_CELL_BACKGROUND_RGBA:
497 g_value_set_boxed (value, v_boxed: &priv->cell_background);
498 break;
499 case PROP_CELL_BACKGROUND_SET:
500 g_value_set_boolean (value, v_boolean: priv->cell_background_set);
501 break;
502 case PROP_CELL_BACKGROUND:
503 default:
504 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
505 break;
506 }
507
508}
509
510static void
511gtk_cell_renderer_set_property (GObject *object,
512 guint param_id,
513 const GValue *value,
514 GParamSpec *pspec)
515{
516 GtkCellRenderer *cell = GTK_CELL_RENDERER (object);
517 GtkCellRendererPrivate *priv = cell->priv;
518
519 switch (param_id)
520 {
521 case PROP_MODE:
522 if (priv->mode != g_value_get_enum (value))
523 {
524 priv->mode = g_value_get_enum (value);
525 g_object_notify_by_pspec (object, pspec);
526 }
527 break;
528 case PROP_VISIBLE:
529 if (priv->visible != g_value_get_boolean (value))
530 {
531 priv->visible = g_value_get_boolean (value);
532 g_object_notify_by_pspec (object, pspec);
533 }
534 break;
535 case PROP_SENSITIVE:
536 if (priv->sensitive != g_value_get_boolean (value))
537 {
538 priv->sensitive = g_value_get_boolean (value);
539 g_object_notify_by_pspec (object, pspec);
540 }
541 break;
542 case PROP_XALIGN:
543 if (priv->xalign != g_value_get_float (value))
544 {
545 priv->xalign = g_value_get_float (value);
546 g_object_notify_by_pspec (object, pspec);
547 }
548 break;
549 case PROP_YALIGN:
550 if (priv->yalign != g_value_get_float (value))
551 {
552 priv->yalign = g_value_get_float (value);
553 g_object_notify_by_pspec (object, pspec);
554 }
555 break;
556 case PROP_XPAD:
557 if (priv->xpad != g_value_get_uint (value))
558 {
559 priv->xpad = g_value_get_uint (value);
560 g_object_notify_by_pspec (object, pspec);
561 }
562 break;
563 case PROP_YPAD:
564 if (priv->ypad != g_value_get_uint (value))
565 {
566 priv->ypad = g_value_get_uint (value);
567 g_object_notify_by_pspec (object, pspec);
568 }
569 break;
570 case PROP_WIDTH:
571 if (priv->width != g_value_get_int (value))
572 {
573 priv->width = g_value_get_int (value);
574 g_object_notify_by_pspec (object, pspec);
575 }
576 break;
577 case PROP_HEIGHT:
578 if (priv->height != g_value_get_int (value))
579 {
580 priv->height = g_value_get_int (value);
581 g_object_notify_by_pspec (object, pspec);
582 }
583 break;
584 case PROP_IS_EXPANDER:
585 if (priv->is_expander != g_value_get_boolean (value))
586 {
587 priv->is_expander = g_value_get_boolean (value);
588 g_object_notify_by_pspec (object, pspec);
589 }
590 break;
591 case PROP_IS_EXPANDED:
592 if (priv->is_expanded != g_value_get_boolean (value))
593 {
594 priv->is_expanded = g_value_get_boolean (value);
595 g_object_notify_by_pspec (object, pspec);
596 }
597 break;
598 case PROP_CELL_BACKGROUND:
599 {
600 GdkRGBA rgba;
601
602 if (!g_value_get_string (value))
603 set_cell_bg_color (cell, NULL);
604 else if (gdk_rgba_parse (rgba: &rgba, spec: g_value_get_string (value)))
605 set_cell_bg_color (cell, rgba: &rgba);
606 else
607 g_warning ("Don't know color '%s'", g_value_get_string (value));
608
609 g_object_notify (object, property_name: "cell-background");
610 }
611 break;
612 case PROP_CELL_BACKGROUND_RGBA:
613 set_cell_bg_color (cell, rgba: g_value_get_boxed (value));
614 break;
615 case PROP_CELL_BACKGROUND_SET:
616 if (priv->cell_background_set != g_value_get_boolean (value))
617 {
618 priv->cell_background_set = g_value_get_boolean (value);
619 g_object_notify (object, property_name: "cell-background-set");
620 }
621 break;
622 default:
623 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
624 break;
625 }
626}
627
628static void
629set_cell_bg_color (GtkCellRenderer *cell,
630 GdkRGBA *rgba)
631{
632 GtkCellRendererPrivate *priv = cell->priv;
633
634 if (rgba)
635 {
636 if (!priv->cell_background_set)
637 {
638 priv->cell_background_set = TRUE;
639 g_object_notify (G_OBJECT (cell), property_name: "cell-background-set");
640 }
641
642 priv->cell_background = *rgba;
643 }
644 else
645 {
646 if (priv->cell_background_set)
647 {
648 priv->cell_background_set = FALSE;
649 g_object_notify (G_OBJECT (cell), property_name: "cell-background-set");
650 }
651 }
652 g_object_notify (G_OBJECT (cell), property_name: "cell-background-rgba");
653}
654
655/**
656 * gtk_cell_renderer_snapshot:
657 * @cell: a `GtkCellRenderer`
658 * @snapshot: a `GtkSnapshot` to draw to
659 * @widget: the widget owning @window
660 * @background_area: entire cell area (including tree expanders and maybe
661 * padding on the sides)
662 * @cell_area: area normally rendered by a cell renderer
663 * @flags: flags that affect rendering
664 *
665 * Invokes the virtual render function of the `GtkCellRenderer`. The three
666 * passed-in rectangles are areas in @cr. Most renderers will draw within
667 * @cell_area; the xalign, yalign, xpad, and ypad fields of the `GtkCellRenderer`
668 * should be honored with respect to @cell_area. @background_area includes the
669 * blank space around the cell, and also the area containing the tree expander;
670 * so the @background_area rectangles for all cells tile to cover the entire
671 * @window.
672 **/
673void
674gtk_cell_renderer_snapshot (GtkCellRenderer *cell,
675 GtkSnapshot *snapshot,
676 GtkWidget *widget,
677 const GdkRectangle *background_area,
678 const GdkRectangle *cell_area,
679 GtkCellRendererState flags)
680{
681 gboolean selected = FALSE;
682 GtkCellRendererPrivate *priv = cell->priv;
683 GtkStyleContext *context;
684 GtkStateFlags state;
685
686 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
687 g_return_if_fail (GTK_CELL_RENDERER_GET_CLASS (cell)->snapshot != NULL);
688 g_return_if_fail (snapshot != NULL);
689
690 selected = (flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED;
691
692 gtk_snapshot_push_debug (snapshot, message: "%s", G_OBJECT_TYPE_NAME (cell));
693
694 if (priv->cell_background_set && !selected)
695 {
696 gtk_snapshot_append_color (snapshot,
697 color: &priv->cell_background,
698 bounds: &GRAPHENE_RECT_INIT (
699 background_area->x, background_area->y,
700 background_area->width, background_area->height
701 ));
702 }
703
704 gtk_snapshot_push_clip (snapshot,
705 bounds: &GRAPHENE_RECT_INIT (
706 background_area->x, background_area->y,
707 background_area->width, background_area->height
708 ));
709
710 context = gtk_widget_get_style_context (widget);
711
712 gtk_style_context_save (context);
713 gtk_style_context_add_class (context, class_name: "cell");
714
715 state = gtk_cell_renderer_get_state (cell, widget, cell_state: flags);
716 gtk_style_context_set_state (context, flags: state);
717
718 GTK_CELL_RENDERER_GET_CLASS (cell)->snapshot (cell,
719 snapshot,
720 widget,
721 background_area,
722 cell_area,
723 flags);
724 gtk_style_context_restore (context);
725 gtk_snapshot_pop (snapshot);
726 gtk_snapshot_pop (snapshot);
727}
728
729/**
730 * gtk_cell_renderer_activate:
731 * @cell: a `GtkCellRenderer`
732 * @event: a `GdkEvent`
733 * @widget: widget that received the event
734 * @path: widget-dependent string representation of the event location;
735 * e.g. for `GtkTreeView`, a string representation of `GtkTreePath`
736 * @background_area: background area as passed to gtk_cell_renderer_render()
737 * @cell_area: cell area as passed to gtk_cell_renderer_render()
738 * @flags: render flags
739 *
740 * Passes an activate event to the cell renderer for possible processing.
741 * Some cell renderers may use events; for example, `GtkCellRendererToggle`
742 * toggles when it gets a mouse click.
743 *
744 * Returns: %TRUE if the event was consumed/handled
745 **/
746gboolean
747gtk_cell_renderer_activate (GtkCellRenderer *cell,
748 GdkEvent *event,
749 GtkWidget *widget,
750 const char *path,
751 const GdkRectangle *background_area,
752 const GdkRectangle *cell_area,
753 GtkCellRendererState flags)
754{
755 GtkCellRendererPrivate *priv;
756
757 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
758
759 priv = cell->priv;
760
761 if (priv->mode != GTK_CELL_RENDERER_MODE_ACTIVATABLE)
762 return FALSE;
763
764 if (GTK_CELL_RENDERER_GET_CLASS (cell)->activate == NULL)
765 return FALSE;
766
767 return GTK_CELL_RENDERER_GET_CLASS (cell)->activate (cell,
768 event,
769 widget,
770 path,
771 (GdkRectangle *) background_area,
772 (GdkRectangle *) cell_area,
773 flags);
774}
775
776/**
777 * gtk_cell_renderer_start_editing:
778 * @cell: a `GtkCellRenderer`
779 * @event: (nullable): a `GdkEvent`
780 * @widget: widget that received the event
781 * @path: widget-dependent string representation of the event location;
782 * e.g. for `GtkTreeView`, a string representation of `GtkTreePath`
783 * @background_area: background area as passed to gtk_cell_renderer_render()
784 * @cell_area: cell area as passed to gtk_cell_renderer_render()
785 * @flags: render flags
786 *
787 * Starts editing the contents of this @cell, through a new `GtkCellEditable`
788 * widget created by the `GtkCellRenderer`Class.start_editing virtual function.
789 *
790 * Returns: (nullable) (transfer none): A new `GtkCellEditable` for editing this
791 * @cell, or %NULL if editing is not possible
792 **/
793GtkCellEditable *
794gtk_cell_renderer_start_editing (GtkCellRenderer *cell,
795 GdkEvent *event,
796 GtkWidget *widget,
797 const char *path,
798 const GdkRectangle *background_area,
799 const GdkRectangle *cell_area,
800 GtkCellRendererState flags)
801
802{
803 GtkCellRendererPrivate *priv;
804 GtkCellEditable *editable;
805
806 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), NULL);
807
808 priv = cell->priv;
809
810 if (priv->mode != GTK_CELL_RENDERER_MODE_EDITABLE)
811 return NULL;
812
813 if (GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing == NULL)
814 return NULL;
815
816 editable = GTK_CELL_RENDERER_GET_CLASS (cell)->start_editing (cell,
817 event,
818 widget,
819 path,
820 (GdkRectangle *) background_area,
821 (GdkRectangle *) cell_area,
822 flags);
823 if (editable == NULL)
824 return NULL;
825
826 gtk_widget_add_css_class (GTK_WIDGET (editable), css_class: "cell");
827
828 g_signal_emit (instance: cell,
829 signal_id: cell_renderer_signals[EDITING_STARTED], detail: 0,
830 editable, path);
831
832 priv->editing = TRUE;
833
834 return editable;
835}
836
837/**
838 * gtk_cell_renderer_set_fixed_size:
839 * @cell: A `GtkCellRenderer`
840 * @width: the width of the cell renderer, or -1
841 * @height: the height of the cell renderer, or -1
842 *
843 * Sets the renderer size to be explicit, independent of the properties set.
844 **/
845void
846gtk_cell_renderer_set_fixed_size (GtkCellRenderer *cell,
847 int width,
848 int height)
849{
850 GtkCellRendererPrivate *priv;
851
852 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
853 g_return_if_fail (width >= -1 && height >= -1);
854
855 priv = cell->priv;
856
857 if ((width != priv->width) || (height != priv->height))
858 {
859 g_object_freeze_notify (G_OBJECT (cell));
860
861 if (width != priv->width)
862 {
863 priv->width = width;
864 g_object_notify (G_OBJECT (cell), property_name: "width");
865 }
866
867 if (height != priv->height)
868 {
869 priv->height = height;
870 g_object_notify (G_OBJECT (cell), property_name: "height");
871 }
872
873 g_object_thaw_notify (G_OBJECT (cell));
874 }
875}
876
877/**
878 * gtk_cell_renderer_get_fixed_size:
879 * @cell: A `GtkCellRenderer`
880 * @width: (out) (optional): location to fill in with the fixed width of the cell
881 * @height: (out) (optional): location to fill in with the fixed height of the cell
882 *
883 * Fills in @width and @height with the appropriate size of @cell.
884 */
885void
886gtk_cell_renderer_get_fixed_size (GtkCellRenderer *cell,
887 int *width,
888 int *height)
889{
890 GtkCellRendererPrivate *priv;
891
892 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
893
894 priv = cell->priv;
895
896 if (width)
897 *width = priv->width;
898 if (height)
899 *height = priv->height;
900}
901
902/**
903 * gtk_cell_renderer_set_alignment:
904 * @cell: A `GtkCellRenderer`
905 * @xalign: the x alignment of the cell renderer
906 * @yalign: the y alignment of the cell renderer
907 *
908 * Sets the renderer’s alignment within its available space.
909 **/
910void
911gtk_cell_renderer_set_alignment (GtkCellRenderer *cell,
912 float xalign,
913 float yalign)
914{
915 GtkCellRendererPrivate *priv;
916
917 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
918 g_return_if_fail (xalign >= 0.0 && xalign <= 1.0);
919 g_return_if_fail (yalign >= 0.0 && yalign <= 1.0);
920
921 priv = cell->priv;
922
923 if ((xalign != priv->xalign) || (yalign != priv->yalign))
924 {
925 g_object_freeze_notify (G_OBJECT (cell));
926
927 if (xalign != priv->xalign)
928 {
929 priv->xalign = xalign;
930 g_object_notify (G_OBJECT (cell), property_name: "xalign");
931 }
932
933 if (yalign != priv->yalign)
934 {
935 priv->yalign = yalign;
936 g_object_notify (G_OBJECT (cell), property_name: "yalign");
937 }
938
939 g_object_thaw_notify (G_OBJECT (cell));
940 }
941}
942
943/**
944 * gtk_cell_renderer_get_alignment:
945 * @cell: A `GtkCellRenderer`
946 * @xalign: (out) (optional): location to fill in with the x alignment of the cell
947 * @yalign: (out) (optional): location to fill in with the y alignment of the cell
948 *
949 * Fills in @xalign and @yalign with the appropriate values of @cell.
950 */
951void
952gtk_cell_renderer_get_alignment (GtkCellRenderer *cell,
953 float *xalign,
954 float *yalign)
955{
956 GtkCellRendererPrivate *priv;
957
958 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
959
960 priv = cell->priv;
961
962 if (xalign)
963 *xalign = priv->xalign;
964 if (yalign)
965 *yalign = priv->yalign;
966}
967
968/**
969 * gtk_cell_renderer_set_padding:
970 * @cell: A `GtkCellRenderer`
971 * @xpad: the x padding of the cell renderer
972 * @ypad: the y padding of the cell renderer
973 *
974 * Sets the renderer’s padding.
975 **/
976void
977gtk_cell_renderer_set_padding (GtkCellRenderer *cell,
978 int xpad,
979 int ypad)
980{
981 GtkCellRendererPrivate *priv;
982
983 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
984 g_return_if_fail (xpad >= 0 && ypad >= 0);
985
986 priv = cell->priv;
987
988 if ((xpad != priv->xpad) || (ypad != priv->ypad))
989 {
990 g_object_freeze_notify (G_OBJECT (cell));
991
992 if (xpad != priv->xpad)
993 {
994 priv->xpad = xpad;
995 g_object_notify (G_OBJECT (cell), property_name: "xpad");
996 }
997
998 if (ypad != priv->ypad)
999 {
1000 priv->ypad = ypad;
1001 g_object_notify (G_OBJECT (cell), property_name: "ypad");
1002 }
1003
1004 g_object_thaw_notify (G_OBJECT (cell));
1005 }
1006}
1007
1008/**
1009 * gtk_cell_renderer_get_padding:
1010 * @cell: A `GtkCellRenderer`
1011 * @xpad: (out) (optional): location to fill in with the x padding of the cell
1012 * @ypad: (out) (optional): location to fill in with the y padding of the cell
1013 *
1014 * Fills in @xpad and @ypad with the appropriate values of @cell.
1015 */
1016void
1017gtk_cell_renderer_get_padding (GtkCellRenderer *cell,
1018 int *xpad,
1019 int *ypad)
1020{
1021 GtkCellRendererPrivate *priv;
1022
1023 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1024
1025 priv = cell->priv;
1026
1027 if (xpad)
1028 *xpad = priv->xpad;
1029 if (ypad)
1030 *ypad = priv->ypad;
1031}
1032
1033/**
1034 * gtk_cell_renderer_set_visible:
1035 * @cell: A `GtkCellRenderer`
1036 * @visible: the visibility of the cell
1037 *
1038 * Sets the cell renderer’s visibility.
1039 **/
1040void
1041gtk_cell_renderer_set_visible (GtkCellRenderer *cell,
1042 gboolean visible)
1043{
1044 GtkCellRendererPrivate *priv;
1045
1046 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1047
1048 priv = cell->priv;
1049
1050 if (priv->visible != visible)
1051 {
1052 priv->visible = visible ? TRUE : FALSE;
1053 g_object_notify (G_OBJECT (cell), property_name: "visible");
1054 }
1055}
1056
1057/**
1058 * gtk_cell_renderer_get_visible:
1059 * @cell: A `GtkCellRenderer`
1060 *
1061 * Returns the cell renderer’s visibility.
1062 *
1063 * Returns: %TRUE if the cell renderer is visible
1064 */
1065gboolean
1066gtk_cell_renderer_get_visible (GtkCellRenderer *cell)
1067{
1068 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1069
1070 return cell->priv->visible;
1071}
1072
1073/**
1074 * gtk_cell_renderer_set_sensitive:
1075 * @cell: A `GtkCellRenderer`
1076 * @sensitive: the sensitivity of the cell
1077 *
1078 * Sets the cell renderer’s sensitivity.
1079 **/
1080void
1081gtk_cell_renderer_set_sensitive (GtkCellRenderer *cell,
1082 gboolean sensitive)
1083{
1084 GtkCellRendererPrivate *priv;
1085
1086 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1087
1088 priv = cell->priv;
1089
1090 if (priv->sensitive != sensitive)
1091 {
1092 priv->sensitive = sensitive ? TRUE : FALSE;
1093 g_object_notify (G_OBJECT (cell), property_name: "sensitive");
1094 }
1095}
1096
1097/**
1098 * gtk_cell_renderer_get_sensitive:
1099 * @cell: A `GtkCellRenderer`
1100 *
1101 * Returns the cell renderer’s sensitivity.
1102 *
1103 * Returns: %TRUE if the cell renderer is sensitive
1104 */
1105gboolean
1106gtk_cell_renderer_get_sensitive (GtkCellRenderer *cell)
1107{
1108 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1109
1110 return cell->priv->sensitive;
1111}
1112
1113
1114/**
1115 * gtk_cell_renderer_is_activatable:
1116 * @cell: A `GtkCellRenderer`
1117 *
1118 * Checks whether the cell renderer can do something when activated.
1119 *
1120 * Returns: %TRUE if the cell renderer can do anything when activated
1121 */
1122gboolean
1123gtk_cell_renderer_is_activatable (GtkCellRenderer *cell)
1124{
1125 GtkCellRendererPrivate *priv;
1126
1127 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1128
1129 priv = cell->priv;
1130
1131 return (priv->visible &&
1132 (priv->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1133 priv->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE));
1134}
1135
1136
1137/**
1138 * gtk_cell_renderer_stop_editing:
1139 * @cell: A `GtkCellRenderer`
1140 * @canceled: %TRUE if the editing has been canceled
1141 *
1142 * Informs the cell renderer that the editing is stopped.
1143 * If @canceled is %TRUE, the cell renderer will emit the
1144 * `GtkCellRenderer`::editing-canceled signal.
1145 *
1146 * This function should be called by cell renderer implementations
1147 * in response to the `GtkCellEditable::editing-done` signal of
1148 * `GtkCellEditable`.
1149 **/
1150void
1151gtk_cell_renderer_stop_editing (GtkCellRenderer *cell,
1152 gboolean canceled)
1153{
1154 GtkCellRendererPrivate *priv;
1155
1156 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1157
1158 priv = cell->priv;
1159
1160 if (priv->editing)
1161 {
1162 priv->editing = FALSE;
1163 if (canceled)
1164 g_signal_emit (instance: cell, signal_id: cell_renderer_signals[EDITING_CANCELED], detail: 0);
1165 }
1166}
1167
1168static void
1169gtk_cell_renderer_real_get_preferred_size (GtkCellRenderer *cell,
1170 GtkWidget *widget,
1171 GtkOrientation orientation,
1172 int *minimum_size,
1173 int *natural_size)
1174{
1175 GtkRequisition min_req;
1176
1177 min_req.width = 0;
1178 min_req.height = 0;
1179
1180 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1181 {
1182 if (minimum_size)
1183 *minimum_size = min_req.width;
1184
1185 if (natural_size)
1186 *natural_size = min_req.width;
1187 }
1188 else
1189 {
1190 if (minimum_size)
1191 *minimum_size = min_req.height;
1192
1193 if (natural_size)
1194 *natural_size = min_req.height;
1195 }
1196}
1197
1198static GtkSizeRequestMode
1199gtk_cell_renderer_real_get_request_mode (GtkCellRenderer *cell)
1200{
1201 /* By default cell renderers are height-for-width. */
1202 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1203}
1204
1205static void
1206gtk_cell_renderer_real_get_preferred_width (GtkCellRenderer *cell,
1207 GtkWidget *widget,
1208 int *minimum_size,
1209 int *natural_size)
1210{
1211 gtk_cell_renderer_real_get_preferred_size (cell, widget, orientation: GTK_ORIENTATION_HORIZONTAL,
1212 minimum_size, natural_size);
1213}
1214
1215static void
1216gtk_cell_renderer_real_get_preferred_height (GtkCellRenderer *cell,
1217 GtkWidget *widget,
1218 int *minimum_size,
1219 int *natural_size)
1220{
1221 gtk_cell_renderer_real_get_preferred_size (cell, widget, orientation: GTK_ORIENTATION_VERTICAL,
1222 minimum_size, natural_size);
1223}
1224
1225
1226static void
1227gtk_cell_renderer_real_get_preferred_height_for_width (GtkCellRenderer *cell,
1228 GtkWidget *widget,
1229 int width,
1230 int *minimum_height,
1231 int *natural_height)
1232{
1233 gtk_cell_renderer_get_preferred_height (cell, widget, minimum_size: minimum_height, natural_size: natural_height);
1234}
1235
1236static void
1237gtk_cell_renderer_real_get_preferred_width_for_height (GtkCellRenderer *cell,
1238 GtkWidget *widget,
1239 int height,
1240 int *minimum_width,
1241 int *natural_width)
1242{
1243 gtk_cell_renderer_get_preferred_width (cell, widget, minimum_size: minimum_width, natural_size: natural_width);
1244}
1245
1246
1247/* Default implementation assumes that a cell renderer will never use more
1248 * space than its natural size (this is fine for toggles and pixbufs etc
1249 * but needs to be overridden from wrapping/ellipsizing text renderers) */
1250static void
1251gtk_cell_renderer_real_get_aligned_area (GtkCellRenderer *cell,
1252 GtkWidget *widget,
1253 GtkCellRendererState flags,
1254 const GdkRectangle *cell_area,
1255 GdkRectangle *aligned_area)
1256{
1257 int opposite_size, x_offset, y_offset;
1258 int natural_size;
1259
1260 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1261 g_return_if_fail (GTK_IS_WIDGET (widget));
1262 g_return_if_fail (cell_area != NULL);
1263 g_return_if_fail (aligned_area != NULL);
1264
1265 *aligned_area = *cell_area;
1266
1267 /* Trim up the aligned size */
1268 if (gtk_cell_renderer_get_request_mode (cell) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
1269 {
1270 gtk_cell_renderer_get_preferred_width (cell, widget,
1271 NULL, natural_size: &natural_size);
1272
1273 aligned_area->width = MIN (aligned_area->width, natural_size);
1274
1275 gtk_cell_renderer_get_preferred_height_for_width (cell, widget,
1276 width: aligned_area->width,
1277 NULL, natural_height: &opposite_size);
1278
1279 aligned_area->height = MIN (opposite_size, aligned_area->height);
1280 }
1281 else
1282 {
1283 gtk_cell_renderer_get_preferred_height (cell, widget,
1284 NULL, natural_size: &natural_size);
1285
1286 aligned_area->height = MIN (aligned_area->width, natural_size);
1287
1288 gtk_cell_renderer_get_preferred_width_for_height (cell, widget,
1289 height: aligned_area->height,
1290 NULL, natural_width: &opposite_size);
1291
1292 aligned_area->width = MIN (opposite_size, aligned_area->width);
1293 }
1294
1295 /* offset the cell position */
1296 _gtk_cell_renderer_calc_offset (cell, cell_area,
1297 direction: gtk_widget_get_direction (widget),
1298 width: aligned_area->width,
1299 height: aligned_area->height,
1300 x_offset: &x_offset, y_offset: &y_offset);
1301
1302 aligned_area->x += x_offset;
1303 aligned_area->y += y_offset;
1304}
1305
1306
1307/* An internal convenience function for some containers to peek at the
1308 * cell alignment in a target allocation (used to draw focus and align
1309 * cells in the icon view).
1310 *
1311 * Note this is only a trivial “align * (allocation - request)” operation.
1312 */
1313void
1314_gtk_cell_renderer_calc_offset (GtkCellRenderer *cell,
1315 const GdkRectangle *cell_area,
1316 GtkTextDirection direction,
1317 int width,
1318 int height,
1319 int *x_offset,
1320 int *y_offset)
1321{
1322 GtkCellRendererPrivate *priv;
1323
1324 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1325 g_return_if_fail (cell_area != NULL);
1326 g_return_if_fail (x_offset || y_offset);
1327
1328 priv = cell->priv;
1329
1330 if (x_offset)
1331 {
1332 *x_offset = (((direction == GTK_TEXT_DIR_RTL) ?
1333 (1.0 - priv->xalign) : priv->xalign) *
1334 (cell_area->width - width));
1335 *x_offset = MAX (*x_offset, 0);
1336 }
1337 if (y_offset)
1338 {
1339 *y_offset = (priv->yalign *
1340 (cell_area->height - height));
1341 *y_offset = MAX (*y_offset, 0);
1342 }
1343}
1344
1345/**
1346 * gtk_cell_renderer_get_request_mode:
1347 * @cell: a `GtkCellRenderer` instance
1348 *
1349 * Gets whether the cell renderer prefers a height-for-width layout
1350 * or a width-for-height layout.
1351 *
1352 * Returns: The `GtkSizeRequestMode` preferred by this renderer.
1353 */
1354GtkSizeRequestMode
1355gtk_cell_renderer_get_request_mode (GtkCellRenderer *cell)
1356{
1357 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1358
1359 return GTK_CELL_RENDERER_GET_CLASS (cell)->get_request_mode (cell);
1360}
1361
1362/**
1363 * gtk_cell_renderer_get_preferred_width:
1364 * @cell: a `GtkCellRenderer` instance
1365 * @widget: the `GtkWidget` this cell will be rendering to
1366 * @minimum_size: (out) (optional): location to store the minimum size
1367 * @natural_size: (out) (optional): location to store the natural size
1368 *
1369 * Retrieves a renderer’s natural size when rendered to @widget.
1370 */
1371void
1372gtk_cell_renderer_get_preferred_width (GtkCellRenderer *cell,
1373 GtkWidget *widget,
1374 int *minimum_size,
1375 int *natural_size)
1376{
1377 GtkCellRendererClass *klass;
1378 int width;
1379
1380 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1381 g_return_if_fail (GTK_IS_WIDGET (widget));
1382 g_return_if_fail (NULL != minimum_size || NULL != natural_size);
1383
1384 gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), width: &width, NULL);
1385
1386 if (width < 0)
1387 {
1388 klass = GTK_CELL_RENDERER_GET_CLASS (cell);
1389 klass->get_preferred_width (cell, widget, minimum_size, natural_size);
1390 }
1391 else
1392 {
1393 if (minimum_size)
1394 *minimum_size = width;
1395 if (natural_size)
1396 *natural_size = width;
1397 }
1398
1399#if DEBUG_CELL_SIZE_REQUEST
1400 g_message ("%s returning minimum width: %d and natural width: %d",
1401 G_OBJECT_TYPE_NAME (cell),
1402 minimum_size ? *minimum_size : 20000,
1403 natural_size ? *natural_size : 20000);
1404#endif
1405}
1406
1407
1408/**
1409 * gtk_cell_renderer_get_preferred_height:
1410 * @cell: a `GtkCellRenderer` instance
1411 * @widget: the `GtkWidget` this cell will be rendering to
1412 * @minimum_size: (out) (optional): location to store the minimum size
1413 * @natural_size: (out) (optional): location to store the natural size
1414 *
1415 * Retrieves a renderer’s natural size when rendered to @widget.
1416 */
1417void
1418gtk_cell_renderer_get_preferred_height (GtkCellRenderer *cell,
1419 GtkWidget *widget,
1420 int *minimum_size,
1421 int *natural_size)
1422{
1423 GtkCellRendererClass *klass;
1424 int height;
1425
1426 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1427 g_return_if_fail (GTK_IS_WIDGET (widget));
1428 g_return_if_fail (NULL != minimum_size || NULL != natural_size);
1429
1430 gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), NULL, height: &height);
1431
1432 if (height < 0)
1433 {
1434 klass = GTK_CELL_RENDERER_GET_CLASS (cell);
1435 klass->get_preferred_height (cell, widget, minimum_size, natural_size);
1436 }
1437 else
1438 {
1439 if (minimum_size)
1440 *minimum_size = height;
1441 if (natural_size)
1442 *natural_size = height;
1443 }
1444
1445#if DEBUG_CELL_SIZE_REQUEST
1446 g_message ("%s returning minimum height: %d and natural height: %d",
1447 G_OBJECT_TYPE_NAME (cell),
1448 minimum_size ? *minimum_size : 20000,
1449 natural_size ? *natural_size : 20000);
1450#endif
1451}
1452
1453
1454/**
1455 * gtk_cell_renderer_get_preferred_width_for_height:
1456 * @cell: a `GtkCellRenderer` instance
1457 * @widget: the `GtkWidget` this cell will be rendering to
1458 * @height: the size which is available for allocation
1459 * @minimum_width: (out) (optional): location for storing the minimum size
1460 * @natural_width: (out) (optional): location for storing the preferred size
1461 *
1462 * Retrieves a cell renderers’s minimum and natural width if it were rendered to
1463 * @widget with the specified @height.
1464 */
1465void
1466gtk_cell_renderer_get_preferred_width_for_height (GtkCellRenderer *cell,
1467 GtkWidget *widget,
1468 int height,
1469 int *minimum_width,
1470 int *natural_width)
1471{
1472 GtkCellRendererClass *klass;
1473 int width;
1474
1475 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1476 g_return_if_fail (GTK_IS_WIDGET (widget));
1477 g_return_if_fail (NULL != minimum_width || NULL != natural_width);
1478
1479 gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), width: &width, NULL);
1480
1481 if (width < 0)
1482 {
1483 klass = GTK_CELL_RENDERER_GET_CLASS (cell);
1484 klass->get_preferred_width_for_height (cell, widget, height, minimum_width, natural_width);
1485 }
1486 else
1487 {
1488 if (minimum_width)
1489 *minimum_width = width;
1490 if (natural_width)
1491 *natural_width = width;
1492 }
1493
1494#if DEBUG_CELL_SIZE_REQUEST
1495 g_message ("%s width for height: %d is minimum %d and natural: %d",
1496 G_OBJECT_TYPE_NAME (cell), height,
1497 minimum_width ? *minimum_width : 20000,
1498 natural_width ? *natural_width : 20000);
1499#endif
1500}
1501
1502/**
1503 * gtk_cell_renderer_get_preferred_height_for_width:
1504 * @cell: a `GtkCellRenderer` instance
1505 * @widget: the `GtkWidget` this cell will be rendering to
1506 * @width: the size which is available for allocation
1507 * @minimum_height: (out) (optional): location for storing the minimum size
1508 * @natural_height: (out) (optional): location for storing the preferred size
1509 *
1510 * Retrieves a cell renderers’s minimum and natural height if it were rendered to
1511 * @widget with the specified @width.
1512 */
1513void
1514gtk_cell_renderer_get_preferred_height_for_width (GtkCellRenderer *cell,
1515 GtkWidget *widget,
1516 int width,
1517 int *minimum_height,
1518 int *natural_height)
1519{
1520 GtkCellRendererClass *klass;
1521 int height;
1522
1523 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1524 g_return_if_fail (GTK_IS_WIDGET (widget));
1525 g_return_if_fail (NULL != minimum_height || NULL != natural_height);
1526
1527 gtk_cell_renderer_get_fixed_size (GTK_CELL_RENDERER (cell), NULL, height: &height);
1528
1529 if (height < 0)
1530 {
1531 klass = GTK_CELL_RENDERER_GET_CLASS (cell);
1532 klass->get_preferred_height_for_width (cell, widget, width, minimum_height, natural_height);
1533 }
1534 else
1535 {
1536 if (minimum_height)
1537 *minimum_height = height;
1538 if (natural_height)
1539 *natural_height = height;
1540 }
1541
1542#if DEBUG_CELL_SIZE_REQUEST
1543 g_message ("%s height for width: %d is minimum %d and natural: %d",
1544 G_OBJECT_TYPE_NAME (cell), width,
1545 minimum_height ? *minimum_height : 20000,
1546 natural_height ? *natural_height : 20000);
1547#endif
1548}
1549
1550/**
1551 * gtk_cell_renderer_get_preferred_size:
1552 * @cell: a `GtkCellRenderer` instance
1553 * @widget: the `GtkWidget` this cell will be rendering to
1554 * @minimum_size: (out) (optional): location for storing the minimum size
1555 * @natural_size: (out) (optional): location for storing the natural size
1556 *
1557 * Retrieves the minimum and natural size of a cell taking
1558 * into account the widget’s preference for height-for-width management.
1559 */
1560void
1561gtk_cell_renderer_get_preferred_size (GtkCellRenderer *cell,
1562 GtkWidget *widget,
1563 GtkRequisition *minimum_size,
1564 GtkRequisition *natural_size)
1565{
1566 int min_width, nat_width;
1567 int min_height, nat_height;
1568
1569 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1570
1571 if (gtk_cell_renderer_get_request_mode (cell) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
1572 {
1573 gtk_cell_renderer_get_preferred_width (cell, widget, minimum_size: &min_width, natural_size: &nat_width);
1574
1575 if (minimum_size)
1576 {
1577 minimum_size->width = min_width;
1578 gtk_cell_renderer_get_preferred_height_for_width (cell, widget, width: min_width,
1579 minimum_height: &minimum_size->height, NULL);
1580 }
1581
1582 if (natural_size)
1583 {
1584 natural_size->width = nat_width;
1585 gtk_cell_renderer_get_preferred_height_for_width (cell, widget, width: nat_width,
1586 NULL, natural_height: &natural_size->height);
1587 }
1588 }
1589 else /* GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT */
1590 {
1591 gtk_cell_renderer_get_preferred_height (cell, widget, minimum_size: &min_height, natural_size: &nat_height);
1592
1593 if (minimum_size)
1594 {
1595 minimum_size->height = min_height;
1596 gtk_cell_renderer_get_preferred_width_for_height (cell, widget, height: min_height,
1597 minimum_width: &minimum_size->width, NULL);
1598 }
1599
1600 if (natural_size)
1601 {
1602 natural_size->height = nat_height;
1603 gtk_cell_renderer_get_preferred_width_for_height (cell, widget, height: nat_height,
1604 NULL, natural_width: &natural_size->width);
1605 }
1606 }
1607}
1608
1609/**
1610 * gtk_cell_renderer_get_aligned_area:
1611 * @cell: a `GtkCellRenderer` instance
1612 * @widget: the `GtkWidget` this cell will be rendering to
1613 * @flags: render flags
1614 * @cell_area: cell area which would be passed to gtk_cell_renderer_render()
1615 * @aligned_area: (out): the return location for the space inside @cell_area
1616 * that would actually be used to render.
1617 *
1618 * Gets the aligned area used by @cell inside @cell_area. Used for finding
1619 * the appropriate edit and focus rectangle.
1620 */
1621void
1622gtk_cell_renderer_get_aligned_area (GtkCellRenderer *cell,
1623 GtkWidget *widget,
1624 GtkCellRendererState flags,
1625 const GdkRectangle *cell_area,
1626 GdkRectangle *aligned_area)
1627{
1628 GtkCellRendererClass *klass;
1629
1630 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1631 g_return_if_fail (GTK_IS_WIDGET (widget));
1632 g_return_if_fail (cell_area != NULL);
1633 g_return_if_fail (aligned_area != NULL);
1634
1635 klass = GTK_CELL_RENDERER_GET_CLASS (cell);
1636 klass->get_aligned_area (cell, widget, flags, cell_area, aligned_area);
1637
1638 g_assert (aligned_area->x >= cell_area->x && aligned_area->x <= cell_area->x + cell_area->width);
1639 g_assert (aligned_area->y >= cell_area->y && aligned_area->y <= cell_area->y + cell_area->height);
1640 g_assert ((aligned_area->x - cell_area->x) + aligned_area->width <= cell_area->width);
1641 g_assert ((aligned_area->y - cell_area->y) + aligned_area->height <= cell_area->height);
1642}
1643
1644/**
1645 * gtk_cell_renderer_get_state:
1646 * @cell: (nullable): a `GtkCellRenderer`
1647 * @widget: (nullable): a `GtkWidget`
1648 * @cell_state: cell renderer state
1649 *
1650 * Translates the cell renderer state to `GtkStateFlags`,
1651 * based on the cell renderer and widget sensitivity, and
1652 * the given `GtkCellRenderer`State.
1653 *
1654 * Returns: the widget state flags applying to @cell
1655 **/
1656GtkStateFlags
1657gtk_cell_renderer_get_state (GtkCellRenderer *cell,
1658 GtkWidget *widget,
1659 GtkCellRendererState cell_state)
1660{
1661 GtkStateFlags state = 0;
1662
1663 g_return_val_if_fail (!cell || GTK_IS_CELL_RENDERER (cell), 0);
1664 g_return_val_if_fail (!widget || GTK_IS_WIDGET (widget), 0);
1665
1666 if (widget)
1667 state |= gtk_widget_get_state_flags (widget);
1668
1669 state &= ~(GTK_STATE_FLAG_FOCUSED | GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_DROP_ACTIVE);
1670
1671 if ((state & GTK_STATE_FLAG_INSENSITIVE) != 0 ||
1672 (cell && !gtk_cell_renderer_get_sensitive (cell)) ||
1673 (cell_state & GTK_CELL_RENDERER_INSENSITIVE) != 0)
1674 {
1675 state |= GTK_STATE_FLAG_INSENSITIVE;
1676 }
1677 else
1678 {
1679 if ((widget && gtk_widget_has_focus (widget)) &&
1680 (cell_state & GTK_CELL_RENDERER_FOCUSED) != 0)
1681 state |= GTK_STATE_FLAG_FOCUSED;
1682
1683 if ((cell_state & GTK_CELL_RENDERER_PRELIT) != 0)
1684 state |= GTK_STATE_FLAG_PRELIGHT;
1685 }
1686
1687 if ((cell_state & GTK_CELL_RENDERER_SELECTED) != 0)
1688 state |= GTK_STATE_FLAG_SELECTED;
1689
1690 return state;
1691}
1692
1693/**
1694 * gtk_cell_renderer_set_is_expander:
1695 * @cell: a `GtkCellRenderer`
1696 * @is_expander: whether @cell is an expander
1697 *
1698 * Sets whether the given `GtkCellRenderer` is an expander.
1699 */
1700void
1701gtk_cell_renderer_set_is_expander (GtkCellRenderer *cell,
1702 gboolean is_expander)
1703{
1704 GtkCellRendererPrivate *priv = gtk_cell_renderer_get_instance_private (self: cell);
1705
1706 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1707
1708 is_expander = !!is_expander;
1709
1710 if (is_expander != priv->is_expander)
1711 {
1712 priv->is_expander = is_expander;
1713
1714 g_object_notify (G_OBJECT (cell), property_name: "is-expander");
1715 }
1716}
1717
1718/**
1719 * gtk_cell_renderer_get_is_expander:
1720 * @cell: a `GtkCellRenderer`
1721 *
1722 * Checks whether the given `GtkCellRenderer` is an expander.
1723 *
1724 * Returns: %TRUE if @cell is an expander, and %FALSE otherwise
1725 */
1726gboolean
1727gtk_cell_renderer_get_is_expander (GtkCellRenderer *cell)
1728{
1729 GtkCellRendererPrivate *priv = gtk_cell_renderer_get_instance_private (self: cell);
1730
1731 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1732
1733 return priv->is_expander;
1734}
1735
1736/**
1737 * gtk_cell_renderer_set_is_expanded:
1738 * @cell: a `GtkCellRenderer`
1739 * @is_expanded: whether @cell should be expanded
1740 *
1741 * Sets whether the given `GtkCellRenderer` is expanded.
1742 */
1743void
1744gtk_cell_renderer_set_is_expanded (GtkCellRenderer *cell,
1745 gboolean is_expanded)
1746{
1747 GtkCellRendererPrivate *priv = gtk_cell_renderer_get_instance_private (self: cell);
1748
1749 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1750
1751 is_expanded = !!is_expanded;
1752
1753 if (is_expanded != priv->is_expanded)
1754 {
1755 priv->is_expanded = is_expanded;
1756
1757 g_object_notify (G_OBJECT (cell), property_name: "is-expanded");
1758 }
1759}
1760
1761/**
1762 * gtk_cell_renderer_get_is_expanded:
1763 * @cell: a `GtkCellRenderer`
1764 *
1765 * Checks whether the given `GtkCellRenderer` is expanded.
1766 *
1767 * Returns: %TRUE if the cell renderer is expanded
1768 */
1769gboolean
1770gtk_cell_renderer_get_is_expanded (GtkCellRenderer *cell)
1771{
1772 GtkCellRendererPrivate *priv = gtk_cell_renderer_get_instance_private (self: cell);
1773
1774 g_return_val_if_fail (GTK_IS_CELL_RENDERER (cell), FALSE);
1775
1776 return priv->is_expanded;
1777}
1778

source code of gtk/gtk/gtkcellrenderer.c