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 "gtkcellareaiter.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 GtkCellAreaIter *iter,
57 const GdkRectangle *cell_area,
58 GtkCellRendererState flags);
59 static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
60 GtkCellAreaIter *iter,
64 gint *natural_height);
65 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
66 GtkCellAreaIter *iter,
71 static gboolean gtk_cell_area_real_can_focus (GtkCellArea *area);
72 static gboolean gtk_cell_area_real_activate (GtkCellArea *area,
73 GtkCellAreaIter *iter,
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);
100 /* Attribute/Cell metadata */
102 const gchar *attribute;
109 GtkCellLayoutDataFunc func;
111 GDestroyNotify destroy;
114 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
116 GDestroyNotify destroy);
117 static void cell_info_free (CellInfo *info);
118 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
119 const gchar *attribute,
121 static void cell_attribute_free (CellAttribute *attribute);
122 static gint cell_attribute_find (CellAttribute *cell_attribute,
123 const gchar *attribute);
125 /* Internal signal emissions */
126 static void gtk_cell_area_editing_started (GtkCellArea *area,
127 GtkCellRenderer *renderer,
128 GtkCellEditable *editable);
129 static void gtk_cell_area_editing_canceled (GtkCellArea *area,
130 GtkCellRenderer *renderer);
131 static void gtk_cell_area_editing_done (GtkCellArea *area,
132 GtkCellRenderer *renderer,
133 GtkCellEditable *editable);
134 static void gtk_cell_area_remove_editable (GtkCellArea *area,
135 GtkCellRenderer *renderer,
136 GtkCellEditable *editable);
139 /* Struct to pass data along while looping over
140 * cell renderers to apply attributes
146 gboolean is_expander;
147 gboolean is_expanded;
150 struct _GtkCellAreaPrivate
152 /* The GtkCellArea bookkeeps any connected
153 * attributes in this hash table.
155 GHashTable *cell_info;
157 /* The cell border decides how much space to reserve
158 * around each cell for the background_area
160 GtkBorder cell_border;
162 /* Current path is saved as a side-effect
163 * of gtk_cell_area_apply_attributes() */
166 /* Current cell being edited and editable widget used */
167 GtkCellEditable *edit_widget;
168 GtkCellRenderer *edited_cell;
170 /* Signal connections to the editable widget */
171 gulong editing_done_id;
172 gulong remove_widget_id;
174 /* Currently focused cell */
175 GtkCellRenderer *focus_cell;
180 PROP_CELL_MARGIN_LEFT,
181 PROP_CELL_MARGIN_RIGHT,
182 PROP_CELL_MARGIN_TOP,
183 PROP_CELL_MARGIN_BOTTOM,
190 SIGNAL_EDITING_STARTED,
191 SIGNAL_EDITING_CANCELED,
193 SIGNAL_REMOVE_EDITABLE,
197 /* Keep the paramspec pool internal, no need to deliver notifications
198 * on cells. at least no percieved need for now */
199 static GParamSpecPool *cell_property_pool = NULL;
200 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
202 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
203 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
206 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
207 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
208 gtk_cell_area_cell_layout_init));
211 gtk_cell_area_init (GtkCellArea *area)
213 GtkCellAreaPrivate *priv;
215 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
220 priv->cell_info = g_hash_table_new_full (g_direct_hash,
223 (GDestroyNotify)cell_info_free);
225 priv->cell_border.left = 0;
226 priv->cell_border.right = 0;
227 priv->cell_border.top = 0;
228 priv->cell_border.bottom = 0;
230 priv->focus_cell = NULL;
231 priv->edited_cell = NULL;
232 priv->edit_widget = NULL;
234 priv->editing_done_id = 0;
235 priv->remove_widget_id = 0;
239 gtk_cell_area_class_init (GtkCellAreaClass *class)
241 GObjectClass *object_class = G_OBJECT_CLASS (class);
244 object_class->dispose = gtk_cell_area_dispose;
245 object_class->finalize = gtk_cell_area_finalize;
246 object_class->get_property = gtk_cell_area_get_property;
247 object_class->set_property = gtk_cell_area_set_property;
251 class->remove = NULL;
252 class->forall = NULL;
253 class->event = gtk_cell_area_real_event;
254 class->render = NULL;
257 class->create_iter = NULL;
258 class->get_request_mode = NULL;
259 class->get_preferred_width = NULL;
260 class->get_preferred_height = NULL;
261 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
262 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
265 class->can_focus = gtk_cell_area_real_can_focus;
267 class->activate = gtk_cell_area_real_activate;
270 cell_area_signals[SIGNAL_EDITING_STARTED] =
271 g_signal_new (I_("editing-started"),
272 G_OBJECT_CLASS_TYPE (object_class),
274 0, /* No class closure here */
276 _gtk_marshal_VOID__OBJECT_OBJECT_STRING,
278 GTK_TYPE_CELL_RENDERER,
279 GTK_TYPE_CELL_EDITABLE,
282 cell_area_signals[SIGNAL_EDITING_CANCELED] =
283 g_signal_new (I_("editing-canceled"),
284 G_OBJECT_CLASS_TYPE (object_class),
286 0, /* No class closure here */
288 _gtk_marshal_VOID__OBJECT,
290 GTK_TYPE_CELL_RENDERER);
292 cell_area_signals[SIGNAL_EDITING_DONE] =
293 g_signal_new (I_("editing-done"),
294 G_OBJECT_CLASS_TYPE (object_class),
296 0, /* No class closure here */
298 _gtk_marshal_VOID__OBJECT_OBJECT,
300 GTK_TYPE_CELL_RENDERER,
301 GTK_TYPE_CELL_EDITABLE);
303 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
304 g_signal_new (I_("remove-editable"),
305 G_OBJECT_CLASS_TYPE (object_class),
307 0, /* No class closure here */
309 _gtk_marshal_VOID__OBJECT_OBJECT,
311 GTK_TYPE_CELL_RENDERER,
312 GTK_TYPE_CELL_EDITABLE);
315 g_object_class_install_property (object_class,
316 PROP_CELL_MARGIN_LEFT,
319 P_("Margin on Left"),
320 P_("Pixels of extra space on the left side of each cell"),
324 GTK_PARAM_READWRITE));
326 g_object_class_install_property (object_class,
327 PROP_CELL_MARGIN_RIGHT,
329 ("cell-margin-right",
330 P_("Margin on Right"),
331 P_("Pixels of extra space on the right side of each cell"),
335 GTK_PARAM_READWRITE));
337 g_object_class_install_property (object_class,
338 PROP_CELL_MARGIN_TOP,
342 P_("Pixels of extra space on the top side of each cell"),
346 GTK_PARAM_READWRITE));
348 g_object_class_install_property (object_class,
349 PROP_CELL_MARGIN_BOTTOM,
351 ("cell-margin-bottom",
352 P_("Margin on Bottom"),
353 P_("Pixels of extra space on the bottom side of each cell"),
357 GTK_PARAM_READWRITE));
359 g_object_class_install_property (object_class,
364 P_("The cell which currently has focus"),
365 GTK_TYPE_CELL_RENDERER,
366 GTK_PARAM_READWRITE));
368 g_object_class_install_property (object_class,
373 P_("The cell which is currently being edited"),
374 GTK_TYPE_CELL_RENDERER,
375 GTK_PARAM_READWRITE));
377 g_object_class_install_property (object_class,
382 P_("The widget currently editing the edited cell"),
383 GTK_TYPE_CELL_RENDERER,
384 GTK_PARAM_READWRITE));
386 /* Pool for Cell Properties */
387 if (!cell_property_pool)
388 cell_property_pool = g_param_spec_pool_new (FALSE);
390 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
393 /*************************************************************
395 *************************************************************/
397 cell_info_new (GtkCellLayoutDataFunc func,
399 GDestroyNotify destroy)
401 CellInfo *info = g_slice_new (CellInfo);
403 info->attributes = NULL;
406 info->destroy = destroy;
412 cell_info_free (CellInfo *info)
415 info->destroy (info->data);
417 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
418 g_slist_free (info->attributes);
420 g_slice_free (CellInfo, info);
423 static CellAttribute *
424 cell_attribute_new (GtkCellRenderer *renderer,
425 const gchar *attribute,
430 /* Check if the attribute really exists and point to
431 * the property string installed on the cell renderer
432 * class (dont dup the string)
434 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
438 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
440 cell_attribute->attribute = pspec->name;
441 cell_attribute->column = column;
443 return cell_attribute;
450 cell_attribute_free (CellAttribute *attribute)
452 g_slice_free (CellAttribute, attribute);
455 /* GCompareFunc for g_slist_find_custom() */
457 cell_attribute_find (CellAttribute *cell_attribute,
458 const gchar *attribute)
460 return g_strcmp0 (cell_attribute->attribute, attribute);
463 /*************************************************************
465 *************************************************************/
467 gtk_cell_area_finalize (GObject *object)
469 GtkCellArea *area = GTK_CELL_AREA (object);
470 GtkCellAreaPrivate *priv = area->priv;
472 /* All cell renderers should already be removed at this point,
473 * just kill our hash table here.
475 g_hash_table_destroy (priv->cell_info);
477 g_free (priv->current_path);
479 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
484 gtk_cell_area_dispose (GObject *object)
486 /* This removes every cell renderer that may be added to the GtkCellArea,
487 * subclasses should be breaking references to the GtkCellRenderers
490 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
492 /* Remove any ref to a focused/edited cell */
493 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
494 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
495 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
497 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
501 gtk_cell_area_set_property (GObject *object,
506 GtkCellArea *area = GTK_CELL_AREA (object);
510 case PROP_CELL_MARGIN_LEFT:
511 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
513 case PROP_CELL_MARGIN_RIGHT:
514 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
516 case PROP_CELL_MARGIN_TOP:
517 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
519 case PROP_CELL_MARGIN_BOTTOM:
520 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
522 case PROP_FOCUS_CELL:
523 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
525 case PROP_EDITED_CELL:
526 gtk_cell_area_set_edited_cell (area, (GtkCellRenderer *)g_value_get_object (value));
528 case PROP_EDIT_WIDGET:
529 gtk_cell_area_set_edit_widget (area, (GtkCellEditable *)g_value_get_object (value));
532 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
538 gtk_cell_area_get_property (GObject *object,
543 GtkCellArea *area = GTK_CELL_AREA (object);
544 GtkCellAreaPrivate *priv = area->priv;
548 case PROP_CELL_MARGIN_LEFT:
549 g_value_set_int (value, priv->cell_border.left);
551 case PROP_CELL_MARGIN_RIGHT:
552 g_value_set_int (value, priv->cell_border.right);
554 case PROP_CELL_MARGIN_TOP:
555 g_value_set_int (value, priv->cell_border.top);
557 case PROP_CELL_MARGIN_BOTTOM:
558 g_value_set_int (value, priv->cell_border.bottom);
560 case PROP_FOCUS_CELL:
561 g_value_set_object (value, priv->focus_cell);
563 case PROP_EDITED_CELL:
564 g_value_set_object (value, priv->edited_cell);
566 case PROP_EDIT_WIDGET:
567 g_value_set_object (value, priv->edit_widget);
570 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
575 /*************************************************************
577 *************************************************************/
579 gtk_cell_area_real_event (GtkCellArea *area,
580 GtkCellAreaIter *iter,
583 const GdkRectangle *cell_area,
584 GtkCellRendererState flags)
586 GtkCellAreaPrivate *priv = area->priv;
588 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
590 GdkEventKey *key_event = (GdkEventKey *)event;
592 /* Cancel any edits in progress */
593 if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
595 gtk_cell_area_stop_editing (area, TRUE);
604 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
605 GtkCellAreaIter *iter,
608 gint *minimum_height,
609 gint *natural_height)
611 /* If the area doesnt do height-for-width, fallback on base preferred height */
612 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
616 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
617 GtkCellAreaIter *iter,
623 /* If the area doesnt do width-for-height, fallback on base preferred width */
624 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
628 get_can_focus (GtkCellRenderer *renderer,
632 if (gtk_cell_renderer_can_focus (renderer))
637 gtk_cell_area_real_can_focus (GtkCellArea *area)
639 gboolean can_focus = FALSE;
641 /* Checks if any renderer can focus for the currently applied
644 * Subclasses can override this in the case that they are also
645 * rendering widgets as well as renderers.
647 gtk_cell_area_forall (area, (GtkCellCallback)get_can_focus, &can_focus);
653 gtk_cell_area_real_activate (GtkCellArea *area,
654 GtkCellAreaIter *iter,
656 const GdkRectangle *cell_area,
657 GtkCellRendererState flags)
659 GtkCellAreaPrivate *priv = area->priv;
660 GdkRectangle background_area;
662 if (priv->focus_cell)
664 /* Get the allocation of the focused cell.
666 gtk_cell_area_get_cell_allocation (area, iter, widget, priv->focus_cell,
667 cell_area, &background_area);
669 /* Activate or Edit the currently focused cell
671 * Currently just not sending an event, renderers afaics dont use
672 * the event argument anyway, worst case is we can synthesize one.
674 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, NULL,
675 &background_area, flags))
682 /*************************************************************
683 * GtkCellLayoutIface *
684 *************************************************************/
686 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
688 iface->pack_start = gtk_cell_area_pack_default;
689 iface->pack_end = gtk_cell_area_pack_default;
690 iface->clear = gtk_cell_area_clear;
691 iface->add_attribute = gtk_cell_area_add_attribute;
692 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
693 iface->clear_attributes = gtk_cell_area_clear_attributes;
694 iface->reorder = gtk_cell_area_reorder;
695 iface->get_cells = gtk_cell_area_get_cells;
699 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
700 GtkCellRenderer *renderer,
703 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
707 gtk_cell_area_clear (GtkCellLayout *cell_layout)
709 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
711 gtk_cell_layout_get_cells (cell_layout);
713 for (l = cells; l; l = l->next)
715 GtkCellRenderer *renderer = l->data;
716 gtk_cell_area_remove (area, renderer);
723 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
724 GtkCellRenderer *renderer,
725 const gchar *attribute,
728 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
729 renderer, attribute, column);
733 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
734 GtkCellRenderer *renderer,
735 GtkCellLayoutDataFunc func,
737 GDestroyNotify destroy)
739 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
740 GtkCellAreaPrivate *priv = area->priv;
743 info = g_hash_table_lookup (priv->cell_info, renderer);
747 if (info->destroy && info->data)
748 info->destroy (info->data);
753 info->data = func_data;
754 info->destroy = destroy;
760 info->destroy = NULL;
765 info = cell_info_new (func, func_data, destroy);
767 g_hash_table_insert (priv->cell_info, renderer, info);
772 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
773 GtkCellRenderer *renderer)
775 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
776 GtkCellAreaPrivate *priv = area->priv;
779 info = g_hash_table_lookup (priv->cell_info, renderer);
783 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
784 g_slist_free (info->attributes);
786 info->attributes = NULL;
791 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
792 GtkCellRenderer *cell,
795 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
796 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
800 accum_cells (GtkCellRenderer *renderer,
803 *accum = g_list_prepend (*accum, renderer);
807 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
811 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
812 (GtkCellCallback)accum_cells,
815 return g_list_reverse (cells);
819 /*************************************************************
821 *************************************************************/
825 * @area: a #GtkCellArea
826 * @renderer: the #GtkCellRenderer to add to @area
828 * Adds @renderer to @area with the default child cell properties.
831 gtk_cell_area_add (GtkCellArea *area,
832 GtkCellRenderer *renderer)
834 GtkCellAreaClass *class;
836 g_return_if_fail (GTK_IS_CELL_AREA (area));
837 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
839 class = GTK_CELL_AREA_GET_CLASS (area);
842 class->add (area, renderer);
844 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
845 g_type_name (G_TYPE_FROM_INSTANCE (area)));
849 * gtk_cell_area_remove:
850 * @area: a #GtkCellArea
851 * @renderer: the #GtkCellRenderer to add to @area
853 * Removes @renderer from @area.
856 gtk_cell_area_remove (GtkCellArea *area,
857 GtkCellRenderer *renderer)
859 GtkCellAreaClass *class;
860 GtkCellAreaPrivate *priv;
862 g_return_if_fail (GTK_IS_CELL_AREA (area));
863 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
865 class = GTK_CELL_AREA_GET_CLASS (area);
868 /* Remove any custom attributes and custom cell data func here first */
869 g_hash_table_remove (priv->cell_info, renderer);
872 class->remove (area, renderer);
874 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
875 g_type_name (G_TYPE_FROM_INSTANCE (area)));
879 * gtk_cell_area_forall
880 * @area: a #GtkCellArea
881 * @callback: the #GtkCellCallback to call
882 * @callback_data: user provided data pointer
884 * Calls @callback for every #GtkCellRenderer in @area.
887 gtk_cell_area_forall (GtkCellArea *area,
888 GtkCellCallback callback,
889 gpointer callback_data)
891 GtkCellAreaClass *class;
893 g_return_if_fail (GTK_IS_CELL_AREA (area));
894 g_return_if_fail (callback != NULL);
896 class = GTK_CELL_AREA_GET_CLASS (area);
899 class->forall (area, callback, callback_data);
901 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
902 g_type_name (G_TYPE_FROM_INSTANCE (area)));
906 * gtk_cell_area_get_cell_allocation:
907 * @area: a #GtkCellArea
908 * @iter: the #GtkCellAreaIter used to hold sizes for @area.
909 * @widget: the #GtkWidget that @area is rendering on
910 * @renderer: the #GtkCellRenderer to get the allocation for
911 * @cell_area: the whole allocated area for @area in @widget
913 * @allocation: where to store the allocation for @renderer
915 * Derives the allocation of @renderer inside @area if @area
916 * were to be renderered in @cell_area.
919 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
920 GtkCellAreaIter *iter,
922 GtkCellRenderer *renderer,
923 const GdkRectangle *cell_area,
924 GdkRectangle *allocation)
926 GtkCellAreaClass *class;
928 g_return_if_fail (GTK_IS_CELL_AREA (area));
929 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
930 g_return_if_fail (GTK_IS_WIDGET (widget));
931 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
932 g_return_if_fail (cell_area != NULL);
933 g_return_if_fail (allocation != NULL);
935 class = GTK_CELL_AREA_GET_CLASS (area);
937 if (class->get_cell_allocation)
938 class->get_cell_allocation (area, iter, widget, renderer, cell_area, allocation);
940 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
941 g_type_name (G_TYPE_FROM_INSTANCE (area)));
945 gtk_cell_area_event (GtkCellArea *area,
946 GtkCellAreaIter *iter,
949 const GdkRectangle *cell_area,
950 GtkCellRendererState flags)
952 GtkCellAreaClass *class;
954 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
955 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
956 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
957 g_return_val_if_fail (event != NULL, 0);
958 g_return_val_if_fail (cell_area != NULL, 0);
960 class = GTK_CELL_AREA_GET_CLASS (area);
963 return class->event (area, iter, widget, event, cell_area, flags);
965 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
966 g_type_name (G_TYPE_FROM_INSTANCE (area)));
971 gtk_cell_area_render (GtkCellArea *area,
972 GtkCellAreaIter *iter,
975 const GdkRectangle *cell_area,
976 GtkCellRendererState flags)
978 GtkCellAreaClass *class;
980 g_return_if_fail (GTK_IS_CELL_AREA (area));
981 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
982 g_return_if_fail (GTK_IS_WIDGET (widget));
983 g_return_if_fail (cr != NULL);
984 g_return_if_fail (cell_area != NULL);
986 class = GTK_CELL_AREA_GET_CLASS (area);
989 class->render (area, iter, widget, cr, cell_area, flags);
991 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
992 g_type_name (G_TYPE_FROM_INSTANCE (area)));
995 /*************************************************************
997 *************************************************************/
999 gtk_cell_area_create_iter (GtkCellArea *area)
1001 GtkCellAreaClass *class;
1003 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1005 class = GTK_CELL_AREA_GET_CLASS (area);
1007 if (class->create_iter)
1008 return class->create_iter (area);
1010 g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'",
1011 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1018 gtk_cell_area_get_request_mode (GtkCellArea *area)
1020 GtkCellAreaClass *class;
1022 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1023 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1025 class = GTK_CELL_AREA_GET_CLASS (area);
1027 if (class->get_request_mode)
1028 return class->get_request_mode (area);
1030 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1031 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1033 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1037 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1038 GtkCellAreaIter *iter,
1043 GtkCellAreaClass *class;
1045 g_return_if_fail (GTK_IS_CELL_AREA (area));
1046 g_return_if_fail (GTK_IS_WIDGET (widget));
1048 class = GTK_CELL_AREA_GET_CLASS (area);
1050 if (class->get_preferred_width)
1051 class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
1053 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1054 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1058 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1059 GtkCellAreaIter *iter,
1062 gint *minimum_height,
1063 gint *natural_height)
1065 GtkCellAreaClass *class;
1067 g_return_if_fail (GTK_IS_CELL_AREA (area));
1068 g_return_if_fail (GTK_IS_WIDGET (widget));
1070 class = GTK_CELL_AREA_GET_CLASS (area);
1071 class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
1075 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1076 GtkCellAreaIter *iter,
1081 GtkCellAreaClass *class;
1083 g_return_if_fail (GTK_IS_CELL_AREA (area));
1084 g_return_if_fail (GTK_IS_WIDGET (widget));
1086 class = GTK_CELL_AREA_GET_CLASS (area);
1088 if (class->get_preferred_height)
1089 class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
1091 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1092 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1096 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1097 GtkCellAreaIter *iter,
1100 gint *minimum_width,
1101 gint *natural_width)
1103 GtkCellAreaClass *class;
1105 g_return_if_fail (GTK_IS_CELL_AREA (area));
1106 g_return_if_fail (GTK_IS_WIDGET (widget));
1108 class = GTK_CELL_AREA_GET_CLASS (area);
1109 class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
1112 /*************************************************************
1114 *************************************************************/
1117 * gtk_cell_area_attribute_connect:
1118 * @area: a #GtkCellArea
1119 * @renderer: the #GtkCellRenderer to connect an attribute for
1120 * @attribute: the attribute name
1121 * @column: the #GtkTreeModel column to fetch attribute values from
1123 * Connects an @attribute to apply values from @column for the
1124 * #GtkTreeModel in use.
1127 gtk_cell_area_attribute_connect (GtkCellArea *area,
1128 GtkCellRenderer *renderer,
1129 const gchar *attribute,
1132 GtkCellAreaPrivate *priv;
1134 CellAttribute *cell_attribute;
1136 g_return_if_fail (GTK_IS_CELL_AREA (area));
1137 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1138 g_return_if_fail (attribute != NULL);
1141 info = g_hash_table_lookup (priv->cell_info, renderer);
1145 info = cell_info_new (NULL, NULL, NULL);
1147 g_hash_table_insert (priv->cell_info, renderer, info);
1153 /* Check we are not adding the same attribute twice */
1154 if ((node = g_slist_find_custom (info->attributes, attribute,
1155 (GCompareFunc)cell_attribute_find)) != NULL)
1157 cell_attribute = node->data;
1159 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1160 "since `%s' is already attributed to column %d",
1162 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1163 attribute, cell_attribute->column);
1168 cell_attribute = cell_attribute_new (renderer, attribute, column);
1170 if (!cell_attribute)
1172 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1173 "since attribute does not exist",
1175 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1179 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1183 * gtk_cell_area_attribute_disconnect:
1184 * @area: a #GtkCellArea
1185 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1186 * @attribute: the attribute name
1188 * Disconnects @attribute for the @renderer in @area so that
1189 * attribute will no longer be updated with values from the
1193 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1194 GtkCellRenderer *renderer,
1195 const gchar *attribute)
1197 GtkCellAreaPrivate *priv;
1199 CellAttribute *cell_attribute;
1202 g_return_if_fail (GTK_IS_CELL_AREA (area));
1203 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1204 g_return_if_fail (attribute != NULL);
1207 info = g_hash_table_lookup (priv->cell_info, renderer);
1211 node = g_slist_find_custom (info->attributes, attribute,
1212 (GCompareFunc)cell_attribute_find);
1215 cell_attribute = node->data;
1217 cell_attribute_free (cell_attribute);
1219 info->attributes = g_slist_delete_link (info->attributes, node);
1225 apply_cell_attributes (GtkCellRenderer *renderer,
1227 AttributeData *data)
1229 CellAttribute *attribute;
1231 GValue value = { 0, };
1232 gboolean is_expander;
1233 gboolean is_expanded;
1235 g_object_freeze_notify (G_OBJECT (renderer));
1237 /* Whether a row expands or is presently expanded can only be
1238 * provided by the view (as these states can vary across views
1239 * accessing the same model).
1241 g_object_get (renderer, "is-expander", &is_expander, NULL);
1242 if (is_expander != data->is_expander)
1243 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1245 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1246 if (is_expanded != data->is_expanded)
1247 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1249 /* Apply the attributes directly to the renderer */
1250 for (list = info->attributes; list; list = list->next)
1252 attribute = list->data;
1254 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1255 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1256 g_value_unset (&value);
1259 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1262 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1263 data->model, data->iter, info->data);
1265 g_object_thaw_notify (G_OBJECT (renderer));
1269 * gtk_cell_area_apply_attributes
1270 * @area: a #GtkCellArea
1271 * @tree_model: a #GtkTreeModel to pull values from
1272 * @iter: the #GtkTreeIter in @tree_model to apply values for
1273 * @is_expander: whether @iter has children
1274 * @is_expanded: whether @iter is expanded in the view and
1275 * children are visible
1277 * Applies any connected attributes to the renderers in
1278 * @area by pulling the values from @tree_model.
1281 gtk_cell_area_apply_attributes (GtkCellArea *area,
1282 GtkTreeModel *tree_model,
1284 gboolean is_expander,
1285 gboolean is_expanded)
1287 GtkCellAreaPrivate *priv;
1291 g_return_if_fail (GTK_IS_CELL_AREA (area));
1292 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1293 g_return_if_fail (iter != NULL);
1297 /* Feed in data needed to apply to every renderer */
1299 data.model = tree_model;
1301 data.is_expander = is_expander;
1302 data.is_expanded = is_expanded;
1304 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1305 * apply the data from the treemodel */
1306 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1308 /* Update the currently applied path */
1309 g_free (priv->current_path);
1310 path = gtk_tree_model_get_path (tree_model, iter);
1311 priv->current_path = gtk_tree_path_to_string (path);
1312 gtk_tree_path_free (path);
1316 * gtk_cell_area_get_current_path_string:
1317 * @area: a #GtkCellArea
1319 * Gets the current #GtkTreePath string for the currently
1320 * applied #GtkTreeIter, this is implicitly updated when
1321 * gtk_cell_area_apply_attributes() is called and can be
1322 * used to interact with renderers from #GtkCellArea
1326 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1328 GtkCellAreaPrivate *priv;
1330 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1334 return priv->current_path;
1338 /*************************************************************
1339 * API: Cell Properties *
1340 *************************************************************/
1342 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1346 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1347 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1348 if (pspec->flags & G_PARAM_WRITABLE)
1349 g_return_if_fail (aclass->set_cell_property != NULL);
1350 if (pspec->flags & G_PARAM_READABLE)
1351 g_return_if_fail (aclass->get_cell_property != NULL);
1352 g_return_if_fail (property_id > 0);
1353 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1354 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1356 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1358 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1359 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1362 g_param_spec_ref (pspec);
1363 g_param_spec_sink (pspec);
1364 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1365 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1369 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1370 const gchar *property_name)
1372 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1373 g_return_val_if_fail (property_name != NULL, NULL);
1375 return g_param_spec_pool_lookup (cell_property_pool,
1377 G_OBJECT_CLASS_TYPE (aclass),
1382 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1383 guint *n_properties)
1385 GParamSpec **pspecs;
1388 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1390 pspecs = g_param_spec_pool_list (cell_property_pool,
1391 G_OBJECT_CLASS_TYPE (aclass),
1400 gtk_cell_area_add_with_properties (GtkCellArea *area,
1401 GtkCellRenderer *renderer,
1402 const gchar *first_prop_name,
1405 GtkCellAreaClass *class;
1407 g_return_if_fail (GTK_IS_CELL_AREA (area));
1408 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1410 class = GTK_CELL_AREA_GET_CLASS (area);
1416 class->add (area, renderer);
1418 va_start (var_args, first_prop_name);
1419 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1423 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1424 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1428 gtk_cell_area_cell_set (GtkCellArea *area,
1429 GtkCellRenderer *renderer,
1430 const gchar *first_prop_name,
1435 g_return_if_fail (GTK_IS_CELL_AREA (area));
1436 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1438 va_start (var_args, first_prop_name);
1439 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1444 gtk_cell_area_cell_get (GtkCellArea *area,
1445 GtkCellRenderer *renderer,
1446 const gchar *first_prop_name,
1451 g_return_if_fail (GTK_IS_CELL_AREA (area));
1452 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1454 va_start (var_args, first_prop_name);
1455 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1460 area_get_cell_property (GtkCellArea *area,
1461 GtkCellRenderer *renderer,
1465 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1467 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1471 area_set_cell_property (GtkCellArea *area,
1472 GtkCellRenderer *renderer,
1474 const GValue *value)
1476 GValue tmp_value = { 0, };
1477 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1479 /* provide a copy to work from, convert (if necessary) and validate */
1480 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1481 if (!g_value_transform (value, &tmp_value))
1482 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1484 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1485 G_VALUE_TYPE_NAME (value));
1486 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1488 gchar *contents = g_strdup_value_contents (value);
1490 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1492 G_VALUE_TYPE_NAME (value),
1494 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1499 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1501 g_value_unset (&tmp_value);
1505 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1506 GtkCellRenderer *renderer,
1507 const gchar *first_property_name,
1512 g_return_if_fail (GTK_IS_CELL_AREA (area));
1513 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1515 name = first_property_name;
1518 GValue value = { 0, };
1519 gchar *error = NULL;
1521 g_param_spec_pool_lookup (cell_property_pool, name,
1522 G_OBJECT_TYPE (area), TRUE);
1525 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1526 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1529 if (!(pspec->flags & G_PARAM_WRITABLE))
1531 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1532 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1536 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1537 G_VALUE_COLLECT (&value, var_args, 0, &error);
1540 g_warning ("%s: %s", G_STRLOC, error);
1543 /* we purposely leak the value here, it might not be
1544 * in a sane state if an error condition occoured
1548 area_set_cell_property (area, renderer, pspec, &value);
1549 g_value_unset (&value);
1550 name = va_arg (var_args, gchar*);
1555 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1556 GtkCellRenderer *renderer,
1557 const gchar *first_property_name,
1562 g_return_if_fail (GTK_IS_CELL_AREA (area));
1563 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1565 name = first_property_name;
1568 GValue value = { 0, };
1572 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1573 G_OBJECT_TYPE (area), TRUE);
1576 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1577 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1580 if (!(pspec->flags & G_PARAM_READABLE))
1582 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1583 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1587 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1588 area_get_cell_property (area, renderer, pspec, &value);
1589 G_VALUE_LCOPY (&value, var_args, 0, &error);
1592 g_warning ("%s: %s", G_STRLOC, error);
1594 g_value_unset (&value);
1597 g_value_unset (&value);
1598 name = va_arg (var_args, gchar*);
1603 gtk_cell_area_cell_set_property (GtkCellArea *area,
1604 GtkCellRenderer *renderer,
1605 const gchar *property_name,
1606 const GValue *value)
1610 g_return_if_fail (GTK_IS_CELL_AREA (area));
1611 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1612 g_return_if_fail (property_name != NULL);
1613 g_return_if_fail (G_IS_VALUE (value));
1615 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1616 G_OBJECT_TYPE (area), TRUE);
1618 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1619 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1620 else if (!(pspec->flags & G_PARAM_WRITABLE))
1621 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1622 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1625 area_set_cell_property (area, renderer, pspec, value);
1630 gtk_cell_area_cell_get_property (GtkCellArea *area,
1631 GtkCellRenderer *renderer,
1632 const gchar *property_name,
1637 g_return_if_fail (GTK_IS_CELL_AREA (area));
1638 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1639 g_return_if_fail (property_name != NULL);
1640 g_return_if_fail (G_IS_VALUE (value));
1642 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1643 G_OBJECT_TYPE (area), TRUE);
1645 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1646 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1647 else if (!(pspec->flags & G_PARAM_READABLE))
1648 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1649 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1652 GValue *prop_value, tmp_value = { 0, };
1654 /* auto-conversion of the callers value type
1656 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1658 g_value_reset (value);
1661 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1663 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1665 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1666 G_VALUE_TYPE_NAME (value));
1671 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1672 prop_value = &tmp_value;
1675 area_get_cell_property (area, renderer, pspec, prop_value);
1677 if (prop_value != value)
1679 g_value_transform (prop_value, value);
1680 g_value_unset (&tmp_value);
1685 /*************************************************************
1687 *************************************************************/
1690 * gtk_cell_area_can_focus:
1691 * @area: a #GtkCellArea
1693 * Returns whether the area can receive keyboard focus,
1694 * after applying new attributes to @area.
1696 * Returns: whether @area can receive focus.
1699 gtk_cell_area_can_focus (GtkCellArea *area)
1701 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1703 return GTK_CELL_AREA_GET_CLASS (area)->can_focus (area);
1707 * gtk_cell_area_focus:
1708 * @area: a #GtkCellArea
1709 * @direction: the #GtkDirectionType
1711 * This should be called by the @area's owning layout widget
1712 * when focus is to be passed to @area, or moved within @area
1713 * for a given @direction and row data.
1715 * Implementing #GtkCellArea classes should implement this
1716 * method to receive and navigate focus in it's own way particular
1717 * to how it lays out cells.
1719 * Returns: %TRUE if focus remains inside @area as a result of this call.
1722 gtk_cell_area_focus (GtkCellArea *area,
1723 GtkDirectionType direction)
1725 GtkCellAreaClass *class;
1727 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1729 class = GTK_CELL_AREA_GET_CLASS (area);
1732 return class->focus (area, direction);
1734 g_warning ("GtkCellAreaClass::focus not implemented for `%s'",
1735 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1741 * gtk_cell_area_activate:
1742 * @area: a #GtkCellArea
1743 * @iter: the #GtkCellAreaIter in context with the current row data
1744 * @widget: the #GtkWidget that @area is rendering on
1745 * @cell_area: the size and location of @area relative to @widget's allocation
1746 * @flags: the #GtkCellRendererState flags for @area for this row of data.
1748 * Activates @area, usually by activating the currently focused
1749 * cell, however some subclasses which embed widgets in the area
1750 * can also activate a widget if it currently has the focus.
1752 * Returns: Whether @area was successfully activated.
1755 gtk_cell_area_activate (GtkCellArea *area,
1756 GtkCellAreaIter *iter,
1758 const GdkRectangle *cell_area,
1759 GtkCellRendererState flags)
1761 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1763 return GTK_CELL_AREA_GET_CLASS (area)->activate (area, iter, widget, cell_area, flags);
1768 * gtk_cell_area_set_focus_cell:
1769 * @area: a #GtkCellArea
1770 * @focus_cell: the #GtkCellRenderer to give focus to
1772 * This is generally called from #GtkCellArea implementations
1773 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
1774 * is called. It's also up to the #GtkCellArea implementation
1775 * to update the focused cell when receiving events from
1776 * gtk_cell_area_event() appropriately.
1779 gtk_cell_area_set_focus_cell (GtkCellArea *area,
1780 GtkCellRenderer *renderer)
1782 GtkCellAreaPrivate *priv;
1784 g_return_if_fail (GTK_IS_CELL_AREA (area));
1785 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1789 if (priv->focus_cell != renderer)
1791 if (priv->focus_cell)
1792 g_object_unref (priv->focus_cell);
1794 priv->focus_cell = renderer;
1796 if (priv->focus_cell)
1797 g_object_ref (priv->focus_cell);
1799 g_object_notify (G_OBJECT (area), "focus-cell");
1804 * gtk_cell_area_get_focus_cell:
1805 * @area: a #GtkCellArea
1807 * Retrieves the currently focused cell for @area
1809 * Returns: the currently focused cell in @area.
1812 gtk_cell_area_get_focus_cell (GtkCellArea *area)
1814 GtkCellAreaPrivate *priv;
1816 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1820 return priv->focus_cell;
1824 /*************************************************************
1825 * API: Cell Activation/Editing *
1826 *************************************************************/
1828 gtk_cell_area_editing_started (GtkCellArea *area,
1829 GtkCellRenderer *renderer,
1830 GtkCellEditable *editable)
1832 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0,
1833 renderer, editable, area->priv->current_path);
1837 gtk_cell_area_editing_canceled (GtkCellArea *area,
1838 GtkCellRenderer *renderer)
1840 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_CANCELED], 0, renderer);
1844 gtk_cell_area_editing_done (GtkCellArea *area,
1845 GtkCellRenderer *renderer,
1846 GtkCellEditable *editable)
1848 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_DONE], 0, renderer, editable);
1852 gtk_cell_area_remove_editable (GtkCellArea *area,
1853 GtkCellRenderer *renderer,
1854 GtkCellEditable *editable)
1856 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
1860 cell_area_editing_done_cb (GtkCellEditable *editable,
1863 GtkCellAreaPrivate *priv = area->priv;
1865 g_assert (priv->edit_widget == editable);
1866 g_assert (priv->edited_cell != NULL);
1868 gtk_cell_area_editing_done (area, priv->edited_cell, priv->edit_widget);
1872 cell_area_remove_widget_cb (GtkCellEditable *editable,
1875 GtkCellAreaPrivate *priv = area->priv;
1877 g_assert (priv->edit_widget == editable);
1878 g_assert (priv->edited_cell != NULL);
1880 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
1882 /* Now that we're done with editing the widget and it can be removed,
1883 * remove our references to the widget and disconnect handlers */
1884 gtk_cell_area_set_edited_cell (area, NULL);
1885 gtk_cell_area_set_edit_widget (area, NULL);
1889 gtk_cell_area_set_edited_cell (GtkCellArea *area,
1890 GtkCellRenderer *renderer)
1892 GtkCellAreaPrivate *priv;
1894 g_return_if_fail (GTK_IS_CELL_AREA (area));
1895 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1899 if (priv->edited_cell != renderer)
1901 if (priv->edited_cell)
1902 g_object_unref (priv->edited_cell);
1904 priv->edited_cell = renderer;
1906 if (priv->edited_cell)
1907 g_object_ref (priv->edited_cell);
1909 g_object_notify (G_OBJECT (area), "edited-cell");
1914 gtk_cell_area_get_edited_cell (GtkCellArea *area)
1916 GtkCellAreaPrivate *priv;
1918 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1922 return priv->edited_cell;
1926 gtk_cell_area_set_edit_widget (GtkCellArea *area,
1927 GtkCellEditable *editable)
1929 GtkCellAreaPrivate *priv;
1931 g_return_if_fail (GTK_IS_CELL_AREA (area));
1932 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
1936 if (priv->edit_widget != editable)
1938 if (priv->edit_widget)
1940 g_signal_handler_disconnect (priv->edit_widget, priv->editing_done_id);
1941 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
1943 g_object_unref (priv->edit_widget);
1946 priv->edit_widget = editable;
1948 if (priv->edit_widget)
1950 priv->editing_done_id =
1951 g_signal_connect (priv->edit_widget, "editing-done",
1952 G_CALLBACK (cell_area_editing_done_cb), area);
1953 priv->remove_widget_id =
1954 g_signal_connect (priv->edit_widget, "remove-widget",
1955 G_CALLBACK (cell_area_remove_widget_cb), area);
1957 g_object_ref (priv->edit_widget);
1960 g_object_notify (G_OBJECT (area), "edit-widget");
1965 gtk_cell_area_get_edit_widget (GtkCellArea *area)
1967 GtkCellAreaPrivate *priv;
1969 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1973 return priv->edit_widget;
1977 gtk_cell_area_activate_cell (GtkCellArea *area,
1979 GtkCellRenderer *renderer,
1981 const GdkRectangle *cell_area,
1982 GtkCellRendererState flags)
1984 GtkCellRendererMode mode;
1985 GdkRectangle inner_area;
1986 GtkCellAreaPrivate *priv;
1988 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1989 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
1990 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
1991 g_return_val_if_fail (cell_area != NULL, FALSE);
1995 /* Remove margins from the background area to produce the cell area.
1997 * XXX Maybe have to do some rtl mode treatment here...
1999 gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
2001 g_object_get (renderer, "mode", &mode, NULL);
2003 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2005 if (gtk_cell_renderer_activate (renderer,
2013 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2015 GtkCellEditable *editable_widget;
2018 gtk_cell_renderer_start_editing (renderer,
2025 if (editable_widget != NULL)
2027 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2029 gtk_cell_area_set_edited_cell (area, renderer);
2030 gtk_cell_area_set_edit_widget (area, editable_widget);
2032 /* Signal that editing started so that callers can get
2033 * a handle on the editable_widget */
2034 gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
2044 gtk_cell_area_stop_editing (GtkCellArea *area,
2047 GtkCellAreaPrivate *priv;
2049 g_return_if_fail (GTK_IS_CELL_AREA (area));
2053 if (priv->edited_cell)
2055 /* Stop editing of the cell renderer */
2056 gtk_cell_renderer_stop_editing (priv->edited_cell, canceled);
2058 /* Signal that editing has been canceled */
2060 gtk_cell_area_editing_canceled (area, priv->edited_cell);
2062 /* Remove any references to the editable widget */
2063 gtk_cell_area_set_edited_cell (area, NULL);
2064 gtk_cell_area_set_edit_widget (area, NULL);
2068 /*************************************************************
2070 *************************************************************/
2072 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
2074 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2076 return area->priv->cell_border.left;
2080 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
2083 GtkCellAreaPrivate *priv;
2085 g_return_if_fail (GTK_IS_CELL_AREA (area));
2089 if (priv->cell_border.left != margin)
2091 priv->cell_border.left = margin;
2093 g_object_notify (G_OBJECT (area), "margin-left");
2098 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
2100 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2102 return area->priv->cell_border.right;
2106 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
2109 GtkCellAreaPrivate *priv;
2111 g_return_if_fail (GTK_IS_CELL_AREA (area));
2115 if (priv->cell_border.right != margin)
2117 priv->cell_border.right = margin;
2119 g_object_notify (G_OBJECT (area), "margin-right");
2124 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
2126 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2128 return area->priv->cell_border.top;
2132 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
2135 GtkCellAreaPrivate *priv;
2137 g_return_if_fail (GTK_IS_CELL_AREA (area));
2141 if (priv->cell_border.top != margin)
2143 priv->cell_border.top = margin;
2145 g_object_notify (G_OBJECT (area), "margin-top");
2150 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
2152 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2154 return area->priv->cell_border.bottom;
2158 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
2161 GtkCellAreaPrivate *priv;
2163 g_return_if_fail (GTK_IS_CELL_AREA (area));
2167 if (priv->cell_border.bottom != margin)
2169 priv->cell_border.bottom = margin;
2171 g_object_notify (G_OBJECT (area), "margin-bottom");
2176 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2177 const GdkRectangle *background_area,
2178 GdkRectangle *cell_area)
2180 GtkCellAreaPrivate *priv;
2182 g_return_if_fail (GTK_IS_CELL_AREA (area));
2183 g_return_if_fail (background_area != NULL);
2184 g_return_if_fail (cell_area != NULL);
2188 *cell_area = *background_area;
2190 cell_area->x += priv->cell_border.left;
2191 cell_area->width -= (priv->cell_border.left + priv->cell_border.right);
2192 cell_area->y += priv->cell_border.top;
2193 cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2197 gtk_cell_area_request_renderer (GtkCellArea *area,
2198 GtkCellRenderer *renderer,
2199 GtkOrientation orientation,
2205 GtkCellAreaPrivate *priv;
2207 g_return_if_fail (GTK_IS_CELL_AREA (area));
2208 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2209 g_return_if_fail (GTK_IS_WIDGET (widget));
2210 g_return_if_fail (minimum_size != NULL);
2211 g_return_if_fail (natural_size != NULL);
2215 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2218 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2221 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2223 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2224 minimum_size, natural_size);
2227 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2228 *natural_size += (priv->cell_border.left + priv->cell_border.right);
2230 else /* GTK_ORIENTATION_VERTICAL */
2233 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2236 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2238 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2239 minimum_size, natural_size);
2242 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2243 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);