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 /* Internal signal emissions */
121 static void gtk_cell_area_editing_started (GtkCellArea *area,
122 GtkCellRenderer *renderer,
123 GtkCellEditable *editable);
124 static void gtk_cell_area_editing_canceled (GtkCellArea *area,
125 GtkCellRenderer *renderer);
126 static void gtk_cell_area_editing_done (GtkCellArea *area,
127 GtkCellRenderer *renderer,
128 GtkCellEditable *editable);
129 static void gtk_cell_area_remove_editable (GtkCellArea *area,
130 GtkCellRenderer *renderer,
131 GtkCellEditable *editable);
134 /* Struct to pass data along while looping over
135 * cell renderers to apply attributes
141 gboolean is_expander;
142 gboolean is_expanded;
145 struct _GtkCellAreaPrivate
147 /* The GtkCellArea bookkeeps any connected
148 * attributes in this hash table.
150 GHashTable *cell_info;
152 /* The cell border decides how much space to reserve
153 * around each cell for the background_area
155 GtkBorder cell_border;
157 /* Current path is saved as a side-effect
158 * of gtk_cell_area_apply_attributes() */
161 /* Current cell being edited and editable widget used */
162 GtkCellEditable *edit_widget;
163 GtkCellRenderer *edited_cell;
165 /* Signal connections to the editable widget */
166 gulong editing_done_id;
167 gulong remove_widget_id;
169 /* Currently focused cell */
170 GtkCellRenderer *focus_cell;
177 PROP_CELL_MARGIN_LEFT,
178 PROP_CELL_MARGIN_RIGHT,
179 PROP_CELL_MARGIN_TOP,
180 PROP_CELL_MARGIN_BOTTOM,
188 SIGNAL_EDITING_STARTED,
189 SIGNAL_EDITING_CANCELED,
191 SIGNAL_REMOVE_EDITABLE,
195 /* Keep the paramspec pool internal, no need to deliver notifications
196 * on cells. at least no percieved need for now */
197 static GParamSpecPool *cell_property_pool = NULL;
198 static guint cell_area_signals[LAST_SIGNAL] = { 0 };
200 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
201 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
204 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
205 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
206 gtk_cell_area_cell_layout_init));
209 gtk_cell_area_init (GtkCellArea *area)
211 GtkCellAreaPrivate *priv;
213 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
218 priv->cell_info = g_hash_table_new_full (g_direct_hash,
221 (GDestroyNotify)cell_info_free);
223 priv->cell_border.left = 0;
224 priv->cell_border.right = 0;
225 priv->cell_border.top = 0;
226 priv->cell_border.bottom = 0;
228 priv->focus_cell = NULL;
229 priv->edited_cell = NULL;
230 priv->edit_widget = NULL;
231 priv->can_focus = FALSE;
233 priv->editing_done_id = 0;
234 priv->remove_widget_id = 0;
238 gtk_cell_area_class_init (GtkCellAreaClass *class)
240 GObjectClass *object_class = G_OBJECT_CLASS (class);
243 object_class->dispose = gtk_cell_area_dispose;
244 object_class->finalize = gtk_cell_area_finalize;
245 object_class->get_property = gtk_cell_area_get_property;
246 object_class->set_property = gtk_cell_area_set_property;
250 class->remove = NULL;
251 class->forall = NULL;
252 class->event = gtk_cell_area_real_event;
253 class->render = NULL;
256 class->create_iter = NULL;
257 class->get_request_mode = NULL;
258 class->get_preferred_width = NULL;
259 class->get_preferred_height = NULL;
260 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
261 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
264 class->grab_focus = NULL;
265 class->update_focus = gtk_cell_area_real_update_focus;
268 cell_area_signals[SIGNAL_FOCUS_LEAVE] =
269 g_signal_new (I_("focus-leave"),
270 G_TYPE_FROM_CLASS (object_class),
272 0, /* Class offset (just a notification, no class handler) */
274 _gtk_marshal_VOID__ENUM_STRING,
276 GTK_TYPE_DIRECTION_TYPE, G_TYPE_STRING);
278 cell_area_signals[SIGNAL_EDITING_STARTED] =
279 g_signal_new (I_("editing-started"),
280 G_OBJECT_CLASS_TYPE (object_class),
282 0, /* No class closure here */
284 _gtk_marshal_VOID__OBJECT_OBJECT_STRING,
286 GTK_TYPE_CELL_RENDERER,
287 GTK_TYPE_CELL_EDITABLE,
290 cell_area_signals[SIGNAL_EDITING_CANCELED] =
291 g_signal_new (I_("editing-canceled"),
292 G_OBJECT_CLASS_TYPE (object_class),
294 0, /* No class closure here */
296 _gtk_marshal_VOID__OBJECT,
298 GTK_TYPE_CELL_RENDERER);
300 cell_area_signals[SIGNAL_EDITING_DONE] =
301 g_signal_new (I_("editing-done"),
302 G_OBJECT_CLASS_TYPE (object_class),
304 0, /* No class closure here */
306 _gtk_marshal_VOID__OBJECT_OBJECT,
308 GTK_TYPE_CELL_RENDERER,
309 GTK_TYPE_CELL_EDITABLE);
311 cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
312 g_signal_new (I_("remove-editable"),
313 G_OBJECT_CLASS_TYPE (object_class),
315 0, /* No class closure here */
317 _gtk_marshal_VOID__OBJECT_OBJECT,
319 GTK_TYPE_CELL_RENDERER,
320 GTK_TYPE_CELL_EDITABLE);
323 g_object_class_install_property (object_class,
324 PROP_CELL_MARGIN_LEFT,
327 P_("Margin on Left"),
328 P_("Pixels of extra space on the left side of each cell"),
332 GTK_PARAM_READWRITE));
334 g_object_class_install_property (object_class,
335 PROP_CELL_MARGIN_RIGHT,
337 ("cell-margin-right",
338 P_("Margin on Right"),
339 P_("Pixels of extra space on the right side of each cell"),
343 GTK_PARAM_READWRITE));
345 g_object_class_install_property (object_class,
346 PROP_CELL_MARGIN_TOP,
350 P_("Pixels of extra space on the top side of each cell"),
354 GTK_PARAM_READWRITE));
356 g_object_class_install_property (object_class,
357 PROP_CELL_MARGIN_BOTTOM,
359 ("cell-margin-bottom",
360 P_("Margin on Bottom"),
361 P_("Pixels of extra space on the bottom side of each cell"),
365 GTK_PARAM_READWRITE));
367 g_object_class_install_property (object_class,
372 P_("The cell which currently has focus"),
373 GTK_TYPE_CELL_RENDERER,
374 GTK_PARAM_READWRITE));
376 g_object_class_install_property (object_class,
381 P_("The cell which is currently being edited"),
382 GTK_TYPE_CELL_RENDERER,
383 GTK_PARAM_READWRITE));
385 g_object_class_install_property (object_class,
390 P_("The widget currently editing the edited cell"),
391 GTK_TYPE_CELL_RENDERER,
392 GTK_PARAM_READWRITE));
394 /* Pool for Cell Properties */
395 if (!cell_property_pool)
396 cell_property_pool = g_param_spec_pool_new (FALSE);
398 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
401 /*************************************************************
403 *************************************************************/
405 cell_info_new (GtkCellLayoutDataFunc func,
407 GDestroyNotify destroy)
409 CellInfo *info = g_slice_new (CellInfo);
411 info->attributes = NULL;
414 info->destroy = destroy;
420 cell_info_free (CellInfo *info)
423 info->destroy (info->data);
425 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
426 g_slist_free (info->attributes);
428 g_slice_free (CellInfo, info);
431 static CellAttribute *
432 cell_attribute_new (GtkCellRenderer *renderer,
433 const gchar *attribute,
438 /* Check if the attribute really exists and point to
439 * the property string installed on the cell renderer
440 * class (dont dup the string)
442 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
446 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
448 cell_attribute->attribute = pspec->name;
449 cell_attribute->column = column;
451 return cell_attribute;
458 cell_attribute_free (CellAttribute *attribute)
460 g_slice_free (CellAttribute, attribute);
463 /* GCompareFunc for g_slist_find_custom() */
465 cell_attribute_find (CellAttribute *cell_attribute,
466 const gchar *attribute)
468 return g_strcmp0 (cell_attribute->attribute, attribute);
471 /*************************************************************
473 *************************************************************/
475 gtk_cell_area_finalize (GObject *object)
477 GtkCellArea *area = GTK_CELL_AREA (object);
478 GtkCellAreaPrivate *priv = area->priv;
480 /* All cell renderers should already be removed at this point,
481 * just kill our hash table here.
483 g_hash_table_destroy (priv->cell_info);
485 g_free (priv->current_path);
487 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
492 gtk_cell_area_dispose (GObject *object)
494 /* This removes every cell renderer that may be added to the GtkCellArea,
495 * subclasses should be breaking references to the GtkCellRenderers
498 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
500 /* Remove any ref to a focused/edited cell */
501 gtk_cell_area_set_focus_cell (GTK_CELL_AREA (object), NULL);
502 gtk_cell_area_set_edited_cell (GTK_CELL_AREA (object), NULL);
503 gtk_cell_area_set_edit_widget (GTK_CELL_AREA (object), NULL);
505 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
509 gtk_cell_area_set_property (GObject *object,
514 GtkCellArea *area = GTK_CELL_AREA (object);
518 case PROP_CELL_MARGIN_LEFT:
519 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
521 case PROP_CELL_MARGIN_RIGHT:
522 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
524 case PROP_CELL_MARGIN_TOP:
525 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
527 case PROP_CELL_MARGIN_BOTTOM:
528 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
530 case PROP_FOCUS_CELL:
531 gtk_cell_area_set_focus_cell (area, (GtkCellRenderer *)g_value_get_object (value));
533 case PROP_EDITED_CELL:
534 gtk_cell_area_set_edited_cell (area, (GtkCellRenderer *)g_value_get_object (value));
536 case PROP_EDIT_WIDGET:
537 gtk_cell_area_set_edit_widget (area, (GtkCellEditable *)g_value_get_object (value));
540 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
546 gtk_cell_area_get_property (GObject *object,
551 GtkCellArea *area = GTK_CELL_AREA (object);
552 GtkCellAreaPrivate *priv = area->priv;
556 case PROP_CELL_MARGIN_LEFT:
557 g_value_set_int (value, priv->cell_border.left);
559 case PROP_CELL_MARGIN_RIGHT:
560 g_value_set_int (value, priv->cell_border.right);
562 case PROP_CELL_MARGIN_TOP:
563 g_value_set_int (value, priv->cell_border.top);
565 case PROP_CELL_MARGIN_BOTTOM:
566 g_value_set_int (value, priv->cell_border.bottom);
568 case PROP_FOCUS_CELL:
569 g_value_set_object (value, priv->focus_cell);
571 case PROP_EDITED_CELL:
572 g_value_set_object (value, priv->edited_cell);
574 case PROP_EDIT_WIDGET:
575 g_value_set_object (value, priv->edit_widget);
578 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
583 /*************************************************************
585 *************************************************************/
587 gtk_cell_area_real_event (GtkCellArea *area,
588 GtkCellAreaIter *iter,
591 const GdkRectangle *cell_area,
592 GtkCellRendererState flags)
594 if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
596 GdkEventKey *key_event = (GdkEventKey *)event;
597 GtkCellAreaPrivate *priv = area->priv;
599 if (priv->focus_cell &&
600 (key_event->keyval == GDK_KEY_space ||
601 key_event->keyval == GDK_KEY_KP_Space ||
602 key_event->keyval == GDK_KEY_Return ||
603 key_event->keyval == GDK_KEY_ISO_Enter ||
604 key_event->keyval == GDK_KEY_KP_Enter))
606 GdkRectangle background_area;
608 /* Get the allocation of the focused cell.
610 gtk_cell_area_get_cell_allocation (area, iter, widget, priv->focus_cell,
611 cell_area, &background_area);
613 /* Activate or Edit the currently focused cell */
614 if (gtk_cell_area_activate_cell (area, widget, priv->focus_cell, event,
615 &background_area, flags))
618 else if (priv->edited_cell &&
619 (key_event->keyval == GDK_KEY_Escape))
621 /* Cancel editing of the cell renderer */
622 gtk_cell_renderer_stop_editing (priv->edited_cell, TRUE);
624 /* Signal that editing has been canceled */
625 gtk_cell_area_editing_canceled (area, priv->edited_cell);
627 /* Remove any references to the editable widget */
628 gtk_cell_area_set_edited_cell (area, NULL);
629 gtk_cell_area_set_edit_widget (area, NULL);
637 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
638 GtkCellAreaIter *iter,
641 gint *minimum_height,
642 gint *natural_height)
644 /* If the area doesnt do height-for-width, fallback on base preferred height */
645 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
649 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
650 GtkCellAreaIter *iter,
656 /* If the area doesnt do width-for-height, fallback on base preferred width */
657 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
661 update_can_focus (GtkCellRenderer *renderer,
665 if (gtk_cell_renderer_can_focus (renderer))
670 gtk_cell_area_real_update_focus (GtkCellArea *area)
672 gboolean can_focus = FALSE;
674 /* Update the area's can focus flag, if any of the renderers can
675 * focus then the area can focus.
677 * Subclasses can override this in the case that they are also
678 * rendering widgets as well as renderers.
680 gtk_cell_area_forall (area, (GtkCellCallback)update_can_focus, &can_focus);
681 gtk_cell_area_set_can_focus (area, can_focus);
683 /* Unset the currently focused cell if the area can not receive
684 * focus for the given row data */
686 gtk_cell_area_set_focus_cell (area, NULL);
689 /*************************************************************
690 * GtkCellLayoutIface *
691 *************************************************************/
693 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
695 iface->pack_start = gtk_cell_area_pack_default;
696 iface->pack_end = gtk_cell_area_pack_default;
697 iface->clear = gtk_cell_area_clear;
698 iface->add_attribute = gtk_cell_area_add_attribute;
699 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
700 iface->clear_attributes = gtk_cell_area_clear_attributes;
701 iface->reorder = gtk_cell_area_reorder;
702 iface->get_cells = gtk_cell_area_get_cells;
706 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
707 GtkCellRenderer *renderer,
710 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
714 gtk_cell_area_clear (GtkCellLayout *cell_layout)
716 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
718 gtk_cell_layout_get_cells (cell_layout);
720 for (l = cells; l; l = l->next)
722 GtkCellRenderer *renderer = l->data;
723 gtk_cell_area_remove (area, renderer);
730 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
731 GtkCellRenderer *renderer,
732 const gchar *attribute,
735 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
736 renderer, attribute, column);
740 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
741 GtkCellRenderer *renderer,
742 GtkCellLayoutDataFunc func,
744 GDestroyNotify destroy)
746 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
747 GtkCellAreaPrivate *priv = area->priv;
750 info = g_hash_table_lookup (priv->cell_info, renderer);
754 if (info->destroy && info->data)
755 info->destroy (info->data);
760 info->data = func_data;
761 info->destroy = destroy;
767 info->destroy = NULL;
772 info = cell_info_new (func, func_data, destroy);
774 g_hash_table_insert (priv->cell_info, renderer, info);
779 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
780 GtkCellRenderer *renderer)
782 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
783 GtkCellAreaPrivate *priv = area->priv;
786 info = g_hash_table_lookup (priv->cell_info, renderer);
790 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
791 g_slist_free (info->attributes);
793 info->attributes = NULL;
798 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
799 GtkCellRenderer *cell,
802 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
803 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
807 accum_cells (GtkCellRenderer *renderer,
810 *accum = g_list_prepend (*accum, renderer);
814 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
818 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
819 (GtkCellCallback)accum_cells,
822 return g_list_reverse (cells);
826 /*************************************************************
828 *************************************************************/
832 * @area: a #GtkCellArea
833 * @renderer: the #GtkCellRenderer to add to @area
835 * Adds @renderer to @area with the default child cell properties.
838 gtk_cell_area_add (GtkCellArea *area,
839 GtkCellRenderer *renderer)
841 GtkCellAreaClass *class;
843 g_return_if_fail (GTK_IS_CELL_AREA (area));
844 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
846 class = GTK_CELL_AREA_GET_CLASS (area);
849 class->add (area, renderer);
851 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
852 g_type_name (G_TYPE_FROM_INSTANCE (area)));
856 * gtk_cell_area_remove:
857 * @area: a #GtkCellArea
858 * @renderer: the #GtkCellRenderer to add to @area
860 * Removes @renderer from @area.
863 gtk_cell_area_remove (GtkCellArea *area,
864 GtkCellRenderer *renderer)
866 GtkCellAreaClass *class;
867 GtkCellAreaPrivate *priv;
869 g_return_if_fail (GTK_IS_CELL_AREA (area));
870 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
872 class = GTK_CELL_AREA_GET_CLASS (area);
875 /* Remove any custom attributes and custom cell data func here first */
876 g_hash_table_remove (priv->cell_info, renderer);
879 class->remove (area, renderer);
881 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
882 g_type_name (G_TYPE_FROM_INSTANCE (area)));
886 * gtk_cell_area_forall
887 * @area: a #GtkCellArea
888 * @callback: the #GtkCellCallback to call
889 * @callback_data: user provided data pointer
891 * Calls @callback for every #GtkCellRenderer in @area.
894 gtk_cell_area_forall (GtkCellArea *area,
895 GtkCellCallback callback,
896 gpointer callback_data)
898 GtkCellAreaClass *class;
900 g_return_if_fail (GTK_IS_CELL_AREA (area));
901 g_return_if_fail (callback != NULL);
903 class = GTK_CELL_AREA_GET_CLASS (area);
906 class->forall (area, callback, callback_data);
908 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
909 g_type_name (G_TYPE_FROM_INSTANCE (area)));
913 * gtk_cell_area_get_cell_allocation:
914 * @area: a #GtkCellArea
915 * @iter: the #GtkCellAreaIter used to hold sizes for @area.
916 * @widget: the #GtkWidget that @area is rendering on
917 * @renderer: the #GtkCellRenderer to get the allocation for
918 * @cell_area: the whole allocated area for @area in @widget
920 * @allocation: where to store the allocation for @renderer
922 * Derives the allocation of @renderer inside @area if @area
923 * were to be renderered in @cell_area.
926 gtk_cell_area_get_cell_allocation (GtkCellArea *area,
927 GtkCellAreaIter *iter,
929 GtkCellRenderer *renderer,
930 const GdkRectangle *cell_area,
931 GdkRectangle *allocation)
933 GtkCellAreaClass *class;
935 g_return_if_fail (GTK_IS_CELL_AREA (area));
936 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
937 g_return_if_fail (GTK_IS_WIDGET (widget));
938 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
939 g_return_if_fail (cell_area != NULL);
940 g_return_if_fail (allocation != NULL);
942 class = GTK_CELL_AREA_GET_CLASS (area);
944 if (class->get_cell_allocation)
945 class->get_cell_allocation (area, iter, widget, renderer, cell_area, allocation);
947 g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
948 g_type_name (G_TYPE_FROM_INSTANCE (area)));
952 gtk_cell_area_event (GtkCellArea *area,
953 GtkCellAreaIter *iter,
956 const GdkRectangle *cell_area,
957 GtkCellRendererState flags)
959 GtkCellAreaClass *class;
961 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
962 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
963 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
964 g_return_val_if_fail (event != NULL, 0);
965 g_return_val_if_fail (cell_area != NULL, 0);
967 class = GTK_CELL_AREA_GET_CLASS (area);
970 return class->event (area, iter, widget, event, cell_area, flags);
972 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
973 g_type_name (G_TYPE_FROM_INSTANCE (area)));
978 gtk_cell_area_render (GtkCellArea *area,
979 GtkCellAreaIter *iter,
982 const GdkRectangle *cell_area,
983 GtkCellRendererState flags)
985 GtkCellAreaClass *class;
987 g_return_if_fail (GTK_IS_CELL_AREA (area));
988 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
989 g_return_if_fail (GTK_IS_WIDGET (widget));
990 g_return_if_fail (cr != NULL);
991 g_return_if_fail (cell_area != NULL);
993 class = GTK_CELL_AREA_GET_CLASS (area);
996 class->render (area, iter, widget, cr, cell_area, flags);
998 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
999 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1002 /*************************************************************
1004 *************************************************************/
1006 gtk_cell_area_create_iter (GtkCellArea *area)
1008 GtkCellAreaClass *class;
1010 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1012 class = GTK_CELL_AREA_GET_CLASS (area);
1014 if (class->create_iter)
1015 return class->create_iter (area);
1017 g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'",
1018 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1025 gtk_cell_area_get_request_mode (GtkCellArea *area)
1027 GtkCellAreaClass *class;
1029 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
1030 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
1032 class = GTK_CELL_AREA_GET_CLASS (area);
1034 if (class->get_request_mode)
1035 return class->get_request_mode (area);
1037 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
1038 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1040 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
1044 gtk_cell_area_get_preferred_width (GtkCellArea *area,
1045 GtkCellAreaIter *iter,
1050 GtkCellAreaClass *class;
1052 g_return_if_fail (GTK_IS_CELL_AREA (area));
1053 g_return_if_fail (GTK_IS_WIDGET (widget));
1055 class = GTK_CELL_AREA_GET_CLASS (area);
1057 if (class->get_preferred_width)
1058 class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
1060 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
1061 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1065 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
1066 GtkCellAreaIter *iter,
1069 gint *minimum_height,
1070 gint *natural_height)
1072 GtkCellAreaClass *class;
1074 g_return_if_fail (GTK_IS_CELL_AREA (area));
1075 g_return_if_fail (GTK_IS_WIDGET (widget));
1077 class = GTK_CELL_AREA_GET_CLASS (area);
1078 class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
1082 gtk_cell_area_get_preferred_height (GtkCellArea *area,
1083 GtkCellAreaIter *iter,
1088 GtkCellAreaClass *class;
1090 g_return_if_fail (GTK_IS_CELL_AREA (area));
1091 g_return_if_fail (GTK_IS_WIDGET (widget));
1093 class = GTK_CELL_AREA_GET_CLASS (area);
1095 if (class->get_preferred_height)
1096 class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
1098 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
1099 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1103 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
1104 GtkCellAreaIter *iter,
1107 gint *minimum_width,
1108 gint *natural_width)
1110 GtkCellAreaClass *class;
1112 g_return_if_fail (GTK_IS_CELL_AREA (area));
1113 g_return_if_fail (GTK_IS_WIDGET (widget));
1115 class = GTK_CELL_AREA_GET_CLASS (area);
1116 class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
1119 /*************************************************************
1121 *************************************************************/
1124 * gtk_cell_area_attribute_connect:
1125 * @area: a #GtkCellArea
1126 * @renderer: the #GtkCellRenderer to connect an attribute for
1127 * @attribute: the attribute name
1128 * @column: the #GtkTreeModel column to fetch attribute values from
1130 * Connects an @attribute to apply values from @column for the
1131 * #GtkTreeModel in use.
1134 gtk_cell_area_attribute_connect (GtkCellArea *area,
1135 GtkCellRenderer *renderer,
1136 const gchar *attribute,
1139 GtkCellAreaPrivate *priv;
1141 CellAttribute *cell_attribute;
1143 g_return_if_fail (GTK_IS_CELL_AREA (area));
1144 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1145 g_return_if_fail (attribute != NULL);
1148 info = g_hash_table_lookup (priv->cell_info, renderer);
1152 info = cell_info_new (NULL, NULL, NULL);
1154 g_hash_table_insert (priv->cell_info, renderer, info);
1160 /* Check we are not adding the same attribute twice */
1161 if ((node = g_slist_find_custom (info->attributes, attribute,
1162 (GCompareFunc)cell_attribute_find)) != NULL)
1164 cell_attribute = node->data;
1166 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1167 "since `%s' is already attributed to column %d",
1169 g_type_name (G_TYPE_FROM_INSTANCE (area)),
1170 attribute, cell_attribute->column);
1175 cell_attribute = cell_attribute_new (renderer, attribute, column);
1177 if (!cell_attribute)
1179 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
1180 "since attribute does not exist",
1182 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1186 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
1190 * gtk_cell_area_attribute_disconnect:
1191 * @area: a #GtkCellArea
1192 * @renderer: the #GtkCellRenderer to disconnect an attribute for
1193 * @attribute: the attribute name
1195 * Disconnects @attribute for the @renderer in @area so that
1196 * attribute will no longer be updated with values from the
1200 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
1201 GtkCellRenderer *renderer,
1202 const gchar *attribute)
1204 GtkCellAreaPrivate *priv;
1206 CellAttribute *cell_attribute;
1209 g_return_if_fail (GTK_IS_CELL_AREA (area));
1210 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1211 g_return_if_fail (attribute != NULL);
1214 info = g_hash_table_lookup (priv->cell_info, renderer);
1218 node = g_slist_find_custom (info->attributes, attribute,
1219 (GCompareFunc)cell_attribute_find);
1222 cell_attribute = node->data;
1224 cell_attribute_free (cell_attribute);
1226 info->attributes = g_slist_delete_link (info->attributes, node);
1232 apply_cell_attributes (GtkCellRenderer *renderer,
1234 AttributeData *data)
1236 CellAttribute *attribute;
1238 GValue value = { 0, };
1239 gboolean is_expander;
1240 gboolean is_expanded;
1242 g_object_freeze_notify (G_OBJECT (renderer));
1244 /* Whether a row expands or is presently expanded can only be
1245 * provided by the view (as these states can vary across views
1246 * accessing the same model).
1248 g_object_get (renderer, "is-expander", &is_expander, NULL);
1249 if (is_expander != data->is_expander)
1250 g_object_set (renderer, "is-expander", data->is_expander, NULL);
1252 g_object_get (renderer, "is-expanded", &is_expanded, NULL);
1253 if (is_expanded != data->is_expanded)
1254 g_object_set (renderer, "is-expanded", data->is_expanded, NULL);
1256 /* Apply the attributes directly to the renderer */
1257 for (list = info->attributes; list; list = list->next)
1259 attribute = list->data;
1261 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
1262 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
1263 g_value_unset (&value);
1266 /* Call any GtkCellLayoutDataFunc that may have been set by the user
1269 info->func (GTK_CELL_LAYOUT (data->area), renderer,
1270 data->model, data->iter, info->data);
1272 g_object_thaw_notify (G_OBJECT (renderer));
1276 * gtk_cell_area_apply_attributes
1277 * @area: a #GtkCellArea
1278 * @tree_model: a #GtkTreeModel to pull values from
1279 * @iter: the #GtkTreeIter in @tree_model to apply values for
1280 * @is_expander: whether @iter has children
1281 * @is_expanded: whether @iter is expanded in the view and
1282 * children are visible
1284 * Applies any connected attributes to the renderers in
1285 * @area by pulling the values from @tree_model.
1288 gtk_cell_area_apply_attributes (GtkCellArea *area,
1289 GtkTreeModel *tree_model,
1291 gboolean is_expander,
1292 gboolean is_expanded)
1294 GtkCellAreaPrivate *priv;
1298 g_return_if_fail (GTK_IS_CELL_AREA (area));
1299 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
1300 g_return_if_fail (iter != NULL);
1304 /* Feed in data needed to apply to every renderer */
1306 data.model = tree_model;
1308 data.is_expander = is_expander;
1309 data.is_expanded = is_expanded;
1311 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
1312 * apply the data from the treemodel */
1313 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
1315 /* Update the currently applied path */
1316 g_free (priv->current_path);
1317 path = gtk_tree_model_get_path (tree_model, iter);
1318 priv->current_path = gtk_tree_path_to_string (path);
1319 gtk_tree_path_free (path);
1323 * gtk_cell_area_get_current_path_string:
1324 * @area: a #GtkCellArea
1326 * Gets the current #GtkTreePath string for the currently
1327 * applied #GtkTreeIter, this is implicitly updated when
1328 * gtk_cell_area_apply_attributes() is called and can be
1329 * used to interact with renderers from #GtkCellArea
1333 gtk_cell_area_get_current_path_string (GtkCellArea *area)
1335 GtkCellAreaPrivate *priv;
1337 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1341 return priv->current_path;
1345 /*************************************************************
1346 * API: Cell Properties *
1347 *************************************************************/
1349 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
1353 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
1354 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
1355 if (pspec->flags & G_PARAM_WRITABLE)
1356 g_return_if_fail (aclass->set_cell_property != NULL);
1357 if (pspec->flags & G_PARAM_READABLE)
1358 g_return_if_fail (aclass->get_cell_property != NULL);
1359 g_return_if_fail (property_id > 0);
1360 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
1361 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
1363 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
1365 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
1366 G_OBJECT_CLASS_NAME (aclass), pspec->name);
1369 g_param_spec_ref (pspec);
1370 g_param_spec_sink (pspec);
1371 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
1372 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
1376 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
1377 const gchar *property_name)
1379 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1380 g_return_val_if_fail (property_name != NULL, NULL);
1382 return g_param_spec_pool_lookup (cell_property_pool,
1384 G_OBJECT_CLASS_TYPE (aclass),
1389 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
1390 guint *n_properties)
1392 GParamSpec **pspecs;
1395 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
1397 pspecs = g_param_spec_pool_list (cell_property_pool,
1398 G_OBJECT_CLASS_TYPE (aclass),
1407 gtk_cell_area_add_with_properties (GtkCellArea *area,
1408 GtkCellRenderer *renderer,
1409 const gchar *first_prop_name,
1412 GtkCellAreaClass *class;
1414 g_return_if_fail (GTK_IS_CELL_AREA (area));
1415 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1417 class = GTK_CELL_AREA_GET_CLASS (area);
1423 class->add (area, renderer);
1425 va_start (var_args, first_prop_name);
1426 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1430 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1431 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1435 gtk_cell_area_cell_set (GtkCellArea *area,
1436 GtkCellRenderer *renderer,
1437 const gchar *first_prop_name,
1442 g_return_if_fail (GTK_IS_CELL_AREA (area));
1443 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1445 va_start (var_args, first_prop_name);
1446 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1451 gtk_cell_area_cell_get (GtkCellArea *area,
1452 GtkCellRenderer *renderer,
1453 const gchar *first_prop_name,
1458 g_return_if_fail (GTK_IS_CELL_AREA (area));
1459 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1461 va_start (var_args, first_prop_name);
1462 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1467 area_get_cell_property (GtkCellArea *area,
1468 GtkCellRenderer *renderer,
1472 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1474 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1478 area_set_cell_property (GtkCellArea *area,
1479 GtkCellRenderer *renderer,
1481 const GValue *value)
1483 GValue tmp_value = { 0, };
1484 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1486 /* provide a copy to work from, convert (if necessary) and validate */
1487 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1488 if (!g_value_transform (value, &tmp_value))
1489 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1491 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1492 G_VALUE_TYPE_NAME (value));
1493 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1495 gchar *contents = g_strdup_value_contents (value);
1497 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1499 G_VALUE_TYPE_NAME (value),
1501 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1506 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1508 g_value_unset (&tmp_value);
1512 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1513 GtkCellRenderer *renderer,
1514 const gchar *first_property_name,
1519 g_return_if_fail (GTK_IS_CELL_AREA (area));
1520 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1522 name = first_property_name;
1525 GValue value = { 0, };
1526 gchar *error = NULL;
1528 g_param_spec_pool_lookup (cell_property_pool, name,
1529 G_OBJECT_TYPE (area), TRUE);
1532 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1533 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1536 if (!(pspec->flags & G_PARAM_WRITABLE))
1538 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1539 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1543 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1544 G_VALUE_COLLECT (&value, var_args, 0, &error);
1547 g_warning ("%s: %s", G_STRLOC, error);
1550 /* we purposely leak the value here, it might not be
1551 * in a sane state if an error condition occoured
1555 area_set_cell_property (area, renderer, pspec, &value);
1556 g_value_unset (&value);
1557 name = va_arg (var_args, gchar*);
1562 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1563 GtkCellRenderer *renderer,
1564 const gchar *first_property_name,
1569 g_return_if_fail (GTK_IS_CELL_AREA (area));
1570 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1572 name = first_property_name;
1575 GValue value = { 0, };
1579 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1580 G_OBJECT_TYPE (area), TRUE);
1583 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1584 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1587 if (!(pspec->flags & G_PARAM_READABLE))
1589 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1590 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1594 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1595 area_get_cell_property (area, renderer, pspec, &value);
1596 G_VALUE_LCOPY (&value, var_args, 0, &error);
1599 g_warning ("%s: %s", G_STRLOC, error);
1601 g_value_unset (&value);
1604 g_value_unset (&value);
1605 name = va_arg (var_args, gchar*);
1610 gtk_cell_area_cell_set_property (GtkCellArea *area,
1611 GtkCellRenderer *renderer,
1612 const gchar *property_name,
1613 const GValue *value)
1617 g_return_if_fail (GTK_IS_CELL_AREA (area));
1618 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1619 g_return_if_fail (property_name != NULL);
1620 g_return_if_fail (G_IS_VALUE (value));
1622 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1623 G_OBJECT_TYPE (area), TRUE);
1625 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1626 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1627 else if (!(pspec->flags & G_PARAM_WRITABLE))
1628 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1629 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1632 area_set_cell_property (area, renderer, pspec, value);
1637 gtk_cell_area_cell_get_property (GtkCellArea *area,
1638 GtkCellRenderer *renderer,
1639 const gchar *property_name,
1644 g_return_if_fail (GTK_IS_CELL_AREA (area));
1645 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1646 g_return_if_fail (property_name != NULL);
1647 g_return_if_fail (G_IS_VALUE (value));
1649 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1650 G_OBJECT_TYPE (area), TRUE);
1652 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1653 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1654 else if (!(pspec->flags & G_PARAM_READABLE))
1655 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1656 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1659 GValue *prop_value, tmp_value = { 0, };
1661 /* auto-conversion of the callers value type
1663 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1665 g_value_reset (value);
1668 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1670 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1672 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1673 G_VALUE_TYPE_NAME (value));
1678 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1679 prop_value = &tmp_value;
1682 area_get_cell_property (area, renderer, pspec, prop_value);
1684 if (prop_value != value)
1686 g_value_transform (prop_value, value);
1687 g_value_unset (&tmp_value);
1692 /*************************************************************
1694 *************************************************************/
1697 * gtk_cell_area_grab_focus:
1698 * @area: a #GtkCellArea
1699 * @direction: the #GtkDirectionType from which focus came
1701 * This should be called by the @area's owning layout widget
1702 * when focus should be passed to @area for a given row data.
1704 * Note that after applying new attributes for @area that
1705 * gtk_cell_area_update_focus() should be called and
1706 * gtk_cell_area_can_focus() should be checked before trying
1707 * to pass focus to @area.
1709 * Implementing #GtkCellArea classes should implement this
1710 * method to receive focus in it's own way particular to
1711 * how it lays out cells.
1714 gtk_cell_area_grab_focus (GtkCellArea *area,
1715 GtkDirectionType direction)
1717 GtkCellAreaClass *class;
1719 g_return_if_fail (GTK_IS_CELL_AREA (area));
1721 class = GTK_CELL_AREA_GET_CLASS (area);
1723 if (class->grab_focus)
1724 class->grab_focus (area, direction);
1726 g_warning ("GtkCellAreaClass::grab_focus not implemented for `%s'",
1727 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1731 * gtk_cell_area_focus_leave:
1732 * @area: a #GtkCellArea
1733 * @direction: the #GtkDirectionType in which focus
1735 * @path: the current #GtkTreePath string for the
1736 * event which was handled by @area
1738 * Notifies that focus is to leave @area in the
1741 * This is called by #GtkCellArea implementations upon
1742 * handling a key event that caused focus to leave the
1743 * cell. The resulting signal can be handled by the
1744 * owning layouting widget to decide which new @area
1745 * to pass focus to and from what @direction. Or to
1746 * pass focus along to an entirely new data row.
1749 gtk_cell_area_focus_leave (GtkCellArea *area,
1750 GtkDirectionType direction,
1753 g_return_if_fail (GTK_IS_CELL_AREA (area));
1755 g_signal_emit (area, cell_area_signals[SIGNAL_FOCUS_LEAVE], 0, direction, path);
1759 * gtk_cell_area_update_focus:
1760 * @area: a #GtkCellArea
1762 * Updates focus information on @area for a given
1765 * After calling gtk_cell_area_apply_attributes() to
1766 * the @area this method should be called to update
1767 * information about whether the @area can focus and
1768 * which is the cell currently in focus.
1771 gtk_cell_area_update_focus (GtkCellArea *area)
1773 g_return_if_fail (GTK_IS_CELL_AREA (area));
1775 GTK_CELL_AREA_GET_CLASS (area)->update_focus (area);
1779 * gtk_cell_area_set_can_focus:
1780 * @area: a #GtkCellArea
1781 * @can_focus: whether @area can receive focus
1783 * This is generally called from GtkCellArea::update_focus()
1784 * implementations to update if the @area can focus after
1785 * applying new row data attributes.
1788 gtk_cell_area_set_can_focus (GtkCellArea *area,
1791 GtkCellAreaPrivate *priv;
1793 g_return_if_fail (GTK_IS_CELL_AREA (area));
1797 if (priv->can_focus != can_focus)
1799 priv->can_focus = can_focus;
1804 * gtk_cell_area_get_can_focus:
1805 * @area: a #GtkCellArea
1807 * Returns whether the area can receive keyboard focus,
1808 * after applying new attributes to @area,
1809 * gtk_cell_area_update_focus() needs to be called before
1810 * calling this method.
1812 * Returns: whether @area can receive focus.
1815 gtk_cell_area_get_can_focus (GtkCellArea *area)
1817 GtkCellAreaPrivate *priv;
1819 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
1823 return priv->can_focus;
1828 * gtk_cell_area_set_focus_cell:
1829 * @area: a #GtkCellArea
1830 * @focus_cell: the #GtkCellRenderer to give focus to
1832 * This is generally called from #GtkCellArea implementations
1833 * either gtk_cell_area_grab_focus() or gtk_cell_area_update_focus()
1834 * is called. It's also up to the #GtkCellArea implementation
1835 * to update the focused cell when receiving events from
1836 * gtk_cell_area_event() appropriately.
1839 gtk_cell_area_set_focus_cell (GtkCellArea *area,
1840 GtkCellRenderer *renderer)
1842 GtkCellAreaPrivate *priv;
1844 g_return_if_fail (GTK_IS_CELL_AREA (area));
1845 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1849 if (priv->focus_cell != renderer)
1851 if (priv->focus_cell)
1852 g_object_unref (priv->focus_cell);
1854 priv->focus_cell = renderer;
1856 if (priv->focus_cell)
1857 g_object_ref (priv->focus_cell);
1859 g_object_notify (G_OBJECT (area), "focus-cell");
1864 * gtk_cell_area_get_focus_cell:
1865 * @area: a #GtkCellArea
1867 * Retrieves the currently focused cell for @area
1869 * Returns: the currently focused cell in @area.
1872 gtk_cell_area_get_focus_cell (GtkCellArea *area)
1874 GtkCellAreaPrivate *priv;
1876 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1880 return priv->focus_cell;
1884 /*************************************************************
1885 * API: Cell Activation/Editing *
1886 *************************************************************/
1888 gtk_cell_area_editing_started (GtkCellArea *area,
1889 GtkCellRenderer *renderer,
1890 GtkCellEditable *editable)
1892 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_STARTED], 0,
1893 renderer, editable, area->priv->current_path);
1897 gtk_cell_area_editing_canceled (GtkCellArea *area,
1898 GtkCellRenderer *renderer)
1900 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_CANCELED], 0, renderer);
1904 gtk_cell_area_editing_done (GtkCellArea *area,
1905 GtkCellRenderer *renderer,
1906 GtkCellEditable *editable)
1908 g_signal_emit (area, cell_area_signals[SIGNAL_EDITING_DONE], 0, renderer, editable);
1912 gtk_cell_area_remove_editable (GtkCellArea *area,
1913 GtkCellRenderer *renderer,
1914 GtkCellEditable *editable)
1916 g_signal_emit (area, cell_area_signals[SIGNAL_REMOVE_EDITABLE], 0, renderer, editable);
1920 cell_area_editing_done_cb (GtkCellEditable *editable,
1923 GtkCellAreaPrivate *priv = area->priv;
1925 g_assert (priv->edit_widget == editable);
1926 g_assert (priv->edited_cell != NULL);
1928 gtk_cell_area_editing_done (area, priv->edited_cell, priv->edit_widget);
1932 cell_area_remove_widget_cb (GtkCellEditable *editable,
1935 GtkCellAreaPrivate *priv = area->priv;
1937 g_assert (priv->edit_widget == editable);
1938 g_assert (priv->edited_cell != NULL);
1940 gtk_cell_area_remove_editable (area, priv->edited_cell, priv->edit_widget);
1942 /* Now that we're done with editing the widget and it can be removed,
1943 * remove our references to the widget and disconnect handlers */
1944 gtk_cell_area_set_edited_cell (area, NULL);
1945 gtk_cell_area_set_edit_widget (area, NULL);
1949 gtk_cell_area_set_edited_cell (GtkCellArea *area,
1950 GtkCellRenderer *renderer)
1952 GtkCellAreaPrivate *priv;
1954 g_return_if_fail (GTK_IS_CELL_AREA (area));
1955 g_return_if_fail (renderer == NULL || GTK_IS_CELL_RENDERER (renderer));
1959 if (priv->edited_cell != renderer)
1961 if (priv->edited_cell)
1962 g_object_unref (priv->edited_cell);
1964 priv->edited_cell = renderer;
1966 if (priv->edited_cell)
1967 g_object_ref (priv->edited_cell);
1969 g_object_notify (G_OBJECT (area), "edited-cell");
1974 gtk_cell_area_get_edited_cell (GtkCellArea *area)
1976 GtkCellAreaPrivate *priv;
1978 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
1982 return priv->edited_cell;
1986 gtk_cell_area_set_edit_widget (GtkCellArea *area,
1987 GtkCellEditable *editable)
1989 GtkCellAreaPrivate *priv;
1991 g_return_if_fail (GTK_IS_CELL_AREA (area));
1992 g_return_if_fail (editable == NULL || GTK_IS_CELL_EDITABLE (editable));
1996 if (priv->edit_widget != editable)
1998 if (priv->edit_widget)
2000 g_signal_handler_disconnect (priv->edit_widget, priv->editing_done_id);
2001 g_signal_handler_disconnect (priv->edit_widget, priv->remove_widget_id);
2003 g_object_unref (priv->edit_widget);
2006 priv->edit_widget = editable;
2008 if (priv->edit_widget)
2010 priv->editing_done_id =
2011 g_signal_connect (priv->edit_widget, "editing-done",
2012 G_CALLBACK (cell_area_editing_done_cb), area);
2013 priv->remove_widget_id =
2014 g_signal_connect (priv->edit_widget, "remove-widget",
2015 G_CALLBACK (cell_area_remove_widget_cb), area);
2017 g_object_ref (priv->edit_widget);
2020 g_object_notify (G_OBJECT (area), "edit-widget");
2025 gtk_cell_area_get_edit_widget (GtkCellArea *area)
2027 GtkCellAreaPrivate *priv;
2029 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
2033 return priv->edit_widget;
2037 gtk_cell_area_activate_cell (GtkCellArea *area,
2039 GtkCellRenderer *renderer,
2041 const GdkRectangle *cell_area,
2042 GtkCellRendererState flags)
2044 GtkCellRendererMode mode;
2045 GdkRectangle inner_area;
2046 GtkCellAreaPrivate *priv;
2048 g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
2049 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
2050 g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
2051 g_return_val_if_fail (event != NULL, FALSE);
2052 g_return_val_if_fail (cell_area != NULL, FALSE);
2056 /* Remove margins from the background area to produce the cell area.
2058 * XXX Maybe have to do some rtl mode treatment here...
2060 gtk_cell_area_inner_cell_area (area, cell_area, &inner_area);
2062 g_object_get (renderer, "mode", &mode, NULL);
2064 if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2066 if (gtk_cell_renderer_activate (renderer,
2074 else if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2076 GtkCellEditable *editable_widget;
2079 gtk_cell_renderer_start_editing (renderer,
2086 if (editable_widget != NULL)
2088 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (editable_widget), FALSE);
2090 gtk_cell_area_set_edited_cell (area, renderer);
2091 gtk_cell_area_set_edit_widget (area, editable_widget);
2093 /* Signal that editing started so that callers can get
2094 * a handle on the editable_widget */
2095 gtk_cell_area_editing_started (area, priv->focus_cell, editable_widget);
2105 /*************************************************************
2107 *************************************************************/
2109 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
2111 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2113 return area->priv->cell_border.left;
2117 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
2120 GtkCellAreaPrivate *priv;
2122 g_return_if_fail (GTK_IS_CELL_AREA (area));
2126 if (priv->cell_border.left != margin)
2128 priv->cell_border.left = margin;
2130 g_object_notify (G_OBJECT (area), "margin-left");
2135 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
2137 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2139 return area->priv->cell_border.right;
2143 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
2146 GtkCellAreaPrivate *priv;
2148 g_return_if_fail (GTK_IS_CELL_AREA (area));
2152 if (priv->cell_border.right != margin)
2154 priv->cell_border.right = margin;
2156 g_object_notify (G_OBJECT (area), "margin-right");
2161 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
2163 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2165 return area->priv->cell_border.top;
2169 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
2172 GtkCellAreaPrivate *priv;
2174 g_return_if_fail (GTK_IS_CELL_AREA (area));
2178 if (priv->cell_border.top != margin)
2180 priv->cell_border.top = margin;
2182 g_object_notify (G_OBJECT (area), "margin-top");
2187 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
2189 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
2191 return area->priv->cell_border.bottom;
2195 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
2198 GtkCellAreaPrivate *priv;
2200 g_return_if_fail (GTK_IS_CELL_AREA (area));
2204 if (priv->cell_border.bottom != margin)
2206 priv->cell_border.bottom = margin;
2208 g_object_notify (G_OBJECT (area), "margin-bottom");
2213 gtk_cell_area_inner_cell_area (GtkCellArea *area,
2214 const GdkRectangle *background_area,
2215 GdkRectangle *cell_area)
2217 GtkCellAreaPrivate *priv;
2219 g_return_if_fail (GTK_IS_CELL_AREA (area));
2220 g_return_if_fail (background_area != NULL);
2221 g_return_if_fail (cell_area != NULL);
2225 *cell_area = *background_area;
2227 cell_area->x += priv->cell_border.left;
2228 cell_area->width -= (priv->cell_border.left + priv->cell_border.right);
2229 cell_area->y += priv->cell_border.top;
2230 cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
2234 gtk_cell_area_request_renderer (GtkCellArea *area,
2235 GtkCellRenderer *renderer,
2236 GtkOrientation orientation,
2242 GtkCellAreaPrivate *priv;
2244 g_return_if_fail (GTK_IS_CELL_AREA (area));
2245 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
2246 g_return_if_fail (GTK_IS_WIDGET (widget));
2247 g_return_if_fail (minimum_size != NULL);
2248 g_return_if_fail (natural_size != NULL);
2252 if (orientation == GTK_ORIENTATION_HORIZONTAL)
2255 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
2258 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
2260 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
2261 minimum_size, natural_size);
2264 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
2265 *natural_size += (priv->cell_border.left + priv->cell_border.right);
2267 else /* GTK_ORIENTATION_VERTICAL */
2270 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
2273 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
2275 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
2276 minimum_size, natural_size);
2279 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
2280 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);