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 "gtkprivate.h"
36 #include <gobject/gvaluecollector.h>
40 static void gtk_cell_area_dispose (GObject *object);
41 static void gtk_cell_area_finalize (GObject *object);
42 static void gtk_cell_area_set_property (GObject *object,
46 static void gtk_cell_area_get_property (GObject *object,
51 /* GtkCellAreaClass */
52 static void gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
53 GtkCellAreaIter *iter,
57 gint *natural_height);
58 static void gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
59 GtkCellAreaIter *iter,
65 /* GtkCellLayoutIface */
66 static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
67 static void gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
68 GtkCellRenderer *renderer,
70 static void gtk_cell_area_clear (GtkCellLayout *cell_layout);
71 static void gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
72 GtkCellRenderer *renderer,
73 const gchar *attribute,
75 static void gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
76 GtkCellRenderer *cell,
77 GtkCellLayoutDataFunc func,
79 GDestroyNotify destroy);
80 static void gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
81 GtkCellRenderer *renderer);
82 static void gtk_cell_area_reorder (GtkCellLayout *cell_layout,
83 GtkCellRenderer *cell,
85 static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
87 /* Attribute/Cell metadata */
89 const gchar *attribute;
96 GtkCellLayoutDataFunc func;
98 GDestroyNotify destroy;
101 static CellInfo *cell_info_new (GtkCellLayoutDataFunc func,
103 GDestroyNotify destroy);
104 static void cell_info_free (CellInfo *info);
105 static CellAttribute *cell_attribute_new (GtkCellRenderer *renderer,
106 const gchar *attribute,
108 static void cell_attribute_free (CellAttribute *attribute);
109 static gint cell_attribute_find (CellAttribute *cell_attribute,
110 const gchar *attribute);
112 /* Struct to pass data along while looping over
113 * cell renderers to apply attributes
121 struct _GtkCellAreaPrivate
123 GHashTable *cell_info;
125 GtkBorder cell_border;
128 /* Keep the paramspec pool internal, no need to deliver notifications
129 * on cells. at least no percieved need for now */
130 static GParamSpecPool *cell_property_pool = NULL;
132 #define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
133 #define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
137 PROP_CELL_MARGIN_LEFT,
138 PROP_CELL_MARGIN_RIGHT,
139 PROP_CELL_MARGIN_TOP,
140 PROP_CELL_MARGIN_BOTTOM
143 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
144 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
145 gtk_cell_area_cell_layout_init));
148 gtk_cell_area_init (GtkCellArea *area)
150 GtkCellAreaPrivate *priv;
152 area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area,
157 priv->cell_info = g_hash_table_new_full (g_direct_hash,
160 (GDestroyNotify)cell_info_free);
162 priv->cell_border.left = 0;
163 priv->cell_border.right = 0;
164 priv->cell_border.top = 0;
165 priv->cell_border.bottom = 0;
169 gtk_cell_area_class_init (GtkCellAreaClass *class)
171 GObjectClass *object_class = G_OBJECT_CLASS (class);
174 object_class->dispose = gtk_cell_area_dispose;
175 object_class->finalize = gtk_cell_area_finalize;
176 object_class->get_property = gtk_cell_area_get_property;
177 object_class->set_property = gtk_cell_area_set_property;
181 class->remove = NULL;
182 class->forall = NULL;
184 class->render = NULL;
187 class->create_iter = NULL;
188 class->get_request_mode = NULL;
189 class->get_preferred_width = NULL;
190 class->get_preferred_height = NULL;
191 class->get_preferred_height_for_width = gtk_cell_area_real_get_preferred_height_for_width;
192 class->get_preferred_width_for_height = gtk_cell_area_real_get_preferred_width_for_height;
195 g_object_class_install_property (object_class,
196 PROP_CELL_MARGIN_LEFT,
199 P_("Margin on Left"),
200 P_("Pixels of extra space on the left side of each cell"),
204 GTK_PARAM_READWRITE));
206 g_object_class_install_property (object_class,
207 PROP_CELL_MARGIN_RIGHT,
209 ("cell-margin-right",
210 P_("Margin on Right"),
211 P_("Pixels of extra space on the right side of each cell"),
215 GTK_PARAM_READWRITE));
217 g_object_class_install_property (object_class,
218 PROP_CELL_MARGIN_TOP,
222 P_("Pixels of extra space on the top side of each cell"),
226 GTK_PARAM_READWRITE));
228 g_object_class_install_property (object_class,
229 PROP_CELL_MARGIN_BOTTOM,
231 ("cell-margin-bottom",
232 P_("Margin on Bottom"),
233 P_("Pixels of extra space on the bottom side of each cell"),
237 GTK_PARAM_READWRITE));
239 /* Pool for Cell Properties */
240 if (!cell_property_pool)
241 cell_property_pool = g_param_spec_pool_new (FALSE);
243 g_type_class_add_private (object_class, sizeof (GtkCellAreaPrivate));
246 /*************************************************************
248 *************************************************************/
250 cell_info_new (GtkCellLayoutDataFunc func,
252 GDestroyNotify destroy)
254 CellInfo *info = g_slice_new (CellInfo);
256 info->attributes = NULL;
259 info->destroy = destroy;
265 cell_info_free (CellInfo *info)
268 info->destroy (info->data);
270 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
271 g_slist_free (info->attributes);
273 g_slice_free (CellInfo, info);
276 static CellAttribute *
277 cell_attribute_new (GtkCellRenderer *renderer,
278 const gchar *attribute,
283 /* Check if the attribute really exists and point to
284 * the property string installed on the cell renderer
285 * class (dont dup the string)
287 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (renderer), attribute);
291 CellAttribute *cell_attribute = g_slice_new (CellAttribute);
293 cell_attribute->attribute = pspec->name;
294 cell_attribute->column = column;
296 return cell_attribute;
303 cell_attribute_free (CellAttribute *attribute)
305 g_slice_free (CellAttribute, attribute);
308 /* GCompareFunc for g_slist_find_custom() */
310 cell_attribute_find (CellAttribute *cell_attribute,
311 const gchar *attribute)
313 return g_strcmp0 (cell_attribute->attribute, attribute);
316 /*************************************************************
318 *************************************************************/
320 gtk_cell_area_finalize (GObject *object)
322 GtkCellArea *area = GTK_CELL_AREA (object);
323 GtkCellAreaPrivate *priv = area->priv;
325 /* All cell renderers should already be removed at this point,
326 * just kill our hash table here.
328 g_hash_table_destroy (priv->cell_info);
330 G_OBJECT_CLASS (gtk_cell_area_parent_class)->finalize (object);
335 gtk_cell_area_dispose (GObject *object)
337 /* This removes every cell renderer that may be added to the GtkCellArea,
338 * subclasses should be breaking references to the GtkCellRenderers
341 gtk_cell_layout_clear (GTK_CELL_LAYOUT (object));
343 G_OBJECT_CLASS (gtk_cell_area_parent_class)->dispose (object);
347 gtk_cell_area_set_property (GObject *object,
352 GtkCellArea *area = GTK_CELL_AREA (object);
356 case PROP_CELL_MARGIN_LEFT:
357 gtk_cell_area_set_cell_margin_left (area, g_value_get_int (value));
359 case PROP_CELL_MARGIN_RIGHT:
360 gtk_cell_area_set_cell_margin_right (area, g_value_get_int (value));
362 case PROP_CELL_MARGIN_TOP:
363 gtk_cell_area_set_cell_margin_top (area, g_value_get_int (value));
365 case PROP_CELL_MARGIN_BOTTOM:
366 gtk_cell_area_set_cell_margin_bottom (area, g_value_get_int (value));
369 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
375 gtk_cell_area_get_property (GObject *object,
380 GtkCellArea *area = GTK_CELL_AREA (object);
381 GtkCellAreaPrivate *priv = area->priv;
385 case PROP_CELL_MARGIN_LEFT:
386 g_value_set_int (value, priv->cell_border.left);
388 case PROP_CELL_MARGIN_RIGHT:
389 g_value_set_int (value, priv->cell_border.right);
391 case PROP_CELL_MARGIN_TOP:
392 g_value_set_int (value, priv->cell_border.top);
394 case PROP_CELL_MARGIN_BOTTOM:
395 g_value_set_int (value, priv->cell_border.bottom);
398 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
403 /*************************************************************
405 *************************************************************/
407 gtk_cell_area_real_get_preferred_height_for_width (GtkCellArea *area,
408 GtkCellAreaIter *iter,
411 gint *minimum_height,
412 gint *natural_height)
414 /* If the area doesnt do height-for-width, fallback on base preferred height */
415 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_height, natural_height);
419 gtk_cell_area_real_get_preferred_width_for_height (GtkCellArea *area,
420 GtkCellAreaIter *iter,
426 /* If the area doesnt do width-for-height, fallback on base preferred width */
427 GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, iter, widget, minimum_width, natural_width);
430 /*************************************************************
431 * GtkCellLayoutIface *
432 *************************************************************/
434 gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface)
436 iface->pack_start = gtk_cell_area_pack_default;
437 iface->pack_end = gtk_cell_area_pack_default;
438 iface->clear = gtk_cell_area_clear;
439 iface->add_attribute = gtk_cell_area_add_attribute;
440 iface->set_cell_data_func = gtk_cell_area_set_cell_data_func;
441 iface->clear_attributes = gtk_cell_area_clear_attributes;
442 iface->reorder = gtk_cell_area_reorder;
443 iface->get_cells = gtk_cell_area_get_cells;
447 gtk_cell_area_pack_default (GtkCellLayout *cell_layout,
448 GtkCellRenderer *renderer,
451 gtk_cell_area_add (GTK_CELL_AREA (cell_layout), renderer);
455 gtk_cell_area_clear (GtkCellLayout *cell_layout)
457 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
459 gtk_cell_layout_get_cells (cell_layout);
461 for (l = cells; l; l = l->next)
463 GtkCellRenderer *renderer = l->data;
464 gtk_cell_area_remove (area, renderer);
471 gtk_cell_area_add_attribute (GtkCellLayout *cell_layout,
472 GtkCellRenderer *renderer,
473 const gchar *attribute,
476 gtk_cell_area_attribute_connect (GTK_CELL_AREA (cell_layout),
477 renderer, attribute, column);
481 gtk_cell_area_set_cell_data_func (GtkCellLayout *cell_layout,
482 GtkCellRenderer *renderer,
483 GtkCellLayoutDataFunc func,
485 GDestroyNotify destroy)
487 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
488 GtkCellAreaPrivate *priv = area->priv;
491 info = g_hash_table_lookup (priv->cell_info, renderer);
495 if (info->destroy && info->data)
496 info->destroy (info->data);
501 info->data = func_data;
502 info->destroy = destroy;
508 info->destroy = NULL;
513 info = cell_info_new (func, func_data, destroy);
515 g_hash_table_insert (priv->cell_info, renderer, info);
520 gtk_cell_area_clear_attributes (GtkCellLayout *cell_layout,
521 GtkCellRenderer *renderer)
523 GtkCellArea *area = GTK_CELL_AREA (cell_layout);
524 GtkCellAreaPrivate *priv = area->priv;
527 info = g_hash_table_lookup (priv->cell_info, renderer);
531 g_slist_foreach (info->attributes, (GFunc)cell_attribute_free, NULL);
532 g_slist_free (info->attributes);
534 info->attributes = NULL;
539 gtk_cell_area_reorder (GtkCellLayout *cell_layout,
540 GtkCellRenderer *cell,
543 g_warning ("GtkCellLayout::reorder not implemented for `%s'",
544 g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
548 accum_cells (GtkCellRenderer *renderer,
551 *accum = g_list_prepend (*accum, renderer);
555 gtk_cell_area_get_cells (GtkCellLayout *cell_layout)
559 gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
560 (GtkCellCallback)accum_cells,
563 return g_list_reverse (cells);
567 /*************************************************************
569 *************************************************************/
571 gtk_cell_area_add (GtkCellArea *area,
572 GtkCellRenderer *renderer)
574 GtkCellAreaClass *class;
576 g_return_if_fail (GTK_IS_CELL_AREA (area));
577 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
579 class = GTK_CELL_AREA_GET_CLASS (area);
582 class->add (area, renderer);
584 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
585 g_type_name (G_TYPE_FROM_INSTANCE (area)));
589 gtk_cell_area_remove (GtkCellArea *area,
590 GtkCellRenderer *renderer)
592 GtkCellAreaClass *class;
593 GtkCellAreaPrivate *priv;
595 g_return_if_fail (GTK_IS_CELL_AREA (area));
596 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
598 class = GTK_CELL_AREA_GET_CLASS (area);
601 /* Remove any custom attributes and custom cell data func here first */
602 g_hash_table_remove (priv->cell_info, renderer);
605 class->remove (area, renderer);
607 g_warning ("GtkCellAreaClass::remove not implemented for `%s'",
608 g_type_name (G_TYPE_FROM_INSTANCE (area)));
612 gtk_cell_area_forall (GtkCellArea *area,
613 GtkCellCallback callback,
614 gpointer callback_data)
616 GtkCellAreaClass *class;
618 g_return_if_fail (GTK_IS_CELL_AREA (area));
619 g_return_if_fail (callback != NULL);
621 class = GTK_CELL_AREA_GET_CLASS (area);
624 class->forall (area, callback, callback_data);
626 g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
627 g_type_name (G_TYPE_FROM_INSTANCE (area)));
631 gtk_cell_area_event (GtkCellArea *area,
632 GtkCellAreaIter *iter,
635 const GdkRectangle *cell_area,
636 GtkCellRendererState flags)
638 GtkCellAreaClass *class;
640 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
641 g_return_val_if_fail (GTK_IS_CELL_AREA_ITER (iter), 0);
642 g_return_val_if_fail (GTK_IS_WIDGET (widget), 0);
643 g_return_val_if_fail (event != NULL, 0);
644 g_return_val_if_fail (cell_area != NULL, 0);
646 class = GTK_CELL_AREA_GET_CLASS (area);
649 return class->event (area, iter, widget, event, cell_area, flags);
651 g_warning ("GtkCellAreaClass::event not implemented for `%s'",
652 g_type_name (G_TYPE_FROM_INSTANCE (area)));
657 gtk_cell_area_render (GtkCellArea *area,
658 GtkCellAreaIter *iter,
661 const GdkRectangle *cell_area,
662 GtkCellRendererState flags)
664 GtkCellAreaClass *class;
666 g_return_if_fail (GTK_IS_CELL_AREA (area));
667 g_return_if_fail (GTK_IS_CELL_AREA_ITER (iter));
668 g_return_if_fail (GTK_IS_WIDGET (widget));
669 g_return_if_fail (cr != NULL);
670 g_return_if_fail (cell_area != NULL);
672 class = GTK_CELL_AREA_GET_CLASS (area);
675 class->render (area, iter, widget, cr, cell_area, flags);
677 g_warning ("GtkCellAreaClass::render not implemented for `%s'",
678 g_type_name (G_TYPE_FROM_INSTANCE (area)));
683 gtk_cell_area_create_iter (GtkCellArea *area)
685 GtkCellAreaClass *class;
687 g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
689 class = GTK_CELL_AREA_GET_CLASS (area);
691 if (class->create_iter)
692 return class->create_iter (area);
694 g_warning ("GtkCellAreaClass::create_iter not implemented for `%s'",
695 g_type_name (G_TYPE_FROM_INSTANCE (area)));
702 gtk_cell_area_get_request_mode (GtkCellArea *area)
704 GtkCellAreaClass *class;
706 g_return_val_if_fail (GTK_IS_CELL_AREA (area),
707 GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH);
709 class = GTK_CELL_AREA_GET_CLASS (area);
711 if (class->get_request_mode)
712 return class->get_request_mode (area);
714 g_warning ("GtkCellAreaClass::get_request_mode not implemented for `%s'",
715 g_type_name (G_TYPE_FROM_INSTANCE (area)));
717 return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
721 gtk_cell_area_get_preferred_width (GtkCellArea *area,
722 GtkCellAreaIter *iter,
727 GtkCellAreaClass *class;
729 g_return_if_fail (GTK_IS_CELL_AREA (area));
730 g_return_if_fail (GTK_IS_WIDGET (widget));
732 class = GTK_CELL_AREA_GET_CLASS (area);
734 if (class->get_preferred_width)
735 class->get_preferred_width (area, iter, widget, minimum_size, natural_size);
737 g_warning ("GtkCellAreaClass::get_preferred_width not implemented for `%s'",
738 g_type_name (G_TYPE_FROM_INSTANCE (area)));
742 gtk_cell_area_get_preferred_height_for_width (GtkCellArea *area,
743 GtkCellAreaIter *iter,
746 gint *minimum_height,
747 gint *natural_height)
749 GtkCellAreaClass *class;
751 g_return_if_fail (GTK_IS_CELL_AREA (area));
752 g_return_if_fail (GTK_IS_WIDGET (widget));
754 class = GTK_CELL_AREA_GET_CLASS (area);
755 class->get_preferred_height_for_width (area, iter, widget, width, minimum_height, natural_height);
759 gtk_cell_area_get_preferred_height (GtkCellArea *area,
760 GtkCellAreaIter *iter,
765 GtkCellAreaClass *class;
767 g_return_if_fail (GTK_IS_CELL_AREA (area));
768 g_return_if_fail (GTK_IS_WIDGET (widget));
770 class = GTK_CELL_AREA_GET_CLASS (area);
772 if (class->get_preferred_height)
773 class->get_preferred_height (area, iter, widget, minimum_size, natural_size);
775 g_warning ("GtkCellAreaClass::get_preferred_height not implemented for `%s'",
776 g_type_name (G_TYPE_FROM_INSTANCE (area)));
780 gtk_cell_area_get_preferred_width_for_height (GtkCellArea *area,
781 GtkCellAreaIter *iter,
787 GtkCellAreaClass *class;
789 g_return_if_fail (GTK_IS_CELL_AREA (area));
790 g_return_if_fail (GTK_IS_WIDGET (widget));
792 class = GTK_CELL_AREA_GET_CLASS (area);
793 class->get_preferred_width_for_height (area, iter, widget, height, minimum_width, natural_width);
798 gtk_cell_area_attribute_connect (GtkCellArea *area,
799 GtkCellRenderer *renderer,
800 const gchar *attribute,
803 GtkCellAreaPrivate *priv;
805 CellAttribute *cell_attribute;
807 g_return_if_fail (GTK_IS_CELL_AREA (area));
808 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
809 g_return_if_fail (attribute != NULL);
812 info = g_hash_table_lookup (priv->cell_info, renderer);
816 info = cell_info_new (NULL, NULL, NULL);
818 g_hash_table_insert (priv->cell_info, renderer, info);
824 /* Check we are not adding the same attribute twice */
825 if ((node = g_slist_find_custom (info->attributes, attribute,
826 (GCompareFunc)cell_attribute_find)) != NULL)
828 cell_attribute = node->data;
830 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
831 "since `%s' is already attributed to column %d",
833 g_type_name (G_TYPE_FROM_INSTANCE (area)),
834 attribute, cell_attribute->column);
839 cell_attribute = cell_attribute_new (renderer, attribute, column);
843 g_warning ("Cannot connect attribute `%s' for cell renderer class `%s' "
844 "since attribute does not exist",
846 g_type_name (G_TYPE_FROM_INSTANCE (area)));
850 info->attributes = g_slist_prepend (info->attributes, cell_attribute);
854 gtk_cell_area_attribute_disconnect (GtkCellArea *area,
855 GtkCellRenderer *renderer,
856 const gchar *attribute)
858 GtkCellAreaPrivate *priv;
860 CellAttribute *cell_attribute;
863 g_return_if_fail (GTK_IS_CELL_AREA (area));
864 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
865 g_return_if_fail (attribute != NULL);
868 info = g_hash_table_lookup (priv->cell_info, renderer);
872 node = g_slist_find_custom (info->attributes, attribute,
873 (GCompareFunc)cell_attribute_find);
876 cell_attribute = node->data;
878 cell_attribute_free (cell_attribute);
880 info->attributes = g_slist_delete_link (info->attributes, node);
886 apply_cell_attributes (GtkCellRenderer *renderer,
890 CellAttribute *attribute;
892 GValue value = { 0, };
894 /* Apply the attributes directly to the renderer */
895 for (list = info->attributes; list; list = list->next)
897 attribute = list->data;
899 gtk_tree_model_get_value (data->model, data->iter, attribute->column, &value);
900 g_object_set_property (G_OBJECT (renderer), attribute->attribute, &value);
901 g_value_unset (&value);
904 /* Call any GtkCellLayoutDataFunc that may have been set by the user
907 info->func (GTK_CELL_LAYOUT (data->area), renderer,
908 data->model, data->iter, info->data);
912 gtk_cell_area_apply_attributes (GtkCellArea *area,
913 GtkTreeModel *tree_model,
916 GtkCellAreaPrivate *priv;
919 g_return_if_fail (GTK_IS_CELL_AREA (area));
920 g_return_if_fail (GTK_IS_TREE_MODEL (tree_model));
921 g_return_if_fail (iter != NULL);
925 /* Go over any cells that have attributes or custom GtkCellLayoutDataFuncs and
926 * apply the data from the treemodel */
927 g_hash_table_foreach (priv->cell_info, (GHFunc)apply_cell_attributes, &data);
930 /* Cell Properties */
932 gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
936 g_return_if_fail (GTK_IS_CELL_AREA_CLASS (aclass));
937 g_return_if_fail (G_IS_PARAM_SPEC (pspec));
938 if (pspec->flags & G_PARAM_WRITABLE)
939 g_return_if_fail (aclass->set_cell_property != NULL);
940 if (pspec->flags & G_PARAM_READABLE)
941 g_return_if_fail (aclass->get_cell_property != NULL);
942 g_return_if_fail (property_id > 0);
943 g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0); /* paranoid */
944 g_return_if_fail ((pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)) == 0);
946 if (g_param_spec_pool_lookup (cell_property_pool, pspec->name, G_OBJECT_CLASS_TYPE (aclass), TRUE))
948 g_warning (G_STRLOC ": class `%s' already contains a cell property named `%s'",
949 G_OBJECT_CLASS_NAME (aclass), pspec->name);
952 g_param_spec_ref (pspec);
953 g_param_spec_sink (pspec);
954 PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
955 g_param_spec_pool_insert (cell_property_pool, pspec, G_OBJECT_CLASS_TYPE (aclass));
959 gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
960 const gchar *property_name)
962 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
963 g_return_val_if_fail (property_name != NULL, NULL);
965 return g_param_spec_pool_lookup (cell_property_pool,
967 G_OBJECT_CLASS_TYPE (aclass),
972 gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
978 g_return_val_if_fail (GTK_IS_CELL_AREA_CLASS (aclass), NULL);
980 pspecs = g_param_spec_pool_list (cell_property_pool,
981 G_OBJECT_CLASS_TYPE (aclass),
990 gtk_cell_area_add_with_properties (GtkCellArea *area,
991 GtkCellRenderer *renderer,
992 const gchar *first_prop_name,
995 GtkCellAreaClass *class;
997 g_return_if_fail (GTK_IS_CELL_AREA (area));
998 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1000 class = GTK_CELL_AREA_GET_CLASS (area);
1006 class->add (area, renderer);
1008 va_start (var_args, first_prop_name);
1009 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1013 g_warning ("GtkCellAreaClass::add not implemented for `%s'",
1014 g_type_name (G_TYPE_FROM_INSTANCE (area)));
1018 gtk_cell_area_cell_set (GtkCellArea *area,
1019 GtkCellRenderer *renderer,
1020 const gchar *first_prop_name,
1025 g_return_if_fail (GTK_IS_CELL_AREA (area));
1026 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1028 va_start (var_args, first_prop_name);
1029 gtk_cell_area_cell_set_valist (area, renderer, first_prop_name, var_args);
1034 gtk_cell_area_cell_get (GtkCellArea *area,
1035 GtkCellRenderer *renderer,
1036 const gchar *first_prop_name,
1041 g_return_if_fail (GTK_IS_CELL_AREA (area));
1042 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1044 va_start (var_args, first_prop_name);
1045 gtk_cell_area_cell_get_valist (area, renderer, first_prop_name, var_args);
1050 area_get_cell_property (GtkCellArea *area,
1051 GtkCellRenderer *renderer,
1055 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1057 class->get_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), value, pspec);
1061 area_set_cell_property (GtkCellArea *area,
1062 GtkCellRenderer *renderer,
1064 const GValue *value)
1066 GValue tmp_value = { 0, };
1067 GtkCellAreaClass *class = g_type_class_peek (pspec->owner_type);
1069 /* provide a copy to work from, convert (if necessary) and validate */
1070 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1071 if (!g_value_transform (value, &tmp_value))
1072 g_warning ("unable to set cell property `%s' of type `%s' from value of type `%s'",
1074 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1075 G_VALUE_TYPE_NAME (value));
1076 else if (g_param_value_validate (pspec, &tmp_value) && !(pspec->flags & G_PARAM_LAX_VALIDATION))
1078 gchar *contents = g_strdup_value_contents (value);
1080 g_warning ("value \"%s\" of type `%s' is invalid for property `%s' of type `%s'",
1082 G_VALUE_TYPE_NAME (value),
1084 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
1089 class->set_cell_property (area, renderer, PARAM_SPEC_PARAM_ID (pspec), &tmp_value, pspec);
1091 g_value_unset (&tmp_value);
1095 gtk_cell_area_cell_set_valist (GtkCellArea *area,
1096 GtkCellRenderer *renderer,
1097 const gchar *first_property_name,
1102 g_return_if_fail (GTK_IS_CELL_AREA (area));
1103 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1105 name = first_property_name;
1108 GValue value = { 0, };
1109 gchar *error = NULL;
1111 g_param_spec_pool_lookup (cell_property_pool, name,
1112 G_OBJECT_TYPE (area), TRUE);
1115 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1116 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1119 if (!(pspec->flags & G_PARAM_WRITABLE))
1121 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1122 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1126 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1127 G_VALUE_COLLECT (&value, var_args, 0, &error);
1130 g_warning ("%s: %s", G_STRLOC, error);
1133 /* we purposely leak the value here, it might not be
1134 * in a sane state if an error condition occoured
1138 area_set_cell_property (area, renderer, pspec, &value);
1139 g_value_unset (&value);
1140 name = va_arg (var_args, gchar*);
1145 gtk_cell_area_cell_get_valist (GtkCellArea *area,
1146 GtkCellRenderer *renderer,
1147 const gchar *first_property_name,
1152 g_return_if_fail (GTK_IS_CELL_AREA (area));
1153 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1155 name = first_property_name;
1158 GValue value = { 0, };
1162 pspec = g_param_spec_pool_lookup (cell_property_pool, name,
1163 G_OBJECT_TYPE (area), TRUE);
1166 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1167 G_STRLOC, G_OBJECT_TYPE_NAME (area), name);
1170 if (!(pspec->flags & G_PARAM_READABLE))
1172 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1173 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1177 g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1178 area_get_cell_property (area, renderer, pspec, &value);
1179 G_VALUE_LCOPY (&value, var_args, 0, &error);
1182 g_warning ("%s: %s", G_STRLOC, error);
1184 g_value_unset (&value);
1187 g_value_unset (&value);
1188 name = va_arg (var_args, gchar*);
1193 gtk_cell_area_cell_set_property (GtkCellArea *area,
1194 GtkCellRenderer *renderer,
1195 const gchar *property_name,
1196 const GValue *value)
1200 g_return_if_fail (GTK_IS_CELL_AREA (area));
1201 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1202 g_return_if_fail (property_name != NULL);
1203 g_return_if_fail (G_IS_VALUE (value));
1205 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1206 G_OBJECT_TYPE (area), TRUE);
1208 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1209 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1210 else if (!(pspec->flags & G_PARAM_WRITABLE))
1211 g_warning ("%s: cell property `%s' of cell area class `%s' is not writable",
1212 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1215 area_set_cell_property (area, renderer, pspec, value);
1220 gtk_cell_area_cell_get_property (GtkCellArea *area,
1221 GtkCellRenderer *renderer,
1222 const gchar *property_name,
1227 g_return_if_fail (GTK_IS_CELL_AREA (area));
1228 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1229 g_return_if_fail (property_name != NULL);
1230 g_return_if_fail (G_IS_VALUE (value));
1232 pspec = g_param_spec_pool_lookup (cell_property_pool, property_name,
1233 G_OBJECT_TYPE (area), TRUE);
1235 g_warning ("%s: cell area class `%s' has no cell property named `%s'",
1236 G_STRLOC, G_OBJECT_TYPE_NAME (area), property_name);
1237 else if (!(pspec->flags & G_PARAM_READABLE))
1238 g_warning ("%s: cell property `%s' of cell area class `%s' is not readable",
1239 G_STRLOC, pspec->name, G_OBJECT_TYPE_NAME (area));
1242 GValue *prop_value, tmp_value = { 0, };
1244 /* auto-conversion of the callers value type
1246 if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
1248 g_value_reset (value);
1251 else if (!g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
1253 g_warning ("can't retrieve cell property `%s' of type `%s' as value of type `%s'",
1255 g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
1256 G_VALUE_TYPE_NAME (value));
1261 g_value_init (&tmp_value, G_PARAM_SPEC_VALUE_TYPE (pspec));
1262 prop_value = &tmp_value;
1265 area_get_cell_property (area, renderer, pspec, prop_value);
1267 if (prop_value != value)
1269 g_value_transform (prop_value, value);
1270 g_value_unset (&tmp_value);
1277 gtk_cell_area_get_cell_margin_left (GtkCellArea *area)
1279 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1281 return area->priv->cell_border.left;
1285 gtk_cell_area_set_cell_margin_left (GtkCellArea *area,
1288 GtkCellAreaPrivate *priv;
1290 g_return_if_fail (GTK_IS_CELL_AREA (area));
1294 if (priv->cell_border.left != margin)
1296 priv->cell_border.left = margin;
1298 g_object_notify (G_OBJECT (area), "margin-left");
1303 gtk_cell_area_get_cell_margin_right (GtkCellArea *area)
1305 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1307 return area->priv->cell_border.right;
1311 gtk_cell_area_set_cell_margin_right (GtkCellArea *area,
1314 GtkCellAreaPrivate *priv;
1316 g_return_if_fail (GTK_IS_CELL_AREA (area));
1320 if (priv->cell_border.right != margin)
1322 priv->cell_border.right = margin;
1324 g_object_notify (G_OBJECT (area), "margin-right");
1329 gtk_cell_area_get_cell_margin_top (GtkCellArea *area)
1331 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1333 return area->priv->cell_border.top;
1337 gtk_cell_area_set_cell_margin_top (GtkCellArea *area,
1340 GtkCellAreaPrivate *priv;
1342 g_return_if_fail (GTK_IS_CELL_AREA (area));
1346 if (priv->cell_border.top != margin)
1348 priv->cell_border.top = margin;
1350 g_object_notify (G_OBJECT (area), "margin-top");
1355 gtk_cell_area_get_cell_margin_bottom (GtkCellArea *area)
1357 g_return_val_if_fail (GTK_IS_CELL_AREA (area), 0);
1359 return area->priv->cell_border.bottom;
1363 gtk_cell_area_set_cell_margin_bottom (GtkCellArea *area,
1366 GtkCellAreaPrivate *priv;
1368 g_return_if_fail (GTK_IS_CELL_AREA (area));
1372 if (priv->cell_border.bottom != margin)
1374 priv->cell_border.bottom = margin;
1376 g_object_notify (G_OBJECT (area), "margin-bottom");
1380 /* For convenience in area implementations */
1382 gtk_cell_area_inner_cell_area (GtkCellArea *area,
1383 GdkRectangle *background_area,
1384 GdkRectangle *cell_area)
1386 GtkCellAreaPrivate *priv;
1388 g_return_if_fail (GTK_IS_CELL_AREA (area));
1389 g_return_if_fail (background_area != NULL);
1390 g_return_if_fail (cell_area != NULL);
1394 *cell_area = *background_area;
1396 cell_area->x += priv->cell_border.left;
1397 cell_area->width -= (priv->cell_border.left + priv->cell_border.right);
1398 cell_area->y += priv->cell_border.top;
1399 cell_area->height -= (priv->cell_border.top + priv->cell_border.bottom);
1403 gtk_cell_area_request_renderer (GtkCellArea *area,
1404 GtkCellRenderer *renderer,
1405 GtkOrientation orientation,
1411 GtkCellAreaPrivate *priv;
1413 g_return_if_fail (GTK_IS_CELL_AREA (area));
1414 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
1415 g_return_if_fail (GTK_IS_WIDGET (widget));
1416 g_return_if_fail (minimum_size != NULL);
1417 g_return_if_fail (natural_size != NULL);
1421 if (orientation == GTK_ORIENTATION_HORIZONTAL)
1424 gtk_cell_renderer_get_preferred_width (renderer, widget, minimum_size, natural_size);
1427 for_size = MAX (0, for_size - (priv->cell_border.top + priv->cell_border.bottom));
1429 gtk_cell_renderer_get_preferred_width_for_height (renderer, widget, for_size,
1430 minimum_size, natural_size);
1433 *minimum_size += (priv->cell_border.left + priv->cell_border.right);
1434 *natural_size += (priv->cell_border.left + priv->cell_border.right);
1436 else /* GTK_ORIENTATION_VERTICAL */
1439 gtk_cell_renderer_get_preferred_height (renderer, widget, minimum_size, natural_size);
1442 for_size = MAX (0, for_size - (priv->cell_border.left + priv->cell_border.right));
1444 gtk_cell_renderer_get_preferred_height_for_width (renderer, widget, for_size,
1445 minimum_size, natural_size);
1448 *minimum_size += (priv->cell_border.top + priv->cell_border.bottom);
1449 *natural_size += (priv->cell_border.top + priv->cell_border.bottom);