3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
31 #include "gtkcelllayout.h"
32 #include "gtkcellarea.h"
33 #include "gtkcellareacontext.h"
34 #include "gtkmarshalers.h"
35 #include "gtkprivate.h"
37 #include <gobject/gvaluecollector.h>
41 static void gtk_cell_area_dispose (GObject *object);
42 static void gtk_cell_area_finalize (GObject *object);
43 static void gtk_cell_area_set_property (GObject *object,
47 static void gtk_cell_area_get_property (GObject *object,
52 /* GtkCellAreaClass */
53 static gint gtk_cell_area_real_event (GtkCellArea *area,
54 GtkCellAreaContext *context,
57 const GdkRectangle *cell_area,
58 GtkCellRendererState flags);
59 static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
60 GtkCellAreaContext *context,
64 gint *natural_height);
65 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
66 GtkCellAreaContext *context,
71 static gboolean gtk_cell_area_real_can_focus (GtkCellArea *area);
72 static gboolean gtk_cell_area_real_activate (GtkCellArea *area,
73 GtkCellAreaContext *context,
75 const GdkRectangle *cell_area,
76 GtkCellRendererState flags);
78 /* GtkCellLayoutIface */
79 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
80 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
81 GtkCellRenderer *renderer,
83 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
84 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
85 GtkCellRenderer *renderer,
86 const gchar *attribute,
88 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
89 GtkCellRenderer *cell,
90 GtkCellLayoutDataFunc func,
92 GDestroyNotify destroy);
93 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
94 GtkCellRenderer *renderer);
95 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
96 GtkCellRenderer *cell,
98 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
101 /* Used in forall loop to check if a child renderer is present */
103 GtkCellRenderer *renderer;
104 gboolean has_renderer;
107 /* Attribute/Cell metadata */
109 const gchar *attribute;
116 GtkCellLayoutDataFunc func;
118 GDestroyNotify destroy;
121 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
123 GDestroyNotify destroy);
124 static void cell_info_free (CellInfo *info);
125 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
126 const gchar *attribute,
128 static void cell_attribute_free (CellAttribute *attribute);
129 static gint cell_attribute_find (CellAttribute *cell_attribute,
130 const gchar *attribute);
132 /* Internal functions/signal emissions */
133 static void gtk_cell_area_add_editable (GtkCellArea *area,
134 GtkCellRenderer *renderer,
135 GtkCellEditable *editable,
136 GdkRectangle *cell_area);
137 static void gtk_cell_area_remove_editable (GtkCellArea *area,
138 GtkCellRenderer *renderer,
139 GtkCellEditable *editable);
140 static void gtk_cell_area_set_edit_widget (GtkCellArea *area,
141 GtkCellEditable *editable);
142 static void gtk_cell_area_set_edited_cell (GtkCellArea *area,
143 GtkCellRenderer *renderer);
146 /* Struct to pass data along while looping over
147 * cell renderers to apply attributes
153 gboolean is_expander;
154 gboolean is_expanded;
157 struct _GtkCellAreaPrivate
159 /* The GtkCellArea bookkeeps any connected
160 * attributes in this hash table.
162 GHashTable *cell_info;
164 /* The cell border decides how much space to reserve
165 * around each cell for the background_area
167 GtkBorder cell_border;
169 /* Current path is saved as a side-effect
170 * of gtk_cell_area_apply_attributes() */
173 /* Current cell being edited and editable widget used */
174 GtkCellEditable *edit_widget;
175 GtkCellRenderer *edited_cell;
177 /* Signal connections to the editable widget */
178 gulong remove_widget_id;
180 /* Currently focused cell */
181 GtkCellRenderer *focus_cell;
183 /* Tracking which cells are focus siblings of focusable cells */
184 GHashTable *focus_siblings;
186 /* Detail string to pass to gtk_paint_*() functions */
192 PROP_CELL_MARGIN_LEFT,
193 PROP_CELL_MARGIN_RIGHT,
194 PROP_CELL_MARGIN_TOP,
195 PROP_CELL_MARGIN_BOTTOM,
203 SIGNAL_REMOVE_EDITABLE,
204 SIGNAL_FOCUS_CHANGED,
208 /* Keep the paramspec pool internal, no need to deliver notifications
209 * on cells. at least no percieved need for now */
210 static GParamSpecPool *cell_property_pool = NULL;
211 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
213 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
214 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
217 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
218 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
219 gtk_cell_area_cell_layout_init));
222 gtk_cell_area_init (GtkCellArea *area)
224 GtkCellAreaPrivate *priv;
226 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
231 priv->cell_info = g_hash_table_new_full (g_direct_hash,
234 (GDestroyNotify)cell_info_free);
236 priv->focus_siblings = g_hash_table_new_full (g_direct_hash,
239 (GDestroyNotify)g_list_free);
241 priv->cell_border.left = 0;
242 priv->cell_border.right = 0;
243 priv->cell_border.top = 0;
244 priv->cell_border.bottom = 0;
246 priv->focus_cell = NULL;
247 priv->edited_cell = NULL;
248 priv->edit_widget = NULL;
250 priv->remove_widget_id = 0;
254 gtk_cell_area_class_init (GtkCellAreaClass *class)
256 GObjectClass *object_class = G_OBJECT_CLASS (class);
259 object_class->dispose = gtk_cell_area_dispose;
260 object_class->finalize = gtk_cell_area_finalize;
261 object_class->get_property = gtk_cell_area_get_property;
262 object_class->set_property = gtk_cell_area_set_property;
266 class->remove = NULL;
267 class->forall = NULL;
268 class->event = gtk_cell_area_real_event;
269 class->render = NULL;
272 class->create_context = NULL;
273 class->get_request_mode = NULL;
274 class->get_preferred_width = NULL;
275 class->get_preferred_height = NULL;
276 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
277 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
280 class->can_focus = gtk_cell_area_real_can_focus;
282 class->activate = gtk_cell_area_real_activate;
285 cell_area_signals[SIGNAL_ADD_EDITABLE] =
286 g_signal_new (I_("add-editable"),
287 G_OBJECT_CLASS_TYPE (object_class),
289 0, /* No class closure here */
291 _gtk_marshal_VOID__OBJECT_OBJECT_BOXED_STRING,
293 GTK_TYPE_CELL_RENDERER,
294 GTK_TYPE_CELL_EDITABLE,
298 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
299 g_signal_new (I_("remove-editable"),
300 G_OBJECT_CLASS_TYPE (object_class),
302 0, /* No class closure here */
304 _gtk_marshal_VOID__OBJECT_OBJECT,
306 GTK_TYPE_CELL_RENDERER,
307 GTK_TYPE_CELL_EDITABLE);
309 cell_area_signals[SIGNAL_FOCUS_CHANGED] =
310 g_signal_new (I_("focus-changed"),
311 G_OBJECT_CLASS_TYPE (object_class),
313 0, /* No class closure here */
315 _gtk_marshal_VOID__OBJECT_STRING,
317 GTK_TYPE_CELL_RENDERER,
321 g_object_class_install_property (object_class,
322 PROP_CELL_MARGIN_LEFT,
325 P_("Margin on Left"),
326 P_("Pixels of extra space on the left side of each cell"),
330 GTK_PARAM_READWRITE));
332 g_object_class_install_property (object_class,
333 PROP_CELL_MARGIN_RIGHT,
335 ("cell-margin-right",
336 P_("Margin on Right"),
337 P_("Pixels of extra space on the right side of each cell"),
341 GTK_PARAM_READWRITE));
343 g_object_class_install_property (object_class,
344 PROP_CELL_MARGIN_TOP,
348 P_("Pixels of extra space on the top side of each cell"),
352 GTK_PARAM_READWRITE));
354 g_object_class_install_property (object_class,
355 PROP_CELL_MARGIN_BOTTOM,
357 ("cell-margin-bottom",
358 P_("Margin on Bottom"),
359 P_("Pixels of extra space on the bottom side of each cell"),
363 GTK_PARAM_READWRITE));
365 g_object_class_install_property (object_class,
370 P_("The cell which currently has focus"),
371 GTK_TYPE_CELL_RENDERER,
372 GTK_PARAM_READWRITE));
374 g_object_class_install_property (object_class,
379 P_("The cell which is currently being edited"),
380 GTK_TYPE_CELL_RENDERER,
383 g_object_class_install_property (object_class,
388 P_("The widget currently editing the edited cell"),
389 GTK_TYPE_CELL_RENDERER,
392 /* Pool for Cell Properties */
393 if (!cell_property_pool)
394 cell_property_pool = g_param_spec_pool_new (FALSE);
396 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
399 /*************************************************************
401 *************************************************************/
403 cell_info_new (GtkCellLayoutDataFunc func,
405 GDestroyNotify destroy)
407 CellInfo *info = g_slice_new (CellInfo);
409 info->attributes = NULL;
412 info->destroy = destroy;
418 cell_info_free (CellInfo *info)
421 info->destroy (info->data);
423 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
424 g_slist_free (info->attributes);
426 g_slice_free (CellInfo, info);
429 static CellAttribute *
430 cell_attribute_new (GtkCellRenderer *renderer,
431 const gchar *attribute,
436 /* Check if the attribute really exists and point to
437 * the property string installed on the cell renderer
438 * class (dont dup the string)
440 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
444 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
446 cell_attribute->attribute = pspec->name;
447 cell_attribute->column = column;
449 return cell_attribute;
456 cell_attribute_free (CellAttribute *attribute)
458 g_slice_free (CellAttribute, attribute);
461 /* GCompareFunc for g_slist_find_custom() */
463 cell_attribute_find (CellAttribute *cell_attribute,
464 const gchar *attribute)
466 return g_strcmp0 (cell_attribute->attribute, attribute);
469 /*************************************************************
471 *************************************************************/
473 gtk_cell_area_finalize (GObject *object)
475 GtkCellArea *area = GTK_CELL_AREA (object);
476 GtkCellAreaPrivate *priv = area->priv;
478 /* All cell renderers should already be removed at this point,
479 * just kill our (empty) hash tables here.
481 g_hash_table_destroy (priv->cell_info);
482 g_hash_table_destroy (priv->focus_siblings);
484 g_free (priv->current_path);
486 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
491 gtk_cell_area_dispose (GObject *object)
493 /* This removes every cell renderer that may be added to the GtkCellArea,
494 * subclasses should be breaking references to the GtkCellRenderers
497 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
499 /* Remove any ref to a focused/edited cell */
500 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
501 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
502 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
504 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
508 gtk_cell_area_set_property (GObject *object,
513 GtkCellArea *area = GTK_CELL_AREA (object);
517 case PROP_CELL_MARGIN_LEFT:
518 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
520 case PROP_CELL_MARGIN_RIGHT:
521 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
523 case PROP_CELL_MARGIN_TOP:
524 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
526 case PROP_CELL_MARGIN_BOTTOM:
527 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
529 case PROP_FOCUS_CELL:
530 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
533 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
539 gtk_cell_area_get_property (GObject *object,
544 GtkCellArea *area = GTK_CELL_AREA (object);
545 GtkCellAreaPrivate *priv = area->priv;
549 case PROP_CELL_MARGIN_LEFT:
550 g_value_set_int (value, priv->cell_border.left);
552 case PROP_CELL_MARGIN_RIGHT:
553 g_value_set_int (value, priv->cell_border.right);
555 case PROP_CELL_MARGIN_TOP:
556 g_value_set_int (value, priv->cell_border.top);
558 case PROP_CELL_MARGIN_BOTTOM:
559 g_value_set_int (value, priv->cell_border.bottom);
561 case PROP_FOCUS_CELL:
562 g_value_set_object (value, priv->focus_cell);
564 case PROP_EDITED_CELL:
565 g_value_set_object (value, priv->edited_cell);
567 case PROP_EDIT_WIDGET:
568 g_value_set_object (value, priv->edit_widget);
571 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
576 /*************************************************************
578 *************************************************************/
580 gtk_cell_area_real_event (GtkCellArea *area,
581 GtkCellAreaContext *context,
584 const GdkRectangle *cell_area,
585 GtkCellRendererState flags)
587 GtkCellAreaPrivate *priv = area->priv;
589 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
591 GdkEventKey *key_event = (GdkEventKey *)event;
593 /* Cancel any edits in progress */
594 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
596 gtk_cell_area_stop_editing (area, TRUE);
605 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
606 GtkCellAreaContext *context,
609 gint *minimum_height,
610 gint *natural_height)
612 /* If the area doesnt do height-for-width, fallback on base preferred height */
613 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_height, natural_height);
617 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
618 GtkCellAreaContext *context,
624 /* If the area doesnt do width-for-height, fallback on base preferred width */
625 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
629 get_can_focus (GtkCellRenderer *renderer,
633 if (gtk_cell_renderer_can_focus (renderer))
638 gtk_cell_area_real_can_focus (GtkCellArea *area)
640 gboolean can_focus = FALSE;
642 /* Checks if any renderer can focus for the currently applied
645 * Subclasses can override this in the case that they are also
646 * rendering widgets as well as renderers.
648 gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
654 gtk_cell_area_real_activate (GtkCellArea *area,
655 GtkCellAreaContext *context,
657 const GdkRectangle *cell_area,
658 GtkCellRendererState flags)
660 GtkCellAreaPrivate *priv = area->priv;
661 GdkRectangle background_area;
663 if (priv->focus_cell)
665 /* Get the allocation of the focused cell.
667 gtk_cell_area_get_cell_allocation (area, context, widget, priv->focus_cell,
668 cell_area, &background_area);
670 /* Activate or Edit the currently focused cell
672 * Currently just not sending an event, renderers afaics dont use
673 * the event argument anyway, worst case is we can synthesize one.
675 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
676 &background_area, flags))
683 /*************************************************************
684 * GtkCellLayoutIface *
685 *************************************************************/
687 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
689 iface->pack_start = gtk_cell_area_pack_default;
690 iface->pack_end = gtk_cell_area_pack_default;
691 iface->clear = gtk_cell_area_clear;
692 iface->add_attribute = gtk_cell_area_add_attribute;
693 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
694 iface->clear_attributes = gtk_cell_area_clear_attributes;
695 iface->reorder = gtk_cell_area_reorder;
696 iface->get_cells = gtk_cell_area_get_cells;
700 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
701 GtkCellRenderer *renderer,
704 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
708 gtk_cell_area_clear (GtkCellLayout *cell_layout)
710 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
712 gtk_cell_layout_get_cells (cell_layout);
714 for (l = cells; l; l = l->next)
716 GtkCellRenderer *renderer = l->data;
717 gtk_cell_area_remove (area, renderer);
724 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
725 GtkCellRenderer *renderer,
726 const gchar *attribute,
729 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
730 renderer, attribute, column);
734 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
735 GtkCellRenderer *renderer,
736 GtkCellLayoutDataFunc func,
738 GDestroyNotify destroy)
740 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
741 GtkCellAreaPrivate *priv = area->priv;
744 info = g_hash_table_lookup (priv->cell_info, renderer);
748 if (info->destroy && info->data)
749 info->destroy (info->data);
754 info->data = func_data;
755 info->destroy = destroy;
761 info->destroy = NULL;
766 info = cell_info_new (func, func_data, destroy);
768 g_hash_table_insert (priv->cell_info, renderer, info);
773 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
774 GtkCellRenderer *renderer)
776 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
777 GtkCellAreaPrivate *priv = area->priv;
780 info = g_hash_table_lookup (priv->cell_info, renderer);
784 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
785 g_slist_free (info->attributes);
787 info->attributes = NULL;
792 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
793 GtkCellRenderer *cell,
796 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
797 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
801 accum_cells (GtkCellRenderer *renderer,
804 *accum = g_list_prepend (*accum, renderer);
808 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
812 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
813 (GtkCellCallback)accum_cells,
816 return g_list_reverse (cells);
820 /*************************************************************
822 *************************************************************/
826 * @area: a #GtkCellArea
827 * @renderer: the #GtkCellRenderer to add to @area
829 * Adds @renderer to @area with the default child cell properties.
832 gtk_cell_area_add (GtkCellArea *area,
833 GtkCellRenderer *renderer)
835 GtkCellAreaClass *class;
837 g_return_if_fail (GTK_IS_CELL_AREA (area));
838 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
840 class = GTK_CELL_AREA_GET_CLASS (area);
843 class->add (area, renderer);
845 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
846 g_type_name (G_TYPE_FROM_INSTANCE (area)));
850 * gtk_cell_area_remove:
851 * @area: a #GtkCellArea
852 * @renderer: the #GtkCellRenderer to add to @area
854 * Removes @renderer from @area.
857 gtk_cell_area_remove (GtkCellArea *area,
858 GtkCellRenderer *renderer)
860 GtkCellAreaClass *class;
861 GtkCellAreaPrivate *priv;
862 GList *renderers, *l;
864 g_return_if_fail (GTK_IS_CELL_AREA (area));
865 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
867 class = GTK_CELL_AREA_GET_CLASS (area);
870 /* Remove any custom attributes and custom cell data func here first */
871 g_hash_table_remove (priv->cell_info, renderer);
873 /* Remove focus siblings of this renderer */
874 g_hash_table_remove (priv->focus_siblings, renderer);
876 /* Remove this renderer from any focus renderer's sibling list */
877 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
879 for (l = renderers; l; l = l->next)
881 GtkCellRenderer *focus_renderer = l->data;
883 if (gtk_cell_area_is_focus_sibling (area, focus_renderer, renderer))
885 gtk_cell_area_remove_focus_sibling (area, focus_renderer, renderer);
890 g_list_free (renderers);
893 class->remove (area, renderer);
895 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
896 g_type_name (G_TYPE_FROM_INSTANCE (area)));
900 get_has_renderer (GtkCellRenderer *renderer,
901 HasRendererCheck *check)
903 if (renderer == check->renderer)
904 check->has_renderer = TRUE;
908 * gtk_cell_area_has_renderer:
909 * @area: a #GtkCellArea
910 * @renderer: the #GtkCellRenderer to check
912 * Checks if @area contains @renderer.
914 * Returns: %TRUE if @renderer is in the @area.
917 gtk_cell_area_has_renderer (GtkCellArea *area,
918 GtkCellRenderer *renderer)
920 HasRendererCheck check = { renderer, FALSE };
922 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
923 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
925 gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
927 return check.has_renderer;
931 * gtk_cell_area_forall
932 * @area: a #GtkCellArea
933 * @callback: the #GtkCellCallback to call
934 * @callback_data: user provided data pointer
936 * Calls @callback for every #GtkCellRenderer in @area.
939 gtk_cell_area_forall (GtkCellArea *area,
940 GtkCellCallback callback,
941 gpointer callback_data)
943 GtkCellAreaClass *class;
945 g_return_if_fail (GTK_IS_CELL_AREA (area));
946 g_return_if_fail (callback != NULL);
948 class = GTK_CELL_AREA_GET_CLASS (area);
951 class->forall (area, callback, callback_data);
953 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
954 g_type_name (G_TYPE_FROM_INSTANCE (area)));
958 * gtk_cell_area_get_cell_allocation:
959 * @area: a #GtkCellArea
960 * @context: the #GtkCellAreaContext used to hold sizes for @area.
961 * @widget: the #GtkWidget that @area is rendering on
962 * @renderer: the #GtkCellRenderer to get the allocation for
963 * @cell_area: the whole allocated area for @area in @widget
965 * @allocation: where to store the allocation for @renderer
967 * Derives the allocation of @renderer inside @area if @area
968 * were to be renderered in @cell_area.
971 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
972 GtkCellAreaContext *context,
974 GtkCellRenderer *renderer,
975 const GdkRectangle *cell_area,
976 GdkRectangle *allocation)
978 GtkCellAreaClass *class;
980 g_return_if_fail (GTK_IS_CELL_AREA (area));
981 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
982 g_return_if_fail (GTK_IS_WIDGET (widget));
983 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
984 g_return_if_fail (cell_area != NULL);
985 g_return_if_fail (allocation != NULL);
987 class = GTK_CELL_AREA_GET_CLASS (area);
989 if (class->get_cell_allocation)
990 class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
992 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
993 g_type_name (G_TYPE_FROM_INSTANCE (area)));
997 * gtk_cell_area_event:
998 * @area: a #GtkCellArea
999 * @context: the #GtkCellAreaContext for this row of data.
1000 * @widget: the #GtkWidget that @area is rendering to
1001 * @event: the #GdkEvent to handle
1002 * @cell_area: the @widget relative coordinates for @area
1003 * @flags: the #GtkCellRendererState for @area in this row.
1005 * Delegates event handling to a #GtkCellArea.
1007 * Returns: %TRUE if the event was handled by @area.
1010 gtk_cell_area_event (GtkCellArea *area,
1011 GtkCellAreaContext *context,
1014 const GdkRectangle *cell_area,
1015 GtkCellRendererState flags)
1017 GtkCellAreaClass *class;
1019 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1020 g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), 0);
1021 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
1022 g_return_val_if_fail (event != NULL, 0);
1023 g_return_val_if_fail (cell_area != NULL, 0);
1025 class = GTK_CELL_AREA_GET_CLASS (area);
1028 return class->event (area, context, widget, event, cell_area, flags);
1030 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
1031 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1036 * gtk_cell_area_render:
1037 * @area: a #GtkCellArea
1038 * @context: the #GtkCellAreaContext for this row of data.
1039 * @widget: the #GtkWidget that @area is rendering to
1040 * @cr: the #cairo_t to render with
1041 * @background_area: the @widget relative coordinates for @area's background
1042 * @cell_area: the @widget relative coordinates for @area
1043 * @flags: the #GtkCellRendererState for @area in this row.
1044 * @paint_focus: whether @area should paint focus on focused cells for focused rows or not.
1046 * Renders @area's cells according to @area's layout onto @widget at
1047 * the given coordinates.
1050 gtk_cell_area_render (GtkCellArea *area,
1051 GtkCellAreaContext *context,
1054 const GdkRectangle *background_area,
1055 const GdkRectangle *cell_area,
1056 GtkCellRendererState flags,
1057 gboolean paint_focus)
1059 GtkCellAreaClass *class;
1061 g_return_if_fail (GTK_IS_CELL_AREA (area));
1062 g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
1063 g_return_if_fail (GTK_IS_WIDGET (widget));
1064 g_return_if_fail (cr != NULL);
1065 g_return_if_fail (background_area != NULL);
1066 g_return_if_fail (cell_area != NULL);
1068 class = GTK_CELL_AREA_GET_CLASS (area);
1071 class->render (area, context, widget, cr, background_area, cell_area, flags, paint_focus);
1073 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
1074 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1078 * gtk_cell_area_set_style_detail:
1079 * @area: a #GtkCellArea
1080 * @detail: the #GtkStyle detail string to set
1082 * Sets the detail string used in any gtk_paint_*() functions
1086 gtk_cell_area_set_style_detail (GtkCellArea *area,
1087 const gchar *detail)
1089 GtkCellAreaPrivate *priv;
1091 g_return_if_fail (GTK_IS_CELL_AREA (area));
1095 if (g_strcmp0 (priv->style_detail, detail) != 0)
1097 g_free (priv->style_detail);
1098 priv->style_detail = g_strdup (detail);
1103 * gtk_cell_area_get_style_detail:
1104 * @area: a #GtkCellArea
1106 * Gets the detail string used in any gtk_paint_*() functions
1109 * Returns: the detail string.
1111 G_CONST_RETURN gchar *
1112 gtk_cell_area_get_style_detail (GtkCellArea *area)
1114 GtkCellAreaPrivate *priv;
1116 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1120 return priv->style_detail;
1123 /*************************************************************
1125 *************************************************************/
1127 * gtk_cell_area_create_context:
1128 * @area: a #GtkCellArea
1130 * Creates a #GtkCellAreaContext to be used with @area for
1131 * all purposes. #GtkCellAreaContext stores geometry information
1132 * for rows for which it was operated on, it is important to use
1133 * the same context for the same row of data at all times (i.e.
1134 * one should render and handle events with the same #GtkCellAreaContext
1135 * which was used to request the size of those rows of data).
1137 * Returns: a newly created #GtkCellAreaContext which can be used with @area.
1139 GtkCellAreaContext *
1140 gtk_cell_area_create_context (GtkCellArea *area)
1142 GtkCellAreaClass *class;
1144 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1146 class = GTK_CELL_AREA_GET_CLASS (area);
1148 if (class->create_context)
1149 return class->create_context (area);
1151 g_warning ("GtkCellAreaClass::create_context not implemented for `%s'",
1152 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1159 gtk_cell_area_get_request_mode (GtkCellArea *area)
1161 GtkCellAreaClass *class;
1163 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1164 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1166 class = GTK_CELL_AREA_GET_CLASS (area);
1168 if (class->get_request_mode)
1169 return class->get_request_mode (area);
1171 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1172 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1174 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1178 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1179 GtkCellAreaContext *context,
1184 GtkCellAreaClass *class;
1186 g_return_if_fail (GTK_IS_CELL_AREA (area));
1187 g_return_if_fail (GTK_IS_WIDGET (widget));
1189 class = GTK_CELL_AREA_GET_CLASS (area);
1191 if (class->get_preferred_width)
1192 class->get_preferred_width (area, context, widget, minimum_size, natural_size);
1194 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1195 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1199 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1200 GtkCellAreaContext *context,
1203 gint *minimum_height,
1204 gint *natural_height)
1206 GtkCellAreaClass *class;
1208 g_return_if_fail (GTK_IS_CELL_AREA (area));
1209 g_return_if_fail (GTK_IS_WIDGET (widget));
1211 class = GTK_CELL_AREA_GET_CLASS (area);
1212 class->get_preferred_height_for_width (area, context, widget, width, minimum_height, natural_height);
1216 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1217 GtkCellAreaContext *context,
1222 GtkCellAreaClass *class;
1224 g_return_if_fail (GTK_IS_CELL_AREA (area));
1225 g_return_if_fail (GTK_IS_WIDGET (widget));
1227 class = GTK_CELL_AREA_GET_CLASS (area);
1229 if (class->get_preferred_height)
1230 class->get_preferred_height (area, context, widget, minimum_size, natural_size);
1232 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1233 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1237 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1238 GtkCellAreaContext *context,
1241 gint *minimum_width,
1242 gint *natural_width)
1244 GtkCellAreaClass *class;
1246 g_return_if_fail (GTK_IS_CELL_AREA (area));
1247 g_return_if_fail (GTK_IS_WIDGET (widget));
1249 class = GTK_CELL_AREA_GET_CLASS (area);
1250 class->get_preferred_width_for_height (area, context, widget, height, minimum_width, natural_width);
1253 /*************************************************************
1255 *************************************************************/
1258 * gtk_cell_area_attribute_connect:
1259 * @area: a #GtkCellArea
1260 * @renderer: the #GtkCellRenderer to connect an attribute for
1261 * @attribute: the attribute name
1262 * @column: the #GtkTreeModel column to fetch attribute values from
1264 * Connects an @attribute to apply values from @column for the
1265 * #GtkTreeModel in use.
1268 gtk_cell_area_attribute_connect (GtkCellArea *area,
1269 GtkCellRenderer *renderer,
1270 const gchar *attribute,
1273 GtkCellAreaPrivate *priv;
1275 CellAttribute *cell_attribute;
1277 g_return_if_fail (GTK_IS_CELL_AREA (area));
1278 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1279 g_return_if_fail (attribute != NULL);
1280 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1283 info = g_hash_table_lookup (priv->cell_info, renderer);
1287 info = cell_info_new (NULL, NULL, NULL);
1289 g_hash_table_insert (priv->cell_info, renderer, info);
1295 /* Check we are not adding the same attribute twice */
1296 if ((node = g_slist_find_custom (info->attributes, attribute,
1297 (GCompareFunc)cell_attribute_find)) != NULL)
1299 cell_attribute = node->data;
1301 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1302 "since `%s' is already attributed to column %d",
1304 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1305 attribute, cell_attribute->column);
1310 cell_attribute = cell_attribute_new (renderer, attribute, column);
1312 if (!cell_attribute)
1314 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1315 "since attribute does not exist",
1317 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1321 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1325 * gtk_cell_area_attribute_disconnect:
1326 * @area: a #GtkCellArea
1327 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1328 * @attribute: the attribute name
1330 * Disconnects @attribute for the @renderer in @area so that
1331 * attribute will no longer be updated with values from the
1335 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1336 GtkCellRenderer *renderer,
1337 const gchar *attribute)
1339 GtkCellAreaPrivate *priv;
1341 CellAttribute *cell_attribute;
1344 g_return_if_fail (GTK_IS_CELL_AREA (area));
1345 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1346 g_return_if_fail (attribute != NULL);
1347 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
1350 info = g_hash_table_lookup (priv->cell_info, renderer);
1354 node = g_slist_find_custom (info->attributes, attribute,
1355 (GCompareFunc)cell_attribute_find);
1358 cell_attribute = node->data;
1360 cell_attribute_free (cell_attribute);
1362 info->attributes = g_slist_delete_link (info->attributes, node);
1368 apply_cell_attributes (GtkCellRenderer *renderer,
1370 AttributeData *data)
1372 CellAttribute *attribute;
1374 GValue value = { 0, };
1375 gboolean is_expander;
1376 gboolean is_expanded;
1378 g_object_freeze_notify (G_OBJECT (renderer));
1380 /* Whether a row expands or is presently expanded can only be
1381 * provided by the view (as these states can vary across views
1382 * accessing the same model).
1384 g_object_get (renderer, "is-expander", &is_expander, NULL);
1385 if (is_expander != data->is_expander)
1386 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1388 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1389 if (is_expanded != data->is_expanded)
1390 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1392 /* Apply the attributes directly to the renderer */
1393 for (list = info->attributes; list; list = list->next)
1395 attribute = list->data;
1397 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1398 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1399 g_value_unset (&value);
1402 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1405 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1406 data->model, data->iter, info->data);
1408 g_object_thaw_notify (G_OBJECT (renderer));
1412 * gtk_cell_area_apply_attributes
1413 * @area: a #GtkCellArea
1414 * @tree_model: a #GtkTreeModel to pull values from
1415 * @iter: the #GtkTreeIter in @tree_model to apply values for
1416 * @is_expander: whether @iter has children
1417 * @is_expanded: whether @iter is expanded in the view and
1418 * children are visible
1420 * Applies any connected attributes to the renderers in
1421 * @area by pulling the values from @tree_model.
1424 gtk_cell_area_apply_attributes (GtkCellArea *area,
1425 GtkTreeModel *tree_model,
1427 gboolean is_expander,
1428 gboolean is_expanded)
1430 GtkCellAreaPrivate *priv;
1434 g_return_if_fail (GTK_IS_CELL_AREA (area));
1435 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1436 g_return_if_fail (iter != NULL);
1440 /* Feed in data needed to apply to every renderer */
1442 data.model = tree_model;
1444 data.is_expander = is_expander;
1445 data.is_expanded = is_expanded;
1447 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1448 * apply the data from the treemodel */
1449 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1451 /* Update the currently applied path */
1452 g_free (priv->current_path);
1453 path = gtk_tree_model_get_path (tree_model, iter);
1454 priv->current_path = gtk_tree_path_to_string (path);
1455 gtk_tree_path_free (path);
1459 * gtk_cell_area_get_current_path_string:
1460 * @area: a #GtkCellArea
1462 * Gets the current #GtkTreePath string for the currently
1463 * applied #GtkTreeIter, this is implicitly updated when
1464 * gtk_cell_area_apply_attributes() is called and can be
1465 * used to interact with renderers from #GtkCellArea
1469 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1471 GtkCellAreaPrivate *priv;
1473 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1477 return priv->current_path;
1481 /*************************************************************
1482 * API: Cell Properties *
1483 *************************************************************/
1485 * gtk_cell_area_class_install_cell_property:
1486 * @aclass: a #GtkCellAreaClass
1487 * @property_id: the id for the property
1488 * @pspec: the #GParamSpec for the property
1490 * Installs a cell property on a cell area class.
1493 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1497 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1498 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1499 if (pspec->flags & G_PARAM_WRITABLE)
1500 g_return_if_fail (aclass->set_cell_property != NULL);
1501 if (pspec->flags & G_PARAM_READABLE)
1502 g_return_if_fail (aclass->get_cell_property != NULL);
1503 g_return_if_fail (property_id > 0);
1504 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1505 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1507 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1509 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1510 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1513 g_param_spec_ref (pspec);
1514 g_param_spec_sink (pspec);
1515 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1516 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1520 * gtk_cell_area_class_find_cell_property:
1521 * @aclass: a #GtkCellAreaClass
1522 * @property_name: the name of the child property to find
1523 * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
1524 * child property with that name.
1526 * Finds a cell property of a cell area class by name.
1529 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1530 const gchar *property_name)
1532 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1533 g_return_val_if_fail (property_name != NULL, NULL);
1535 return g_param_spec_pool_lookup (cell_property_pool,
1537 G_OBJECT_CLASS_TYPE (aclass),
1542 * gtk_cell_area_class_list_cell_properties:
1543 * @aclass: a #GtkCellAreaClass
1544 * @n_properties: location to return the number of cell properties found
1545 * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
1546 * The array must be freed with g_free().
1548 * Returns all cell properties of a cell area class.
1551 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1552 guint *n_properties)
1554 GParamSpec **pspecs;
1557 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1559 pspecs = g_param_spec_pool_list (cell_property_pool,
1560 G_OBJECT_CLASS_TYPE (aclass),
1569 * gtk_cell_area_add_with_properties:
1570 * @area: a #GtkCellArea
1571 * @renderer: a #GtkCellRenderer to be placed inside @area
1572 * @first_prop_name: the name of the first cell property to set
1573 * @Varargs: a %NULL-terminated list of property names and values, starting
1574 * with @first_prop_name
1576 * Adds @renderer to @area, setting cell properties at the same time.
1577 * See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
1580 gtk_cell_area_add_with_properties (GtkCellArea *area,
1581 GtkCellRenderer *renderer,
1582 const gchar *first_prop_name,
1585 GtkCellAreaClass *class;
1587 g_return_if_fail (GTK_IS_CELL_AREA (area));
1588 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1590 class = GTK_CELL_AREA_GET_CLASS (area);
1596 class->add (area, renderer);
1598 va_start (var_args, first_prop_name);
1599 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1603 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1604 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1608 * gtk_cell_area_cell_set:
1609 * @area: a #GtkCellArea
1610 * @renderer: a #GtkCellRenderer which is a cell inside @area
1611 * @first_prop_name: the name of the first cell property to set
1612 * @Varargs: a %NULL-terminated list of property names and values, starting
1613 * with @first_prop_name
1615 * Sets one or more cell properties for @cell in @area.
1618 gtk_cell_area_cell_set (GtkCellArea *area,
1619 GtkCellRenderer *renderer,
1620 const gchar *first_prop_name,
1625 g_return_if_fail (GTK_IS_CELL_AREA (area));
1626 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1628 va_start (var_args, first_prop_name);
1629 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1634 * gtk_cell_area_cell_get:
1635 * @area: a #GtkCellArea
1636 * @renderer: a #GtkCellRenderer which is inside @area
1637 * @first_prop_name: the name of the first cell property to get
1638 * @Varargs: return location for the first cell property, followed
1639 * optionally by more name/return location pairs, followed by %NULL
1641 * Gets the values of one or more cell properties for @renderer in @area.
1644 gtk_cell_area_cell_get (GtkCellArea *area,
1645 GtkCellRenderer *renderer,
1646 const gchar *first_prop_name,
1651 g_return_if_fail (GTK_IS_CELL_AREA (area));
1652 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1654 va_start (var_args, first_prop_name);
1655 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1660 area_get_cell_property (GtkCellArea *area,
1661 GtkCellRenderer *renderer,
1665 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1667 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1671 area_set_cell_property (GtkCellArea *area,
1672 GtkCellRenderer *renderer,
1674 const GValue *value)
1676 GValue tmp_value = { 0, };
1677 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1679 /* provide a copy to work from, convert (if necessary) and validate */
1680 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1681 if (!g_value_transform (value, &tmp_value))
1682 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1684 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1685 G_VALUE_TYPE_NAME (value));
1686 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1688 gchar *contents = g_strdup_value_contents (value);
1690 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1692 G_VALUE_TYPE_NAME (value),
1694 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1699 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1701 g_value_unset (&tmp_value);
1705 * gtk_cell_area_cell_set_valist:
1706 * @area: a #GtkCellArea
1707 * @renderer: a #GtkCellRenderer which inside @area
1708 * @first_property_name: the name of the first cell property to set
1709 * @var_args: a %NULL-terminated list of property names and values, starting
1710 * with @first_prop_name
1712 * Sets one or more cell properties for @renderer in @area.
1715 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1716 GtkCellRenderer *renderer,
1717 const gchar *first_property_name,
1722 g_return_if_fail (GTK_IS_CELL_AREA (area));
1723 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1725 name = first_property_name;
1728 GValue value = { 0, };
1729 gchar *error = NULL;
1731 g_param_spec_pool_lookup (cell_property_pool, name,
1732 G_OBJECT_TYPE (area), TRUE);
1735 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1736 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1739 if (!(pspec->flags & G_PARAM_WRITABLE))
1741 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1742 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1746 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1747 G_VALUE_COLLECT (&value, var_args, 0, &error);
1750 g_warning ("%s: %s", G_STRLOC, error);
1753 /* we purposely leak the value here, it might not be
1754 * in a sane state if an error condition occoured
1758 area_set_cell_property (area, renderer, pspec, &value);
1759 g_value_unset (&value);
1760 name = va_arg (var_args, gchar*);
1765 * gtk_cell_area_cell_get_valist:
1766 * @area: a #GtkCellArea
1767 * @renderer: a #GtkCellRenderer inside @area
1768 * @first_property_name: the name of the first property to get
1769 * @var_args: return location for the first property, followed
1770 * optionally by more name/return location pairs, followed by %NULL
1772 * Gets the values of one or more cell properties for @renderer in @area.
1775 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1776 GtkCellRenderer *renderer,
1777 const gchar *first_property_name,
1782 g_return_if_fail (GTK_IS_CELL_AREA (area));
1783 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1785 name = first_property_name;
1788 GValue value = { 0, };
1792 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1793 G_OBJECT_TYPE (area), TRUE);
1796 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1797 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1800 if (!(pspec->flags & G_PARAM_READABLE))
1802 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1803 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1807 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1808 area_get_cell_property (area, renderer, pspec, &value);
1809 G_VALUE_LCOPY (&value, var_args, 0, &error);
1812 g_warning ("%s: %s", G_STRLOC, error);
1814 g_value_unset (&value);
1817 g_value_unset (&value);
1818 name = va_arg (var_args, gchar*);
1823 * gtk_cell_area_cell_set_property:
1824 * @area: a #GtkCellArea
1825 * @renderer: a #GtkCellRenderer inside @area
1826 * @property_name: the name of the cell property to set
1827 * @value: the value to set the cell property to
1829 * Sets a cell property for @renderer in @area.
1832 gtk_cell_area_cell_set_property (GtkCellArea *area,
1833 GtkCellRenderer *renderer,
1834 const gchar *property_name,
1835 const GValue *value)
1839 g_return_if_fail (GTK_IS_CELL_AREA (area));
1840 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1841 g_return_if_fail (property_name != NULL);
1842 g_return_if_fail (G_IS_VALUE (value));
1844 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1845 G_OBJECT_TYPE (area), TRUE);
1847 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1848 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1849 else if (!(pspec->flags & G_PARAM_WRITABLE))
1850 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1851 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1854 area_set_cell_property (area, renderer, pspec, value);
1859 * gtk_cell_area_cell_get_property:
1860 * @area: a #GtkCellArea
1861 * @renderer: a #GtkCellRenderer inside @area
1862 * @property_name: the name of the property to get
1863 * @value: a location to return the value
1865 * Gets the value of a cell property for @renderer in @area.
1868 gtk_cell_area_cell_get_property (GtkCellArea *area,
1869 GtkCellRenderer *renderer,
1870 const gchar *property_name,
1875 g_return_if_fail (GTK_IS_CELL_AREA (area));
1876 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1877 g_return_if_fail (property_name != NULL);
1878 g_return_if_fail (G_IS_VALUE (value));
1880 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1881 G_OBJECT_TYPE (area), TRUE);
1883 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1884 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1885 else if (!(pspec->flags & G_PARAM_READABLE))
1886 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1887 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1890 GValue *prop_value, tmp_value = { 0, };
1892 /* auto-conversion of the callers value type
1894 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1896 g_value_reset (value);
1899 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1901 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1903 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1904 G_VALUE_TYPE_NAME (value));
1909 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1910 prop_value = &tmp_value;
1913 area_get_cell_property (area, renderer, pspec, prop_value);
1915 if (prop_value != value)
1917 g_value_transform (prop_value, value);
1918 g_value_unset (&tmp_value);
1923 /*************************************************************
1925 *************************************************************/
1928 * gtk_cell_area_can_focus:
1929 * @area: a #GtkCellArea
1931 * Returns whether the area can receive keyboard focus,
1932 * after applying new attributes to @area.
1934 * Returns: whether @area can receive focus.
1937 gtk_cell_area_can_focus (GtkCellArea *area)
1939 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1941 return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
1945 * gtk_cell_area_focus:
1946 * @area: a #GtkCellArea
1947 * @direction: the #GtkDirectionType
1949 * This should be called by the @area's owning layout widget
1950 * when focus is to be passed to @area, or moved within @area
1951 * for a given @direction and row data.
1953 * Implementing #GtkCellArea classes should implement this
1954 * method to receive and navigate focus in it's own way particular
1955 * to how it lays out cells.
1957 * Returns: %TRUE if focus remains inside @area as a result of this call.
1960 gtk_cell_area_focus (GtkCellArea *area,
1961 GtkDirectionType direction)
1963 GtkCellAreaClass *class;
1965 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1967 class = GTK_CELL_AREA_GET_CLASS (area);
1970 return class->focus (area, direction);
1972 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
1973 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1979 * gtk_cell_area_activate:
1980 * @area: a #GtkCellArea
1981 * @context: the #GtkCellAreaContext in context with the current row data
1982 * @widget: the #GtkWidget that @area is rendering on
1983 * @cell_area: the size and location of @area relative to @widget's allocation
1984 * @flags: the #GtkCellRendererState flags for @area for this row of data.
1986 * Activates @area, usually by activating the currently focused
1987 * cell, however some subclasses which embed widgets in the area
1988 * can also activate a widget if it currently has the focus.
1990 * Returns: Whether @area was successfully activated.
1993 gtk_cell_area_activate (GtkCellArea *area,
1994 GtkCellAreaContext *context,
1996 const GdkRectangle *cell_area,
1997 GtkCellRendererState flags)
1999 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2001 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
2006 * gtk_cell_area_set_focus_cell:
2007 * @area: a #GtkCellArea
2008 * @focus_cell: the #GtkCellRenderer to give focus to
2010 * This is generally called from #GtkCellArea implementations
2011 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
2012 * is called. It's also up to the #GtkCellArea implementation
2013 * to update the focused cell when receiving events from
2014 * gtk_cell_area_event() appropriately.
2017 gtk_cell_area_set_focus_cell (GtkCellArea *area,
2018 GtkCellRenderer *renderer)
2020 GtkCellAreaPrivate *priv;
2022 g_return_if_fail (GTK_IS_CELL_AREA (area));
2023 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2027 if (priv->focus_cell != renderer)
2029 if (priv->focus_cell)
2030 g_object_unref (priv->focus_cell);
2032 priv->focus_cell = renderer;
2034 if (priv->focus_cell)
2035 g_object_ref (priv->focus_cell);
2037 g_object_notify (G_OBJECT (area), "focus-cell");
2040 /* Signal that the current focus renderer for this path changed
2041 * (it may be that the focus cell did not change, but the row
2042 * may have changed so we need to signal it) */
2043 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_CHANGED], 0,
2044 priv->focus_cell, priv->current_path);
2049 * gtk_cell_area_get_focus_cell:
2050 * @area: a #GtkCellArea
2052 * Retrieves the currently focused cell for @area
2054 * Returns: the currently focused cell in @area.
2057 gtk_cell_area_get_focus_cell (GtkCellArea *area)
2059 GtkCellAreaPrivate *priv;
2061 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2065 return priv->focus_cell;
2069 /*************************************************************
2070 * API: Focus Siblings *
2071 *************************************************************/
2074 * gtk_cell_area_add_focus_sibling:
2075 * @area: a #GtkCellArea
2076 * @renderer: the #GtkCellRenderer expected to have focus
2077 * @sibling: the #GtkCellRenderer to add to @renderer's focus area
2079 * Adds @sibling to @renderer's focusable area, focus will be drawn
2080 * around @renderer and all of it's siblings if @renderer can
2081 * focus for a given row.
2083 * Events handled by focus siblings can also activate the given
2084 * focusable @renderer.
2087 gtk_cell_area_add_focus_sibling (GtkCellArea *area,
2088 GtkCellRenderer *renderer,
2089 GtkCellRenderer *sibling)
2091 GtkCellAreaPrivate *priv;
2094 g_return_if_fail (GTK_IS_CELL_AREA (area));
2095 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2096 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2097 g_return_if_fail (renderer != sibling);
2098 g_return_if_fail (gtk_cell_area_has_renderer (area, renderer));
2099 g_return_if_fail (gtk_cell_area_has_renderer (area, sibling));
2100 g_return_if_fail (!gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2102 /* XXX We should also check that sibling is not in any other renderer's sibling
2103 * list already, a renderer can be sibling of only one focusable renderer
2109 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2112 siblings = g_list_append (siblings, sibling);
2115 siblings = g_list_append (siblings, sibling);
2116 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2121 * gtk_cell_area_remove_focus_sibling:
2122 * @area: a #GtkCellArea
2123 * @renderer: the #GtkCellRenderer expected to have focus
2124 * @sibling: the #GtkCellRenderer to remove from @renderer's focus area
2126 * Removes @sibling from @renderer's focus sibling list
2127 * (see gtk_cell_area_add_focus_sibling()).
2130 gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
2131 GtkCellRenderer *renderer,
2132 GtkCellRenderer *sibling)
2134 GtkCellAreaPrivate *priv;
2137 g_return_if_fail (GTK_IS_CELL_AREA (area));
2138 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2139 g_return_if_fail (GTK_IS_CELL_RENDERER (sibling));
2140 g_return_if_fail (gtk_cell_area_is_focus_sibling (area, renderer, sibling));
2144 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2146 siblings = g_list_copy (siblings);
2147 siblings = g_list_remove (siblings, sibling);
2150 g_hash_table_remove (priv->focus_siblings, renderer);
2152 g_hash_table_insert (priv->focus_siblings, renderer, siblings);
2156 * gtk_cell_area_is_focus_sibling:
2157 * @area: a #GtkCellArea
2158 * @renderer: the #GtkCellRenderer expected to have focus
2159 * @sibling: the #GtkCellRenderer to check against @renderer's sibling list
2161 * Returns %TRUE if @sibling is one of @renderer's focus siblings
2162 * (see gtk_cell_area_add_focus_sibling()).
2165 gtk_cell_area_is_focus_sibling (GtkCellArea *area,
2166 GtkCellRenderer *renderer,
2167 GtkCellRenderer *sibling)
2169 GtkCellAreaPrivate *priv;
2170 GList *siblings, *l;
2172 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2173 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2174 g_return_val_if_fail (GTK_IS_CELL_RENDERER (sibling), FALSE);
2178 siblings = g_hash_table_lookup (priv->focus_siblings, renderer);
2180 for (l = siblings; l; l = l->next)
2182 GtkCellRenderer *a_sibling = l->data;
2184 if (a_sibling == sibling)
2192 * gtk_cell_area_get_focus_siblings:
2193 * @area: a #GtkCellArea
2194 * @renderer: the #GtkCellRenderer expected to have focus
2196 * Gets the focus sibling cell renderers for @renderer.
2198 * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
2201 gtk_cell_area_get_focus_siblings (GtkCellArea *area,
2202 GtkCellRenderer *renderer)
2204 GtkCellAreaPrivate *priv;
2206 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2207 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2211 return g_hash_table_lookup (priv->focus_siblings, renderer);
2215 * gtk_cell_area_get_focus_from_sibling:
2216 * @area: a #GtkCellArea
2217 * @renderer: the #GtkCellRenderer
2219 * Gets the #GtkCellRenderer which is expected to be focusable
2220 * for which @renderer is, or may be a sibling.
2222 * This is handy for #GtkCellArea subclasses when handling events,
2223 * after determining the renderer at the event location it can
2224 * then chose to activate the focus cell for which the event
2225 * cell may have been a sibling.
2227 * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
2230 gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
2231 GtkCellRenderer *renderer)
2233 GtkCellRenderer *ret_renderer = NULL;
2234 GList *renderers, *l;
2236 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2237 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), NULL);
2239 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
2241 for (l = renderers; l; l = l->next)
2243 GtkCellRenderer *a_renderer = l->data;
2246 for (list = gtk_cell_area_get_focus_siblings (area, a_renderer);
2247 list; list = list->next)
2249 GtkCellRenderer *sibling_renderer = list->data;
2251 if (sibling_renderer == renderer)
2253 ret_renderer = a_renderer;
2258 g_list_free (renderers);
2260 return ret_renderer;
2263 /*************************************************************
2264 * API: Cell Activation/Editing *
2265 *************************************************************/
2267 gtk_cell_area_add_editable (GtkCellArea *area,
2268 GtkCellRenderer *renderer,
2269 GtkCellEditable *editable,
2270 GdkRectangle *cell_area)
2272 g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
2273 renderer, editable, cell_area, area->priv->current_path);
2277 gtk_cell_area_remove_editable (GtkCellArea *area,
2278 GtkCellRenderer *renderer,
2279 GtkCellEditable *editable)
2281 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
2285 cell_area_remove_widget_cb (GtkCellEditable *editable,
2288 GtkCellAreaPrivate *priv = area->priv;
2290 g_assert (priv->edit_widget == editable);
2291 g_assert (priv->edited_cell != NULL);
2293 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
2295 /* Now that we're done with editing the widget and it can be removed,
2296 * remove our references to the widget and disconnect handlers */
2297 gtk_cell_area_set_edited_cell (area, NULL);
2298 gtk_cell_area_set_edit_widget (area, NULL);
2302 gtk_cell_area_set_edited_cell (GtkCellArea *area,
2303 GtkCellRenderer *renderer)
2305 GtkCellAreaPrivate *priv;
2307 g_return_if_fail (GTK_IS_CELL_AREA (area));
2308 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
2312 if (priv->edited_cell != renderer)
2314 if (priv->edited_cell)
2315 g_object_unref (priv->edited_cell);
2317 priv->edited_cell = renderer;
2319 if (priv->edited_cell)
2320 g_object_ref (priv->edited_cell);
2322 g_object_notify (G_OBJECT (area), "edited-cell");
2327 gtk_cell_area_set_edit_widget (GtkCellArea *area,
2328 GtkCellEditable *editable)
2330 GtkCellAreaPrivate *priv;
2332 g_return_if_fail (GTK_IS_CELL_AREA (area));
2333 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
2337 if (priv->edit_widget != editable)
2339 if (priv->edit_widget)
2341 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2343 g_object_unref (priv->edit_widget);
2346 priv->edit_widget = editable;
2348 if (priv->edit_widget)
2350 priv->remove_widget_id =
2351 g_signal_connect (priv->edit_widget, "remove-widget",
2352 G_CALLBACK (cell_area_remove_widget_cb), area);
2354 g_object_ref (priv->edit_widget);
2357 g_object_notify (G_OBJECT (area), "edit-widget");
2362 * gtk_cell_area_get_edited_cell:
2363 * @area: a #GtkCellArea
2365 * Gets the #GtkCellRenderer in @area that is currently
2368 * Returns: The currently edited #GtkCellRenderer
2371 gtk_cell_area_get_edited_cell (GtkCellArea *area)
2373 GtkCellAreaPrivate *priv;
2375 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2379 return priv->edited_cell;
2383 * gtk_cell_area_get_edit_widget:
2384 * @area: a #GtkCellArea
2386 * Gets the #GtkCellEditable widget currently used
2387 * to edit the currently edited cell.
2389 * Returns: The currently active #GtkCellEditable widget
2392 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2394 GtkCellAreaPrivate *priv;
2396 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2400 return priv->edit_widget;
2404 * gtk_cell_area_activate_cell:
2405 * @area: a #GtkCellArea
2406 * @widget: the #GtkWidget that @area is rendering onto
2407 * @renderer: the #GtkCellRenderer in @area to activate
2408 * @event: the #GdkEvent for which cell activation should occur
2409 * @cell_area: the #GdkRectangle in @widget relative coordinates
2410 * of @renderer for the current row.
2411 * @flags: the #GtkCellRendererState for @renderer
2413 * This is used by #GtkCellArea subclasses when handling events
2414 * to activate cells, the base #GtkCellArea class activates cells
2415 * for keyboard events for free in it's own GtkCellArea->activate()
2418 * Returns: whether cell activation was successful
2421 gtk_cell_area_activate_cell (GtkCellArea *area,
2423 GtkCellRenderer *renderer,
2425 const GdkRectangle *cell_area,
2426 GtkCellRendererState flags)
2428 GtkCellRendererMode mode;
2429 GdkRectangle inner_area;
2430 GtkCellAreaPrivate *priv;
2432 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2433 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2434 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2435 g_return_val_if_fail (cell_area != NULL, FALSE);
2439 /* Remove margins from the background area to produce the cell area.
2441 * XXX Maybe have to do some rtl mode treatment here...
2443 gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
2445 g_object_get (renderer, "mode", &mode, NULL);
2447 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2449 if (gtk_cell_renderer_activate (renderer,
2457 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2459 GtkCellEditable *editable_widget;
2462 gtk_cell_renderer_start_editing (renderer,
2469 if (editable_widget != NULL)
2471 GdkRectangle edit_area;
2473 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2475 gtk_cell_area_set_edited_cell (area, renderer);
2476 gtk_cell_area_set_edit_widget (area, editable_widget);
2478 gtk_cell_area_aligned_cell_area (area, widget, renderer, &inner_area, &edit_area);
2480 /* Signal that editing started so that callers can get
2481 * a handle on the editable_widget */
2482 gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &edit_area);
2484 /* If the signal was successfully handled start the editing */
2485 if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
2487 gtk_cell_editable_start_editing (editable_widget, NULL);
2488 gtk_widget_grab_focus (GTK_WIDGET (editable_widget));
2492 /* Otherwise clear the editing state and fire a warning */
2493 gtk_cell_area_set_edited_cell (area, NULL);
2494 gtk_cell_area_set_edit_widget (area, NULL);
2496 g_warning ("GtkCellArea::add-editable fired in the dark, no cell editing was started.");
2507 * gtk_cell_area_stop_editing:
2508 * @area: a #GtkCellArea
2509 * @canceled: whether editing was canceled.
2511 * Explicitly stops the editing of the currently
2512 * edited cell (see gtk_cell_area_get_edited_cell()).
2514 * If @canceled is %TRUE, the cell renderer will emit
2515 * the ::editing-canceled signal.
2518 gtk_cell_area_stop_editing (GtkCellArea *area,
2521 GtkCellAreaPrivate *priv;
2523 g_return_if_fail (GTK_IS_CELL_AREA (area));
2527 if (priv->edited_cell)
2529 GtkCellEditable *edit_widget = g_object_ref (priv->edit_widget);
2530 GtkCellRenderer *edit_cell = g_object_ref (priv->edited_cell);
2532 /* Stop editing of the cell renderer */
2533 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2535 /* Remove any references to the editable widget */
2536 gtk_cell_area_set_edited_cell (area, NULL);
2537 gtk_cell_area_set_edit_widget (area, NULL);
2539 /* Send the remove-widget signal explicitly (this is done after setting
2540 * the edit cell/widget NULL to avoid feedback)
2542 gtk_cell_area_remove_editable (area, edit_cell, edit_widget);
2543 g_object_unref (edit_cell);
2544 g_object_unref (edit_widget);
2548 /*************************************************************
2550 *************************************************************/
2552 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
2554 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2556 return area->priv->cell_border.left;
2560 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
2563 GtkCellAreaPrivate *priv;
2565 g_return_if_fail (GTK_IS_CELL_AREA (area));
2569 if (priv->cell_border.left != margin)
2571 priv->cell_border.left = margin;
2573 g_object_notify (G_OBJECT (area), "cell-margin-left");
2578 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
2580 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2582 return area->priv->cell_border.right;
2586 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
2589 GtkCellAreaPrivate *priv;
2591 g_return_if_fail (GTK_IS_CELL_AREA (area));
2595 if (priv->cell_border.right != margin)
2597 priv->cell_border.right = margin;
2599 g_object_notify (G_OBJECT (area), "cell-margin-right");
2604 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
2606 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2608 return area->priv->cell_border.top;
2612 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
2615 GtkCellAreaPrivate *priv;
2617 g_return_if_fail (GTK_IS_CELL_AREA (area));
2621 if (priv->cell_border.top != margin)
2623 priv->cell_border.top = margin;
2625 g_object_notify (G_OBJECT (area), "cell-margin-top");
2630 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
2632 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2634 return area->priv->cell_border.bottom;
2638 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
2641 GtkCellAreaPrivate *priv;
2643 g_return_if_fail (GTK_IS_CELL_AREA (area));
2647 if (priv->cell_border.bottom != margin)
2649 priv->cell_border.bottom = margin;
2651 g_object_notify (G_OBJECT (area), "cell-margin-bottom");
2656 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2657 const GdkRectangle *cell_area,
2658 GdkRectangle *inner_area)
2660 GtkCellAreaPrivate *priv;
2662 g_return_if_fail (GTK_IS_CELL_AREA (area));
2663 g_return_if_fail (cell_area != NULL);
2664 g_return_if_fail (inner_area != NULL);
2668 *inner_area = *cell_area;
2670 inner_area->x += priv->cell_border.left;
2671 inner_area->width -= (priv->cell_border.left + priv->cell_border.right);
2672 inner_area->y += priv->cell_border.top;
2673 inner_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2677 gtk_cell_area_aligned_cell_area (GtkCellArea *area,
2679 GtkCellRenderer *renderer,
2680 const GdkRectangle *cell_area,
2681 GdkRectangle *aligned_area)
2683 GtkCellAreaPrivate *priv;
2684 gint opposite_size, x_offset, y_offset;
2686 g_return_if_fail (GTK_IS_CELL_AREA (area));
2687 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2688 g_return_if_fail (GTK_IS_WIDGET (widget));
2689 g_return_if_fail (cell_area != NULL);
2690 g_return_if_fail (aligned_area != NULL);
2694 *aligned_area = *cell_area;
2696 /* Trim up the aligned size */
2697 if (gtk_cell_renderer_get_request_mode (renderer) == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
2699 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget,
2700 aligned_area->width,
2701 NULL, &opposite_size);
2703 aligned_area->height = MIN (opposite_size, aligned_area->height);
2707 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget,
2708 aligned_area->height,
2709 NULL, &opposite_size);
2711 aligned_area->width = MIN (opposite_size, aligned_area->width);
2714 /* offset the cell position */
2715 _gtk_cell_renderer_calc_offset (renderer, cell_area,
2716 gtk_widget_get_direction (widget),
2717 aligned_area->width,
2718 aligned_area->height,
2719 &x_offset, &y_offset);
2721 aligned_area->x += x_offset;
2722 aligned_area->y += y_offset;
2726 gtk_cell_area_request_renderer (GtkCellArea *area,
2727 GtkCellRenderer *renderer,
2728 GtkOrientation orientation,
2734 GtkCellAreaPrivate *priv;
2736 g_return_if_fail (GTK_IS_CELL_AREA (area));
2737 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2738 g_return_if_fail (GTK_IS_WIDGET (widget));
2739 g_return_if_fail (minimum_size != NULL);
2740 g_return_if_fail (natural_size != NULL);
2744 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2747 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2750 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2752 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2753 minimum_size, natural_size);
2756 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2757 *natural_size += (priv->cell_border.left + priv->cell_border.right);
2759 else /* GTK_ORIENTATION_VERTICAL */
2762 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2765 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2767 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2768 minimum_size, natural_size);
2771 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2772 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);