2 * Copyright (C) 2002, 2003 Kristian Rietveld <kris@gtk.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gtkcellview.h"
21 #include "gtkcelllayout.h"
23 #include "gtksignal.h"
24 #include "gtkcellrenderertext.h"
25 #include "gtkcellrendererpixbuf.h"
26 #include <gobject/gmarshal.h>
28 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
29 struct _GtkCellViewCellInfo
31 GtkCellRenderer *cell;
40 GtkCellLayoutDataFunc func;
42 GDestroyNotify destroy;
45 struct _GtkCellViewPrivate
48 GtkTreeRowReference *displayed_row;
53 gboolean background_set;
57 static void gtk_cell_view_class_init (GtkCellViewClass *klass);
58 static void gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface);
59 static void gtk_cell_view_get_property (GObject *object,
63 static void gtk_cell_view_set_property (GObject *object,
67 static void gtk_cell_view_init (GtkCellView *cellview);
68 static void gtk_cell_view_finalize (GObject *object);
69 static void gtk_cell_view_style_set (GtkWidget *widget,
70 GtkStyle *previous_style);
71 static void gtk_cell_view_size_request (GtkWidget *widget,
72 GtkRequisition *requisition);
73 static void gtk_cell_view_size_allocate (GtkWidget *widget,
74 GtkAllocation *allocation);
75 static gboolean gtk_cell_view_expose (GtkWidget *widget,
76 GdkEventExpose *event);
77 static void gtk_cell_view_set_valuesv (GtkCellView *cellview,
78 GtkCellRenderer *renderer,
80 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info (GtkCellView *cellview,
81 GtkCellRenderer *renderer);
82 static void gtk_cell_view_set_cell_data (GtkCellView *cellview);
85 static void gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout,
86 GtkCellRenderer *renderer,
88 static void gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout,
89 GtkCellRenderer *renderer,
91 static void gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout,
92 GtkCellRenderer *renderer,
93 const gchar *attribute,
95 static void gtk_cell_view_cell_layout_clear (GtkCellLayout *layout);
96 static void gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout,
97 GtkCellRenderer *renderer);
98 static void gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout,
99 GtkCellRenderer *cell,
100 GtkCellLayoutDataFunc func,
102 GDestroyNotify destroy);
113 static GtkObjectClass *parent_class = NULL;
117 gtk_cell_view_get_type (void)
119 static GType cell_view_type = 0;
123 static const GTypeInfo cell_view_info =
125 sizeof (GtkCellViewClass),
126 NULL, /* base_init */
127 NULL, /* base_finalize */
128 (GClassInitFunc) gtk_cell_view_class_init,
129 NULL, /* class_finalize */
130 NULL, /* class_data */
131 sizeof (GtkCellView),
133 (GInstanceInitFunc) gtk_cell_view_init
136 static const GInterfaceInfo cell_layout_info =
138 (GInterfaceInitFunc) gtk_cell_view_cell_layout_init,
143 cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView",
146 g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT,
150 return cell_view_type;
154 gtk_cell_view_class_init (GtkCellViewClass *klass)
156 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
157 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
159 parent_class = g_type_class_peek_parent (klass);
161 gobject_class->get_property = gtk_cell_view_get_property;
162 gobject_class->set_property = gtk_cell_view_set_property;
163 gobject_class->finalize = gtk_cell_view_finalize;
165 widget_class->expose_event = gtk_cell_view_expose;
166 widget_class->size_allocate = gtk_cell_view_size_allocate;
167 widget_class->size_request = gtk_cell_view_size_request;
168 widget_class->style_set = gtk_cell_view_style_set;
171 g_object_class_install_property (gobject_class,
173 g_param_spec_string ("background",
174 _("Background color name"),
175 _("Background color as a string"),
178 g_object_class_install_property (gobject_class,
180 g_param_spec_boxed ("background_gdk",
181 _("Background color"),
182 _("Background color as a GdkColor"),
184 G_PARAM_READABLE | G_PARAM_WRITABLE));
186 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
188 ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
190 _("Whether this tag affects the background color"));
192 g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
196 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
198 iface->pack_start = gtk_cell_view_cell_layout_pack_start;
199 iface->pack_end = gtk_cell_view_cell_layout_pack_end;
200 iface->clear = gtk_cell_view_cell_layout_clear;
201 iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
202 iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
203 iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
207 gtk_cell_view_get_property (GObject *object,
212 GtkCellView *view = GTK_CELL_VIEW (object);
216 case PROP_BACKGROUND_GDK:
220 color = view->priv->background;
222 g_value_set_boxed (value, &color);
225 case PROP_BACKGROUND_SET:
226 g_value_set_boolean (value, view->priv->background_set);
229 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
235 gtk_cell_view_set_property (GObject *object,
240 GtkCellView *view = GTK_CELL_VIEW (object);
244 case PROP_BACKGROUND:
248 if (!g_value_get_string (value))
249 gtk_cell_view_set_background_color (view, NULL);
250 else if (gdk_color_parse (g_value_get_string (value), &color))
251 gtk_cell_view_set_background_color (view, &color);
253 g_warning ("Don't know color `%s'", g_value_get_string (value));
255 g_object_notify (object, "background_gdk");
258 case PROP_BACKGROUND_GDK:
259 gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
261 case PROP_BACKGROUND_SET:
262 view->priv->background_set = g_value_get_boolean (value);
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
271 gtk_cell_view_init (GtkCellView *cellview)
273 GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
275 cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
279 gtk_cell_view_style_set (GtkWidget *widget,
280 GtkStyle *previous_style)
282 if (previous_style && GTK_WIDGET_REALIZED (widget))
283 gdk_window_set_background (widget->window,
284 &widget->style->base[GTK_WIDGET_STATE (widget)]);
288 gtk_cell_view_finalize (GObject *object)
290 GtkCellView *cellview = GTK_CELL_VIEW (object);
292 gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (object));
294 if (G_OBJECT_CLASS (parent_class)->finalize)
295 (* G_OBJECT_CLASS (parent_class)->finalize) (object);
299 gtk_cell_view_size_request (GtkWidget *widget,
300 GtkRequisition *requisition)
303 gboolean first_cell = TRUE;
304 GtkCellView *cellview;
306 cellview = GTK_CELL_VIEW (widget);
308 requisition->width = 0;
309 requisition->height = 0;
311 if (cellview->priv->displayed_row)
312 gtk_cell_view_set_cell_data (cellview);
314 for (i = cellview->priv->cell_list; i; i = i->next)
317 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
319 if (!info->cell->visible)
323 requisition->width += cellview->priv->spacing;
325 gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
328 info->requested_width = width;
329 requisition->width += width;
330 requisition->height = MAX (requisition->height, height);
337 gtk_cell_view_size_allocate (GtkWidget *widget,
338 GtkAllocation *allocation)
341 gint expand_cell_count = 0;
342 gint full_requested_width = 0;
344 GtkCellView *cellview;
346 widget->allocation = *allocation;
348 cellview = GTK_CELL_VIEW (widget);
350 /* checking how much extra space we have */
351 for (i = cellview->priv->cell_list; i; i = i->next)
353 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
355 if (!info->cell->visible)
361 full_requested_width += info->requested_width;
364 extra_space = widget->allocation.width - full_requested_width;
367 else if (extra_space > 0 && expand_cell_count > 0)
368 extra_space /= expand_cell_count;
370 /* iterate list for PACK_START cells */
371 for (i = cellview->priv->cell_list; i; i = i->next)
373 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
375 if (info->pack == GTK_PACK_END)
378 if (!info->cell->visible)
381 info->real_width = info->requested_width + (info->expand?extra_space:0);
384 /* iterate list for PACK_END cells */
385 for (i = cellview->priv->cell_list; i; i = i->next)
387 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
389 if (info->pack == GTK_PACK_START)
392 if (!info->cell->visible)
395 info->real_width = info->requested_width + (info->expand?extra_space:0);
400 gtk_cell_view_expose (GtkWidget *widget,
401 GdkEventExpose *event)
404 GtkCellView *cellview;
407 cellview = GTK_CELL_VIEW (widget);
409 if (! GTK_WIDGET_DRAWABLE (widget))
412 /* "blank" background */
413 if (cellview->priv->background_set)
417 gc = gdk_gc_new (GTK_WIDGET (cellview)->window);
418 gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background);
420 gdk_draw_rectangle (GTK_WIDGET (cellview)->window,
425 widget->allocation.x,
426 widget->allocation.y,
428 widget->allocation.width,
429 widget->allocation.height);
431 g_object_unref (G_OBJECT (gc));
434 /* set cell data (if applicable) */
435 if (cellview->priv->displayed_row)
436 gtk_cell_view_set_cell_data (cellview);
439 area = widget->allocation;
441 /* we draw on our very own window, initialize x and y to zero */
442 area.x = widget->allocation.x;
443 area.y = widget->allocation.y;
446 for (i = cellview->priv->cell_list; i; i = i->next)
448 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
450 if (info->pack == GTK_PACK_END)
453 if (!info->cell->visible)
456 area.width = info->real_width;
458 gtk_cell_renderer_render (info->cell,
462 &area, &area, &event->area, 0);
464 area.x += info->real_width;
468 for (i = cellview->priv->cell_list; i; i = i->next)
470 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
472 if (info->pack == GTK_PACK_START)
475 if (!info->cell->visible)
478 area.width = info->real_width;
480 gtk_cell_renderer_render (info->cell,
484 &area, &area, &event->area, 0);
485 area.x += info->real_width;
491 static GtkCellViewCellInfo *
492 gtk_cell_view_get_cell_info (GtkCellView *cellview,
493 GtkCellRenderer *renderer)
497 for (i = cellview->priv->cell_list; i; i = i->next)
499 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
501 if (info->cell == renderer)
509 gtk_cell_view_set_cell_data (GtkCellView *cellview)
515 g_return_if_fail (cellview->priv->displayed_row != NULL);
517 path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
518 gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
519 gtk_tree_path_free (path);
521 for (i = cellview->priv->cell_list; i; i = i->next)
524 GtkCellViewCellInfo *info = i->data;
528 (* info->func) (GTK_CELL_LAYOUT (cellview),
530 cellview->priv->model,
536 for (j = info->attributes; j && j->next; j = j->next->next)
538 gchar *property = j->data;
539 gint column = GPOINTER_TO_INT (j->next->data);
540 GValue value = {0, };
542 gtk_tree_model_get_value (cellview->priv->model, &iter,
544 g_object_set_property (G_OBJECT (info->cell),
546 g_value_unset (&value);
551 /* GtkCellLayout implementation */
553 gtk_cell_view_cell_layout_pack_start (GtkCellLayout *layout,
554 GtkCellRenderer *renderer,
557 GtkCellViewCellInfo *info;
558 GtkCellView *cellview = GTK_CELL_VIEW (layout);
560 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
561 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
562 g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
564 g_object_ref (G_OBJECT (renderer));
565 gtk_object_sink (GTK_OBJECT (renderer));
567 info = g_new0 (GtkCellViewCellInfo, 1);
568 info->cell = renderer;
569 info->expand = expand ? TRUE : FALSE;
570 info->pack = GTK_PACK_START;
572 cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
576 gtk_cell_view_cell_layout_pack_end (GtkCellLayout *layout,
577 GtkCellRenderer *renderer,
580 GtkCellViewCellInfo *info;
581 GtkCellView *cellview = GTK_CELL_VIEW (layout);
583 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
584 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
585 g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
587 g_object_ref (G_OBJECT (renderer));
588 gtk_object_sink (GTK_OBJECT (renderer));
590 info = g_new0 (GtkCellViewCellInfo, 1);
591 info->cell = renderer;
592 info->expand = expand ? TRUE : FALSE;
593 info->pack = GTK_PACK_END;
595 cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
599 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout *layout,
600 GtkCellRenderer *renderer,
601 const gchar *attribute,
604 GtkCellViewCellInfo *info;
605 GtkCellView *cellview = GTK_CELL_VIEW (layout);
607 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
608 info = gtk_cell_view_get_cell_info (cellview, renderer);
609 g_return_if_fail (info != NULL);
611 info->attributes = g_slist_prepend (info->attributes,
612 GINT_TO_POINTER (column));
613 info->attributes = g_slist_prepend (info->attributes,
614 g_strdup (attribute));
618 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
621 GtkCellView *cellview = GTK_CELL_VIEW (layout);
623 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
625 for (i = cellview->priv->cell_list; i; i = i->next)
627 GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
629 gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
630 g_object_unref (G_OBJECT (info->cell));
634 g_list_free (cellview->priv->cell_list);
635 cellview->priv->cell_list = NULL;
639 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout *layout,
640 GtkCellRenderer *cell,
641 GtkCellLayoutDataFunc func,
643 GDestroyNotify destroy)
645 GtkCellView *cellview = GTK_CELL_VIEW (layout);
646 GtkCellViewCellInfo *info;
648 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
650 info = gtk_cell_view_get_cell_info (cellview, cell);
651 g_return_if_fail (info != NULL);
655 GDestroyNotify d = info->destroy;
657 info->destroy = NULL;
662 info->func_data = func_data;
663 info->destroy = destroy;
667 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout *layout,
668 GtkCellRenderer *renderer)
670 GtkCellViewCellInfo *info;
671 GtkCellView *cellview = GTK_CELL_VIEW (layout);
674 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
675 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
677 info = gtk_cell_view_get_cell_info (cellview, renderer);
678 g_return_if_fail (info != NULL);
680 list = info->attributes;
682 while (list && list->next)
685 list = list->next->next;
689 info->attributes = NULL;
695 gtk_cell_view_new (void)
697 GtkCellView *cellview;
699 cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL));
701 return GTK_WIDGET (cellview);
705 gtk_cell_view_new_with_text (const gchar *text)
707 GtkCellView *cellview;
708 GtkCellRenderer *renderer;
709 GValue value = {0, };
711 cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
713 renderer = gtk_cell_renderer_text_new ();
714 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
717 g_value_init (&value, G_TYPE_STRING);
718 g_value_set_string (&value, text);
719 gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL);
720 g_value_unset (&value);
722 return GTK_WIDGET (cellview);
726 gtk_cell_view_new_with_markup (const gchar *markup)
728 GtkCellView *cellview;
729 GtkCellRenderer *renderer;
730 GValue value = {0, };
732 cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
734 renderer = gtk_cell_renderer_text_new ();
735 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
738 g_value_init (&value, G_TYPE_STRING);
739 g_value_set_string (&value, markup);
740 gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL);
741 g_value_unset (&value);
743 return GTK_WIDGET (cellview);
747 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
749 GtkCellView *cellview;
750 GtkCellRenderer *renderer;
751 GValue value = {0, };
753 cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
755 renderer = gtk_cell_renderer_pixbuf_new ();
756 gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
759 g_value_init (&value, GDK_TYPE_PIXBUF);
760 g_value_set_object (&value, pixbuf);
761 gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL);
762 g_value_unset (&value);
764 return GTK_WIDGET (cellview);
768 gtk_cell_view_set_value (GtkCellView *cellview,
769 GtkCellRenderer *renderer,
773 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
774 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
776 g_object_set_property (G_OBJECT (renderer), property, value);
779 gtk_widget_queue_draw (GTK_WIDGET (cellview));
783 gtk_cell_view_set_valuesv (GtkCellView *cellview,
784 GtkCellRenderer *renderer,
790 attribute = va_arg (args, gchar *);
794 value = va_arg (args, GValue *);
795 gtk_cell_view_set_value (cellview, renderer, attribute, value);
796 attribute = va_arg (args, gchar *);
801 gtk_cell_view_set_values (GtkCellView *cellview,
802 GtkCellRenderer *renderer,
807 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
808 g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
809 g_return_if_fail (gtk_cell_view_get_cell_info (cellview, renderer));
811 va_start (args, renderer);
812 gtk_cell_view_set_valuesv (cellview, renderer, args);
817 gtk_cell_view_set_model (GtkCellView *cellview,
820 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
821 g_return_if_fail (GTK_IS_TREE_MODEL (model));
823 if (cellview->priv->model)
825 if (cellview->priv->displayed_row)
826 gtk_tree_row_reference_free (cellview->priv->displayed_row);
827 cellview->priv->displayed_row = NULL;
829 g_object_unref (G_OBJECT (cellview->priv->model));
830 cellview->priv->model = NULL;
833 cellview->priv->model = model;
835 if (cellview->priv->model)
836 g_object_ref (G_OBJECT (cellview->priv->model));
840 gtk_cell_view_set_displayed_row (GtkCellView *cellview,
843 g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
844 g_return_if_fail (GTK_IS_TREE_MODEL (cellview->priv->model));
845 g_return_if_fail (path != NULL);
847 if (cellview->priv->displayed_row)
848 gtk_tree_row_reference_free (cellview->priv->displayed_row);
850 cellview->priv->displayed_row =
851 gtk_tree_row_reference_new (cellview->priv->model, path);
854 gtk_widget_queue_draw (GTK_WIDGET (cellview));
858 gtk_cell_view_get_displayed_row (GtkCellView *cellview)
860 g_return_val_if_fail (GTK_IS_CELL_VIEW (cellview), NULL);
862 if (!cellview->priv->displayed_row)
865 return gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
869 gtk_cell_view_set_background_color (GtkCellView *view,
872 g_return_if_fail (GTK_IS_CELL_VIEW (view));
876 if (!view->priv->background_set)
878 view->priv->background_set = TRUE;
879 g_object_notify (G_OBJECT (view), "background_set");
882 view->priv->background = *color;
886 if (view->priv->background_set)
888 view->priv->background_set = FALSE;
889 g_object_notify (G_OBJECT (view), "background_set");