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 void gtk_cell_area_real_update_focus (GtkCellArea *area);
73 /* GtkCellLayoutIface */
74 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
75 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
76 GtkCellRenderer *renderer,
78 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
79 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
80 GtkCellRenderer *renderer,
81 const gchar *attribute,
83 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
84 GtkCellRenderer *cell,
85 GtkCellLayoutDataFunc func,
87 GDestroyNotify destroy);
88 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
89 GtkCellRenderer *renderer);
90 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
91 GtkCellRenderer *cell,
93 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
95 /* Attribute/Cell metadata */
97 const gchar *attribute;
104 GtkCellLayoutDataFunc func;
106 GDestroyNotify destroy;
109 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
111 GDestroyNotify destroy);
112 static void cell_info_free (CellInfo *info);
113 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
114 const gchar *attribute,
116 static void cell_attribute_free (CellAttribute *attribute);
117 static gint cell_attribute_find (CellAttribute *cell_attribute,
118 const gchar *attribute);
120 /* Struct to pass data along while looping over
121 * cell renderers to apply attributes
127 gboolean is_expander;
128 gboolean is_expanded;
131 struct _GtkCellAreaPrivate
133 /* The GtkCellArea bookkeeps any connected
134 * attributes in this hash table.
136 GHashTable *cell_info;
138 /* The cell border decides how much space to reserve
139 * around each cell for the background_area
141 GtkBorder cell_border;
143 /* Current path is saved as a side-effect
144 * of gtk_cell_area_apply_attributes() */
147 GtkCellRenderer *edited_cell;
148 GtkCellRenderer *focus_cell;
155 PROP_CELL_MARGIN_LEFT,
156 PROP_CELL_MARGIN_RIGHT,
157 PROP_CELL_MARGIN_TOP,
158 PROP_CELL_MARGIN_BOTTOM,
165 SIGNAL_EDITING_STARTED,
169 /* Keep the paramspec pool internal, no need to deliver notifications
170 * on cells. at least no percieved need for now */
171 static GParamSpecPool *cell_property_pool = NULL;
172 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
174 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
175 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
178 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
179 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
180 gtk_cell_area_cell_layout_init));
183 gtk_cell_area_init (GtkCellArea *area)
185 GtkCellAreaPrivate *priv;
187 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
192 priv->cell_info = g_hash_table_new_full (g_direct_hash,
195 (GDestroyNotify)cell_info_free);
197 priv->cell_border.left = 0;
198 priv->cell_border.right = 0;
199 priv->cell_border.top = 0;
200 priv->cell_border.bottom = 0;
202 priv->focus_cell = NULL;
206 gtk_cell_area_class_init (GtkCellAreaClass *class)
208 GObjectClass *object_class = G_OBJECT_CLASS (class);
211 object_class->dispose = gtk_cell_area_dispose;
212 object_class->finalize = gtk_cell_area_finalize;
213 object_class->get_property = gtk_cell_area_get_property;
214 object_class->set_property = gtk_cell_area_set_property;
218 class->remove = NULL;
219 class->forall = NULL;
220 class->event = gtk_cell_area_real_event;
221 class->render = NULL;
224 class->create_iter = NULL;
225 class->get_request_mode = NULL;
226 class->get_preferred_width = NULL;
227 class->get_preferred_height = NULL;
228 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
229 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
232 class->grab_focus = NULL;
233 class->update_focus = gtk_cell_area_real_update_focus;
236 cell_area_signals[SIGNAL_FOCUS_LEAVE] =
237 g_signal_new (I_("focus-leave"),
238 G_TYPE_FROM_CLASS (object_class),
240 0, /* Class offset (just a notification, no class handler) */
242 _gtk_marshal_VOID__ENUM_STRING,
244 GTK_TYPE_DIRECTION_TYPE, G_TYPE_STRING);
246 cell_area_signals[SIGNAL_EDITING_STARTED] =
247 g_signal_new (I_("editing-started"),
248 G_OBJECT_CLASS_TYPE (object_class),
250 0, /* No class closure here */
252 _gtk_marshal_VOID__OBJECT_OBJECT_STRING,
254 GTK_TYPE_CELL_RENDERER,
255 GTK_TYPE_CELL_EDITABLE,
259 g_object_class_install_property (object_class,
260 PROP_CELL_MARGIN_LEFT,
263 P_("Margin on Left"),
264 P_("Pixels of extra space on the left side of each cell"),
268 GTK_PARAM_READWRITE));
270 g_object_class_install_property (object_class,
271 PROP_CELL_MARGIN_RIGHT,
273 ("cell-margin-right",
274 P_("Margin on Right"),
275 P_("Pixels of extra space on the right side of each cell"),
279 GTK_PARAM_READWRITE));
281 g_object_class_install_property (object_class,
282 PROP_CELL_MARGIN_TOP,
286 P_("Pixels of extra space on the top side of each cell"),
290 GTK_PARAM_READWRITE));
292 g_object_class_install_property (object_class,
293 PROP_CELL_MARGIN_BOTTOM,
295 ("cell-margin-bottom",
296 P_("Margin on Bottom"),
297 P_("Pixels of extra space on the bottom side of each cell"),
301 GTK_PARAM_READWRITE));
303 g_object_class_install_property (object_class,
308 P_("The cell which currently has focus"),
309 GTK_TYPE_CELL_RENDERER,
310 GTK_PARAM_READWRITE));
312 g_object_class_install_property (object_class,
317 P_("The cell which is currently being edited"),
318 GTK_TYPE_CELL_RENDERER,
319 GTK_PARAM_READWRITE));
321 /* Pool for Cell Properties */
322 if (!cell_property_pool)
323 cell_property_pool = g_param_spec_pool_new (FALSE);
325 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
328 /*************************************************************
330 *************************************************************/
332 cell_info_new (GtkCellLayoutDataFunc func,
334 GDestroyNotify destroy)
336 CellInfo *info = g_slice_new (CellInfo);
338 info->attributes = NULL;
341 info->destroy = destroy;
347 cell_info_free (CellInfo *info)
350 info->destroy (info->data);
352 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
353 g_slist_free (info->attributes);
355 g_slice_free (CellInfo, info);
358 static CellAttribute *
359 cell_attribute_new (GtkCellRenderer *renderer,
360 const gchar *attribute,
365 /* Check if the attribute really exists and point to
366 * the property string installed on the cell renderer
367 * class (dont dup the string)
369 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
373 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
375 cell_attribute->attribute = pspec->name;
376 cell_attribute->column = column;
378 return cell_attribute;
385 cell_attribute_free (CellAttribute *attribute)
387 g_slice_free (CellAttribute, attribute);
390 /* GCompareFunc for g_slist_find_custom() */
392 cell_attribute_find (CellAttribute *cell_attribute,
393 const gchar *attribute)
395 return g_strcmp0 (cell_attribute->attribute, attribute);
398 /*************************************************************
400 *************************************************************/
402 gtk_cell_area_finalize (GObject *object)
404 GtkCellArea *area = GTK_CELL_AREA (object);
405 GtkCellAreaPrivate *priv = area->priv;
407 /* All cell renderers should already be removed at this point,
408 * just kill our hash table here.
410 g_hash_table_destroy (priv->cell_info);
412 g_free (priv->current_path);
414 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
419 gtk_cell_area_dispose (GObject *object)
421 /* This removes every cell renderer that may be added to the GtkCellArea,
422 * subclasses should be breaking references to the GtkCellRenderers
425 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
427 /* Remove any ref to a focused/edited cell */
428 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
429 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
431 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
435 gtk_cell_area_set_property (GObject *object,
440 GtkCellArea *area = GTK_CELL_AREA (object);
444 case PROP_CELL_MARGIN_LEFT:
445 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
447 case PROP_CELL_MARGIN_RIGHT:
448 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
450 case PROP_CELL_MARGIN_TOP:
451 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
453 case PROP_CELL_MARGIN_BOTTOM:
454 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
456 case PROP_FOCUS_CELL:
457 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
460 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
466 gtk_cell_area_get_property (GObject *object,
471 GtkCellArea *area = GTK_CELL_AREA (object);
472 GtkCellAreaPrivate *priv = area->priv;
476 case PROP_CELL_MARGIN_LEFT:
477 g_value_set_int (value, priv->cell_border.left);
479 case PROP_CELL_MARGIN_RIGHT:
480 g_value_set_int (value, priv->cell_border.right);
482 case PROP_CELL_MARGIN_TOP:
483 g_value_set_int (value, priv->cell_border.top);
485 case PROP_CELL_MARGIN_BOTTOM:
486 g_value_set_int (value, priv->cell_border.bottom);
488 case PROP_FOCUS_CELL:
489 g_value_set_object (value, priv->focus_cell);
492 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
497 /*************************************************************
499 *************************************************************/
501 gtk_cell_area_real_event (GtkCellArea *area,
502 GtkCellAreaIter *iter,
505 const GdkRectangle *cell_area,
506 GtkCellRendererState flags)
508 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
510 GdkEventKey *key_event = (GdkEventKey *)event;
511 GtkCellAreaPrivate *priv = area->priv;
513 if (priv->focus_cell &&
514 (key_event->keyval == GDK_KEY_space ||
515 key_event->keyval == GDK_KEY_KP_Space ||
516 key_event->keyval == GDK_KEY_Return ||
517 key_event->keyval == GDK_KEY_ISO_Enter ||
518 key_event->keyval == GDK_KEY_KP_Enter))
520 /* Activate or Edit the currently focused cell */
521 GtkCellRendererMode mode;
522 GdkRectangle background_area;
523 GdkRectangle inner_area;
525 /* Get the allocation of the focused cell.
527 gtk_cell_area_get_cell_allocation (area, iter, widget, priv->focus_cell,
528 cell_area, &background_area);
530 /* Remove margins from the background area to produce the cell area.
532 gtk_cell_area_inner_cell_area (area, &background_area, &inner_area);
534 /* XXX Need to do some extra right-to-left casing either here
535 * or inside the above called apis.
538 g_object_get (priv->focus_cell, "mode", &mode, NULL);
540 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
542 if (gtk_cell_renderer_activate (priv->focus_cell,
550 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
552 GtkCellEditable *editable_widget;
555 gtk_cell_renderer_start_editing (priv->focus_cell,
562 if (editable_widget != NULL)
564 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
566 gtk_cell_area_set_edited_cell (area, priv->focus_cell);
568 /* Signal that editing started so that callers can get
569 * a handle on the editable_widget */
570 gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
582 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
583 GtkCellAreaIter *iter,
586 gint *minimum_height,
587 gint *natural_height)
589 /* If the area doesnt do height-for-width, fallback on base preferred height */
590 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
594 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
595 GtkCellAreaIter *iter,
601 /* If the area doesnt do width-for-height, fallback on base preferred width */
602 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
606 update_can_focus (GtkCellRenderer *renderer,
610 if (gtk_cell_renderer_can_focus (renderer))
615 gtk_cell_area_real_update_focus (GtkCellArea *area)
617 gboolean can_focus = FALSE;
619 /* Update the area's can focus flag, if any of the renderers can
620 * focus then the area can focus.
622 * Subclasses can override this in the case that they are also
623 * rendering widgets as well as renderers.
625 gtk_cell_area_forall (area, (GtkCellCallback)update_can_focus, &can_focus);
626 gtk_cell_area_set_can_focus (area, can_focus);
628 /* Unset the currently focused cell if the area can not receive
629 * focus for the given row data */
631 gtk_cell_area_set_focus_cell (area, NULL);
634 /*************************************************************
635 * GtkCellLayoutIface *
636 *************************************************************/
638 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
640 iface->pack_start = gtk_cell_area_pack_default;
641 iface->pack_end = gtk_cell_area_pack_default;
642 iface->clear = gtk_cell_area_clear;
643 iface->add_attribute = gtk_cell_area_add_attribute;
644 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
645 iface->clear_attributes = gtk_cell_area_clear_attributes;
646 iface->reorder = gtk_cell_area_reorder;
647 iface->get_cells = gtk_cell_area_get_cells;
651 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
652 GtkCellRenderer *renderer,
655 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
659 gtk_cell_area_clear (GtkCellLayout *cell_layout)
661 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
663 gtk_cell_layout_get_cells (cell_layout);
665 for (l = cells; l; l = l->next)
667 GtkCellRenderer *renderer = l->data;
668 gtk_cell_area_remove (area, renderer);
675 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
676 GtkCellRenderer *renderer,
677 const gchar *attribute,
680 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
681 renderer, attribute, column);
685 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
686 GtkCellRenderer *renderer,
687 GtkCellLayoutDataFunc func,
689 GDestroyNotify destroy)
691 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
692 GtkCellAreaPrivate *priv = area->priv;
695 info = g_hash_table_lookup (priv->cell_info, renderer);
699 if (info->destroy && info->data)
700 info->destroy (info->data);
705 info->data = func_data;
706 info->destroy = destroy;
712 info->destroy = NULL;
717 info = cell_info_new (func, func_data, destroy);
719 g_hash_table_insert (priv->cell_info, renderer, info);
724 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
725 GtkCellRenderer *renderer)
727 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
728 GtkCellAreaPrivate *priv = area->priv;
731 info = g_hash_table_lookup (priv->cell_info, renderer);
735 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
736 g_slist_free (info->attributes);
738 info->attributes = NULL;
743 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
744 GtkCellRenderer *cell,
747 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
748 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
752 accum_cells (GtkCellRenderer *renderer,
755 *accum = g_list_prepend (*accum, renderer);
759 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
763 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
764 (GtkCellCallback)accum_cells,
767 return g_list_reverse (cells);
771 /*************************************************************
773 *************************************************************/
777 * @area: a #GtkCellArea
778 * @renderer: the #GtkCellRenderer to add to @area
780 * Adds @renderer to @area with the default child cell properties.
783 gtk_cell_area_add (GtkCellArea *area,
784 GtkCellRenderer *renderer)
786 GtkCellAreaClass *class;
788 g_return_if_fail (GTK_IS_CELL_AREA (area));
789 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
791 class = GTK_CELL_AREA_GET_CLASS (area);
794 class->add (area, renderer);
796 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
797 g_type_name (G_TYPE_FROM_INSTANCE (area)));
801 * gtk_cell_area_remove:
802 * @area: a #GtkCellArea
803 * @renderer: the #GtkCellRenderer to add to @area
805 * Removes @renderer from @area.
808 gtk_cell_area_remove (GtkCellArea *area,
809 GtkCellRenderer *renderer)
811 GtkCellAreaClass *class;
812 GtkCellAreaPrivate *priv;
814 g_return_if_fail (GTK_IS_CELL_AREA (area));
815 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
817 class = GTK_CELL_AREA_GET_CLASS (area);
820 /* Remove any custom attributes and custom cell data func here first */
821 g_hash_table_remove (priv->cell_info, renderer);
824 class->remove (area, renderer);
826 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
827 g_type_name (G_TYPE_FROM_INSTANCE (area)));
831 * gtk_cell_area_forall
832 * @area: a #GtkCellArea
833 * @callback: the #GtkCellCallback to call
834 * @callback_data: user provided data pointer
836 * Calls @callback for every #GtkCellRenderer in @area.
839 gtk_cell_area_forall (GtkCellArea *area,
840 GtkCellCallback callback,
841 gpointer callback_data)
843 GtkCellAreaClass *class;
845 g_return_if_fail (GTK_IS_CELL_AREA (area));
846 g_return_if_fail (callback != NULL);
848 class = GTK_CELL_AREA_GET_CLASS (area);
851 class->forall (area, callback, callback_data);
853 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
854 g_type_name (G_TYPE_FROM_INSTANCE (area)));
858 * gtk_cell_area_get_cell_allocation:
859 * @area: a #GtkCellArea
860 * @iter: the #GtkCellAreaIter used to hold sizes for @area.
861 * @widget: the #GtkWidget that @area is rendering on
862 * @renderer: the #GtkCellRenderer to get the allocation for
863 * @cell_area: the whole allocated area for @area in @widget
865 * @allocation: where to store the allocation for @renderer
867 * Derives the allocation of @renderer inside @area if @area
868 * were to be renderered in @cell_area.
871 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
872 GtkCellAreaIter *iter,
874 GtkCellRenderer *renderer,
875 const GdkRectangle *cell_area,
876 GdkRectangle *allocation)
878 GtkCellAreaClass *class;
880 g_return_if_fail (GTK_IS_CELL_AREA (area));
881 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
882 g_return_if_fail (GTK_IS_WIDGET (widget));
883 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
884 g_return_if_fail (cell_area != NULL);
885 g_return_if_fail (allocation != NULL);
887 class = GTK_CELL_AREA_GET_CLASS (area);
889 if (class->get_cell_allocation)
890 class->get_cell_allocation (area, iter, widget, renderer, cell_area, allocation);
892 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
893 g_type_name (G_TYPE_FROM_INSTANCE (area)));
897 gtk_cell_area_event (GtkCellArea *area,
898 GtkCellAreaIter *iter,
901 const GdkRectangle *cell_area,
902 GtkCellRendererState flags)
904 GtkCellAreaClass *class;
906 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
907 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
908 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
909 g_return_val_if_fail (event != NULL, 0);
910 g_return_val_if_fail (cell_area != NULL, 0);
912 class = GTK_CELL_AREA_GET_CLASS (area);
915 return class->event (area, iter, widget, event, cell_area, flags);
917 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
918 g_type_name (G_TYPE_FROM_INSTANCE (area)));
923 gtk_cell_area_render (GtkCellArea *area,
924 GtkCellAreaIter *iter,
927 const GdkRectangle *cell_area,
928 GtkCellRendererState flags)
930 GtkCellAreaClass *class;
932 g_return_if_fail (GTK_IS_CELL_AREA (area));
933 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
934 g_return_if_fail (GTK_IS_WIDGET (widget));
935 g_return_if_fail (cr != NULL);
936 g_return_if_fail (cell_area != NULL);
938 class = GTK_CELL_AREA_GET_CLASS (area);
941 class->render (area, iter, widget, cr, cell_area, flags);
943 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
944 g_type_name (G_TYPE_FROM_INSTANCE (area)));
947 /*************************************************************
949 *************************************************************/
951 gtk_cell_area_create_iter (GtkCellArea *area)
953 GtkCellAreaClass *class;
955 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
957 class = GTK_CELL_AREA_GET_CLASS (area);
959 if (class->create_iter)
960 return class->create_iter (area);
962 g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'",
963 g_type_name (G_TYPE_FROM_INSTANCE (area)));
970 gtk_cell_area_get_request_mode (GtkCellArea *area)
972 GtkCellAreaClass *class;
974 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
975 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
977 class = GTK_CELL_AREA_GET_CLASS (area);
979 if (class->get_request_mode)
980 return class->get_request_mode (area);
982 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
983 g_type_name (G_TYPE_FROM_INSTANCE (area)));
985 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
989 gtk_cell_area_get_preferred_width (GtkCellArea *area,
990 GtkCellAreaIter *iter,
995 GtkCellAreaClass *class;
997 g_return_if_fail (GTK_IS_CELL_AREA (area));
998 g_return_if_fail (GTK_IS_WIDGET (widget));
1000 class = GTK_CELL_AREA_GET_CLASS (area);
1002 if (class->get_preferred_width)
1003 class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
1005 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1006 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1010 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1011 GtkCellAreaIter *iter,
1014 gint *minimum_height,
1015 gint *natural_height)
1017 GtkCellAreaClass *class;
1019 g_return_if_fail (GTK_IS_CELL_AREA (area));
1020 g_return_if_fail (GTK_IS_WIDGET (widget));
1022 class = GTK_CELL_AREA_GET_CLASS (area);
1023 class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
1027 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1028 GtkCellAreaIter *iter,
1033 GtkCellAreaClass *class;
1035 g_return_if_fail (GTK_IS_CELL_AREA (area));
1036 g_return_if_fail (GTK_IS_WIDGET (widget));
1038 class = GTK_CELL_AREA_GET_CLASS (area);
1040 if (class->get_preferred_height)
1041 class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
1043 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1044 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1048 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1049 GtkCellAreaIter *iter,
1052 gint *minimum_width,
1053 gint *natural_width)
1055 GtkCellAreaClass *class;
1057 g_return_if_fail (GTK_IS_CELL_AREA (area));
1058 g_return_if_fail (GTK_IS_WIDGET (widget));
1060 class = GTK_CELL_AREA_GET_CLASS (area);
1061 class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
1064 /*************************************************************
1066 *************************************************************/
1069 * gtk_cell_area_attribute_connect:
1070 * @area: a #GtkCellArea
1071 * @renderer: the #GtkCellRenderer to connect an attribute for
1072 * @attribute: the attribute name
1073 * @column: the #GtkTreeModel column to fetch attribute values from
1075 * Connects an @attribute to apply values from @column for the
1076 * #GtkTreeModel in use.
1079 gtk_cell_area_attribute_connect (GtkCellArea *area,
1080 GtkCellRenderer *renderer,
1081 const gchar *attribute,
1084 GtkCellAreaPrivate *priv;
1086 CellAttribute *cell_attribute;
1088 g_return_if_fail (GTK_IS_CELL_AREA (area));
1089 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1090 g_return_if_fail (attribute != NULL);
1093 info = g_hash_table_lookup (priv->cell_info, renderer);
1097 info = cell_info_new (NULL, NULL, NULL);
1099 g_hash_table_insert (priv->cell_info, renderer, info);
1105 /* Check we are not adding the same attribute twice */
1106 if ((node = g_slist_find_custom (info->attributes, attribute,
1107 (GCompareFunc)cell_attribute_find)) != NULL)
1109 cell_attribute = node->data;
1111 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1112 "since `%s' is already attributed to column %d",
1114 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1115 attribute, cell_attribute->column);
1120 cell_attribute = cell_attribute_new (renderer, attribute, column);
1122 if (!cell_attribute)
1124 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1125 "since attribute does not exist",
1127 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1131 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1135 * gtk_cell_area_attribute_disconnect:
1136 * @area: a #GtkCellArea
1137 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1138 * @attribute: the attribute name
1140 * Disconnects @attribute for the @renderer in @area so that
1141 * attribute will no longer be updated with values from the
1145 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1146 GtkCellRenderer *renderer,
1147 const gchar *attribute)
1149 GtkCellAreaPrivate *priv;
1151 CellAttribute *cell_attribute;
1154 g_return_if_fail (GTK_IS_CELL_AREA (area));
1155 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1156 g_return_if_fail (attribute != NULL);
1159 info = g_hash_table_lookup (priv->cell_info, renderer);
1163 node = g_slist_find_custom (info->attributes, attribute,
1164 (GCompareFunc)cell_attribute_find);
1167 cell_attribute = node->data;
1169 cell_attribute_free (cell_attribute);
1171 info->attributes = g_slist_delete_link (info->attributes, node);
1177 apply_cell_attributes (GtkCellRenderer *renderer,
1179 AttributeData *data)
1181 CellAttribute *attribute;
1183 GValue value = { 0, };
1184 gboolean is_expander;
1185 gboolean is_expanded;
1187 g_object_freeze_notify (G_OBJECT (renderer));
1189 /* Whether a row expands or is presently expanded can only be
1190 * provided by the view (as these states can vary across views
1191 * accessing the same model).
1193 g_object_get (renderer, "is-expander", &is_expander, NULL);
1194 if (is_expander != data->is_expander)
1195 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1197 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1198 if (is_expanded != data->is_expanded)
1199 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1201 /* Apply the attributes directly to the renderer */
1202 for (list = info->attributes; list; list = list->next)
1204 attribute = list->data;
1206 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1207 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1208 g_value_unset (&value);
1211 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1214 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1215 data->model, data->iter, info->data);
1217 g_object_thaw_notify (G_OBJECT (renderer));
1221 * gtk_cell_area_apply_attributes
1222 * @area: a #GtkCellArea
1223 * @tree_model: a #GtkTreeModel to pull values from
1224 * @iter: the #GtkTreeIter in @tree_model to apply values for
1225 * @is_expander: whether @iter has children
1226 * @is_expanded: whether @iter is expanded in the view and
1227 * children are visible
1229 * Applies any connected attributes to the renderers in
1230 * @area by pulling the values from @tree_model.
1233 gtk_cell_area_apply_attributes (GtkCellArea *area,
1234 GtkTreeModel *tree_model,
1236 gboolean is_expander,
1237 gboolean is_expanded)
1239 GtkCellAreaPrivate *priv;
1243 g_return_if_fail (GTK_IS_CELL_AREA (area));
1244 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1245 g_return_if_fail (iter != NULL);
1249 /* Feed in data needed to apply to every renderer */
1251 data.model = tree_model;
1253 data.is_expander = is_expander;
1254 data.is_expanded = is_expanded;
1256 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1257 * apply the data from the treemodel */
1258 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1260 /* Update the currently applied path */
1261 g_free (priv->current_path);
1262 path = gtk_tree_model_get_path (tree_model, iter);
1263 priv->current_path = gtk_tree_path_to_string (path);
1264 gtk_tree_path_free (path);
1268 * gtk_cell_area_get_current_path_string:
1269 * @area: a #GtkCellArea
1271 * Gets the current #GtkTreePath string for the currently
1272 * applied #GtkTreeIter, this is implicitly updated when
1273 * gtk_cell_area_apply_attributes() is called and can be
1274 * used to interact with renderers from #GtkCellArea
1278 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1280 GtkCellAreaPrivate *priv;
1282 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1286 return priv->current_path;
1290 /*************************************************************
1291 * API: Cell Properties *
1292 *************************************************************/
1294 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1298 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1299 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1300 if (pspec->flags & G_PARAM_WRITABLE)
1301 g_return_if_fail (aclass->set_cell_property != NULL);
1302 if (pspec->flags & G_PARAM_READABLE)
1303 g_return_if_fail (aclass->get_cell_property != NULL);
1304 g_return_if_fail (property_id > 0);
1305 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1306 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1308 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1310 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1311 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1314 g_param_spec_ref (pspec);
1315 g_param_spec_sink (pspec);
1316 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1317 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1321 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1322 const gchar *property_name)
1324 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1325 g_return_val_if_fail (property_name != NULL, NULL);
1327 return g_param_spec_pool_lookup (cell_property_pool,
1329 G_OBJECT_CLASS_TYPE (aclass),
1334 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1335 guint *n_properties)
1337 GParamSpec **pspecs;
1340 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1342 pspecs = g_param_spec_pool_list (cell_property_pool,
1343 G_OBJECT_CLASS_TYPE (aclass),
1352 gtk_cell_area_add_with_properties (GtkCellArea *area,
1353 GtkCellRenderer *renderer,
1354 const gchar *first_prop_name,
1357 GtkCellAreaClass *class;
1359 g_return_if_fail (GTK_IS_CELL_AREA (area));
1360 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1362 class = GTK_CELL_AREA_GET_CLASS (area);
1368 class->add (area, renderer);
1370 va_start (var_args, first_prop_name);
1371 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1375 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1376 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1380 gtk_cell_area_cell_set (GtkCellArea *area,
1381 GtkCellRenderer *renderer,
1382 const gchar *first_prop_name,
1387 g_return_if_fail (GTK_IS_CELL_AREA (area));
1388 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1390 va_start (var_args, first_prop_name);
1391 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1396 gtk_cell_area_cell_get (GtkCellArea *area,
1397 GtkCellRenderer *renderer,
1398 const gchar *first_prop_name,
1403 g_return_if_fail (GTK_IS_CELL_AREA (area));
1404 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1406 va_start (var_args, first_prop_name);
1407 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1412 area_get_cell_property (GtkCellArea *area,
1413 GtkCellRenderer *renderer,
1417 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1419 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1423 area_set_cell_property (GtkCellArea *area,
1424 GtkCellRenderer *renderer,
1426 const GValue *value)
1428 GValue tmp_value = { 0, };
1429 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1431 /* provide a copy to work from, convert (if necessary) and validate */
1432 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1433 if (!g_value_transform (value, &tmp_value))
1434 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1436 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1437 G_VALUE_TYPE_NAME (value));
1438 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1440 gchar *contents = g_strdup_value_contents (value);
1442 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1444 G_VALUE_TYPE_NAME (value),
1446 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1451 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1453 g_value_unset (&tmp_value);
1457 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1458 GtkCellRenderer *renderer,
1459 const gchar *first_property_name,
1464 g_return_if_fail (GTK_IS_CELL_AREA (area));
1465 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1467 name = first_property_name;
1470 GValue value = { 0, };
1471 gchar *error = NULL;
1473 g_param_spec_pool_lookup (cell_property_pool, name,
1474 G_OBJECT_TYPE (area), TRUE);
1477 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1478 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1481 if (!(pspec->flags & G_PARAM_WRITABLE))
1483 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1484 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1488 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1489 G_VALUE_COLLECT (&value, var_args, 0, &error);
1492 g_warning ("%s: %s", G_STRLOC, error);
1495 /* we purposely leak the value here, it might not be
1496 * in a sane state if an error condition occoured
1500 area_set_cell_property (area, renderer, pspec, &value);
1501 g_value_unset (&value);
1502 name = va_arg (var_args, gchar*);
1507 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1508 GtkCellRenderer *renderer,
1509 const gchar *first_property_name,
1514 g_return_if_fail (GTK_IS_CELL_AREA (area));
1515 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1517 name = first_property_name;
1520 GValue value = { 0, };
1524 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1525 G_OBJECT_TYPE (area), TRUE);
1528 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1529 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1532 if (!(pspec->flags & G_PARAM_READABLE))
1534 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1535 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1539 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1540 area_get_cell_property (area, renderer, pspec, &value);
1541 G_VALUE_LCOPY (&value, var_args, 0, &error);
1544 g_warning ("%s: %s", G_STRLOC, error);
1546 g_value_unset (&value);
1549 g_value_unset (&value);
1550 name = va_arg (var_args, gchar*);
1555 gtk_cell_area_cell_set_property (GtkCellArea *area,
1556 GtkCellRenderer *renderer,
1557 const gchar *property_name,
1558 const GValue *value)
1562 g_return_if_fail (GTK_IS_CELL_AREA (area));
1563 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1564 g_return_if_fail (property_name != NULL);
1565 g_return_if_fail (G_IS_VALUE (value));
1567 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1568 G_OBJECT_TYPE (area), TRUE);
1570 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1571 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1572 else if (!(pspec->flags & G_PARAM_WRITABLE))
1573 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1574 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1577 area_set_cell_property (area, renderer, pspec, value);
1582 gtk_cell_area_cell_get_property (GtkCellArea *area,
1583 GtkCellRenderer *renderer,
1584 const gchar *property_name,
1589 g_return_if_fail (GTK_IS_CELL_AREA (area));
1590 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1591 g_return_if_fail (property_name != NULL);
1592 g_return_if_fail (G_IS_VALUE (value));
1594 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1595 G_OBJECT_TYPE (area), TRUE);
1597 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1598 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1599 else if (!(pspec->flags & G_PARAM_READABLE))
1600 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1601 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1604 GValue *prop_value, tmp_value = { 0, };
1606 /* auto-conversion of the callers value type
1608 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1610 g_value_reset (value);
1613 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1615 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1617 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1618 G_VALUE_TYPE_NAME (value));
1623 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1624 prop_value = &tmp_value;
1627 area_get_cell_property (area, renderer, pspec, prop_value);
1629 if (prop_value != value)
1631 g_value_transform (prop_value, value);
1632 g_value_unset (&tmp_value);
1637 /*************************************************************
1639 *************************************************************/
1642 * gtk_cell_area_grab_focus:
1643 * @area: a #GtkCellArea
1644 * @direction: the #GtkDirectionType from which focus came
1646 * This should be called by the @area's owning layout widget
1647 * when focus should be passed to @area for a given row data.
1649 * Note that after applying new attributes for @area that
1650 * gtk_cell_area_update_focus() should be called and
1651 * gtk_cell_area_can_focus() should be checked before trying
1652 * to pass focus to @area.
1654 * Implementing #GtkCellArea classes should implement this
1655 * method to receive focus in it's own way particular to
1656 * how it lays out cells.
1659 gtk_cell_area_grab_focus (GtkCellArea *area,
1660 GtkDirectionType direction)
1662 GtkCellAreaClass *class;
1664 g_return_if_fail (GTK_IS_CELL_AREA (area));
1666 class = GTK_CELL_AREA_GET_CLASS (area);
1668 if (class->grab_focus)
1669 class->grab_focus (area, direction);
1671 g_warning ("GtkCellAreaClass::grab_focus not implemented for `%s'",
1672 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1676 * gtk_cell_area_focus_leave:
1677 * @area: a #GtkCellArea
1678 * @direction: the #GtkDirectionType in which focus
1680 * @path: the current #GtkTreePath string for the
1681 * event which was handled by @area
1683 * Notifies that focus is to leave @area in the
1686 * This is called by #GtkCellArea implementations upon
1687 * handling a key event that caused focus to leave the
1688 * cell. The resulting signal can be handled by the
1689 * owning layouting widget to decide which new @area
1690 * to pass focus to and from what @direction. Or to
1691 * pass focus along to an entirely new data row.
1694 gtk_cell_area_focus_leave (GtkCellArea *area,
1695 GtkDirectionType direction,
1698 g_return_if_fail (GTK_IS_CELL_AREA (area));
1700 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path);
1704 * gtk_cell_area_update_focus:
1705 * @area: a #GtkCellArea
1707 * Updates focus information on @area for a given
1710 * After calling gtk_cell_area_apply_attributes() to
1711 * the @area this method should be called to update
1712 * information about whether the @area can focus and
1713 * which is the cell currently in focus.
1716 gtk_cell_area_update_focus (GtkCellArea *area)
1718 g_return_if_fail (GTK_IS_CELL_AREA (area));
1720 GTK_CELL_AREA_GET_CLASS (area)->update_focus (area);
1724 * gtk_cell_area_set_can_focus:
1725 * @area: a #GtkCellArea
1726 * @can_focus: whether @area can receive focus
1728 * This is generally called from GtkCellArea::update_focus()
1729 * implementations to update if the @area can focus after
1730 * applying new row data attributes.
1733 gtk_cell_area_set_can_focus (GtkCellArea *area,
1736 GtkCellAreaPrivate *priv;
1738 g_return_if_fail (GTK_IS_CELL_AREA (area));
1742 if (priv->can_focus != can_focus)
1744 priv->can_focus = can_focus;
1749 * gtk_cell_area_get_can_focus:
1750 * @area: a #GtkCellArea
1752 * Returns whether the area can receive keyboard focus,
1753 * after applying new attributes to @area,
1754 * gtk_cell_area_update_focus() needs to be called before
1755 * calling this method.
1757 * Returns: whether @area can receive focus.
1760 gtk_cell_area_get_can_focus (GtkCellArea *area)
1762 GtkCellAreaPrivate *priv;
1764 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1768 return priv->can_focus;
1773 * gtk_cell_area_set_focus_cell:
1774 * @area: a #GtkCellArea
1775 * @focus_cell: the #GtkCellRenderer to give focus to
1777 * This is generally called from #GtkCellArea implementations
1778 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
1779 * is called. It's also up to the #GtkCellArea implementation
1780 * to update the focused cell when receiving events from
1781 * gtk_cell_area_event() appropriately.
1784 gtk_cell_area_set_focus_cell (GtkCellArea *area,
1785 GtkCellRenderer *renderer)
1787 GtkCellAreaPrivate *priv;
1789 g_return_if_fail (GTK_IS_CELL_AREA (area));
1790 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1794 if (priv->focus_cell != renderer)
1796 if (priv->focus_cell)
1797 g_object_unref (priv->focus_cell);
1799 priv->focus_cell = renderer;
1801 if (priv->focus_cell)
1802 g_object_ref (priv->focus_cell);
1804 g_object_notify (G_OBJECT (area), "focus-cell");
1809 * gtk_cell_area_get_focus_cell:
1810 * @area: a #GtkCellArea
1812 * Retrieves the currently focused cell for @area
1814 * Returns: the currently focused cell in @area.
1817 gtk_cell_area_get_focus_cell (GtkCellArea *area)
1819 GtkCellAreaPrivate *priv;
1821 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1825 return priv->focus_cell;
1829 gtk_cell_area_set_edited_cell (GtkCellArea *area,
1830 GtkCellRenderer *renderer)
1832 GtkCellAreaPrivate *priv;
1834 g_return_if_fail (GTK_IS_CELL_AREA (area));
1835 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1839 if (priv->edited_cell != renderer)
1841 if (priv->edited_cell)
1842 g_object_unref (priv->edited_cell);
1844 priv->edited_cell = renderer;
1846 if (priv->edited_cell)
1847 g_object_ref (priv->edited_cell);
1849 g_object_notify (G_OBJECT (area), "edited-cell");
1854 gtk_cell_area_get_edited_cell (GtkCellArea *area)
1856 GtkCellAreaPrivate *priv;
1858 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1862 return priv->edited_cell;
1865 /*************************************************************
1867 *************************************************************/
1869 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
1871 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1873 return area->priv->cell_border.left;
1877 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
1880 GtkCellAreaPrivate *priv;
1882 g_return_if_fail (GTK_IS_CELL_AREA (area));
1886 if (priv->cell_border.left != margin)
1888 priv->cell_border.left = margin;
1890 g_object_notify (G_OBJECT (area), "margin-left");
1895 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
1897 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1899 return area->priv->cell_border.right;
1903 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
1906 GtkCellAreaPrivate *priv;
1908 g_return_if_fail (GTK_IS_CELL_AREA (area));
1912 if (priv->cell_border.right != margin)
1914 priv->cell_border.right = margin;
1916 g_object_notify (G_OBJECT (area), "margin-right");
1921 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
1923 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1925 return area->priv->cell_border.top;
1929 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
1932 GtkCellAreaPrivate *priv;
1934 g_return_if_fail (GTK_IS_CELL_AREA (area));
1938 if (priv->cell_border.top != margin)
1940 priv->cell_border.top = margin;
1942 g_object_notify (G_OBJECT (area), "margin-top");
1947 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
1949 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1951 return area->priv->cell_border.bottom;
1955 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
1958 GtkCellAreaPrivate *priv;
1960 g_return_if_fail (GTK_IS_CELL_AREA (area));
1964 if (priv->cell_border.bottom != margin)
1966 priv->cell_border.bottom = margin;
1968 g_object_notify (G_OBJECT (area), "margin-bottom");
1972 /* For convenience in area implementations */
1974 gtk_cell_area_editing_started (GtkCellArea *area,
1975 GtkCellRenderer *renderer,
1976 GtkCellEditable *editable)
1978 GtkCellAreaPrivate *priv;
1980 g_return_if_fail (GTK_IS_CELL_AREA (area));
1984 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0,
1985 renderer, editable, priv->current_path);
1989 gtk_cell_area_inner_cell_area (GtkCellArea *area,
1990 GdkRectangle *background_area,
1991 GdkRectangle *cell_area)
1993 GtkCellAreaPrivate *priv;
1995 g_return_if_fail (GTK_IS_CELL_AREA (area));
1996 g_return_if_fail (background_area != NULL);
1997 g_return_if_fail (cell_area != NULL);
2001 *cell_area = *background_area;
2003 cell_area->x += priv->cell_border.left;
2004 cell_area->width -= (priv->cell_border.left + priv->cell_border.right);
2005 cell_area->y += priv->cell_border.top;
2006 cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2010 gtk_cell_area_request_renderer (GtkCellArea *area,
2011 GtkCellRenderer *renderer,
2012 GtkOrientation orientation,
2018 GtkCellAreaPrivate *priv;
2020 g_return_if_fail (GTK_IS_CELL_AREA (area));
2021 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2022 g_return_if_fail (GTK_IS_WIDGET (widget));
2023 g_return_if_fail (minimum_size != NULL);
2024 g_return_if_fail (natural_size != NULL);
2028 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2031 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2034 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2036 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2037 minimum_size, natural_size);
2040 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2041 *natural_size += (priv->cell_border.left + priv->cell_border.right);
2043 else /* GTK_ORIENTATION_VERTICAL */
2046 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2049 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2051 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2052 minimum_size, natural_size);
2055 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2056 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);