]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellview.c
cfa82d5de256ea682a430144322535c47e4a2ac5
[~andy/gtk] / gtk / gtkcellview.c
1 /* gtkellview.c
2  * Copyright (C) 2002, 2003  Kristian Rietveld <kris@gtk.org>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include <config.h>
21 #include "gtkcellview.h"
22 #include "gtkcelllayout.h"
23 #include "gtkintl.h"
24 #include "gtksignal.h"
25 #include "gtkcellrenderertext.h"
26 #include "gtkcellrendererpixbuf.h"
27 #include <gobject/gmarshal.h>
28
29 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
30 struct _GtkCellViewCellInfo
31 {
32   GtkCellRenderer *cell;
33
34   gint requested_width;
35   gint real_width;
36   guint expand : 1;
37   guint pack : 1;
38
39   GSList *attributes;
40
41   GtkCellLayoutDataFunc func;
42   gpointer func_data;
43   GDestroyNotify destroy;
44 };
45
46 struct _GtkCellViewPrivate
47 {
48   GtkTreeModel *model;
49   GtkTreeRowReference *displayed_row;
50   GList *cell_list;
51   gint spacing;
52
53   GdkColor background;
54   gboolean background_set;
55 };
56
57
58 static void        gtk_cell_view_class_init               (GtkCellViewClass *klass);
59 static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
60 static void        gtk_cell_view_get_property             (GObject           *object,
61                                                            guint             param_id,
62                                                            GValue           *value,
63                                                            GParamSpec       *pspec);
64 static void        gtk_cell_view_set_property             (GObject          *object,
65                                                            guint             param_id,
66                                                            const GValue     *value,
67                                                            GParamSpec       *pspec);
68 static void        gtk_cell_view_init                     (GtkCellView      *cellview);
69 static void        gtk_cell_view_finalize                 (GObject          *object);
70 static void        gtk_cell_view_style_set                (GtkWidget        *widget,
71                                                            GtkStyle         *previous_style);
72 static void        gtk_cell_view_size_request             (GtkWidget        *widget,
73                                                            GtkRequisition   *requisition);
74 static void        gtk_cell_view_size_allocate            (GtkWidget        *widget,
75                                                            GtkAllocation    *allocation);
76 static gboolean    gtk_cell_view_expose                   (GtkWidget        *widget,
77                                                            GdkEventExpose   *event);
78 static void        gtk_cell_view_set_valuesv              (GtkCellView      *cellview,
79                                                            GtkCellRenderer  *renderer,
80                                                            va_list           args);
81 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info   (GtkCellView      *cellview,
82                                                            GtkCellRenderer  *renderer);
83
84
85 static void        gtk_cell_view_cell_layout_pack_start        (GtkCellLayout         *layout,
86                                                                 GtkCellRenderer       *renderer,
87                                                                 gboolean               expand);
88 static void        gtk_cell_view_cell_layout_pack_end          (GtkCellLayout         *layout,
89                                                                 GtkCellRenderer       *renderer,
90                                                                 gboolean               expand);
91 static void        gtk_cell_view_cell_layout_add_attribute     (GtkCellLayout         *layout,
92                                                                 GtkCellRenderer       *renderer,
93                                                                 const gchar           *attribute,
94                                                                 gint                   column);
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,
101                                                                 gpointer               func_data,
102                                                                 GDestroyNotify         destroy);
103 static void       gtk_cell_view_cell_layout_reorder            (GtkCellLayout         *layout,
104                                                                 GtkCellRenderer       *cell,
105                                                                 gint                   position);
106
107
108 #define GTK_CELL_VIEW_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
109
110 enum
111 {
112   PROP_0,
113   PROP_BACKGROUND,
114   PROP_BACKGROUND_GDK,
115   PROP_BACKGROUND_SET
116 };
117
118 static GtkObjectClass *parent_class = NULL;
119
120
121 GType
122 gtk_cell_view_get_type (void)
123 {
124   static GType cell_view_type = 0;
125
126   if (!cell_view_type)
127     {
128       static const GTypeInfo cell_view_info =
129         {
130           sizeof (GtkCellViewClass),
131           NULL, /* base_init */
132           NULL, /* base_finalize */
133           (GClassInitFunc) gtk_cell_view_class_init,
134           NULL, /* class_finalize */
135           NULL, /* class_data */
136           sizeof (GtkCellView),
137           0,
138           (GInstanceInitFunc) gtk_cell_view_init
139         };
140
141       static const GInterfaceInfo cell_layout_info =
142        {
143          (GInterfaceInitFunc) gtk_cell_view_cell_layout_init,
144          NULL,
145          NULL
146        };
147
148       cell_view_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkCellView",
149                                                &cell_view_info, 0);
150
151       g_type_add_interface_static (cell_view_type, GTK_TYPE_CELL_LAYOUT,
152                                    &cell_layout_info);
153     }
154
155   return cell_view_type;
156 }
157
158 static void
159 gtk_cell_view_class_init (GtkCellViewClass *klass)
160 {
161   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
162   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
163
164   parent_class = g_type_class_peek_parent (klass);
165
166   gobject_class->get_property = gtk_cell_view_get_property;
167   gobject_class->set_property = gtk_cell_view_set_property;
168   gobject_class->finalize = gtk_cell_view_finalize;
169
170   widget_class->expose_event = gtk_cell_view_expose;
171   widget_class->size_allocate = gtk_cell_view_size_allocate;
172   widget_class->size_request = gtk_cell_view_size_request;
173   widget_class->style_set = gtk_cell_view_style_set;
174
175   /* properties */
176   g_object_class_install_property (gobject_class,
177                                    PROP_BACKGROUND,
178                                    g_param_spec_string ("background",
179                                                         P_("Background color name"),
180                                                         P_("Background color as a string"),
181                                                         NULL,
182                                                         G_PARAM_WRITABLE));
183   g_object_class_install_property (gobject_class,
184                                    PROP_BACKGROUND_GDK,
185                                    g_param_spec_boxed ("background_gdk",
186                                                       P_("Background color"),
187                                                       P_("Background color as a GdkColor"),
188                                                       GDK_TYPE_COLOR,
189                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
190
191 #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))
192
193   ADD_SET_PROP ("background_set", PROP_BACKGROUND_SET,
194                 P_("Background set"),
195                 P_("Whether this tag affects the background color"));
196
197   g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
198 }
199
200 static void
201 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
202 {
203   iface->pack_start = gtk_cell_view_cell_layout_pack_start;
204   iface->pack_end = gtk_cell_view_cell_layout_pack_end;
205   iface->clear = gtk_cell_view_cell_layout_clear;
206   iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
207   iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
208   iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
209   iface->reorder = gtk_cell_view_cell_layout_reorder;
210 }
211
212 static void
213 gtk_cell_view_get_property (GObject    *object,
214                             guint       param_id,
215                             GValue     *value,
216                             GParamSpec *pspec)
217 {
218   GtkCellView *view = GTK_CELL_VIEW (object);
219
220   switch (param_id)
221     {
222       case PROP_BACKGROUND_GDK:
223         {
224           GdkColor color;
225
226           color = view->priv->background;
227
228           g_value_set_boxed (value, &color);
229         }
230         break;
231       case PROP_BACKGROUND_SET:
232         g_value_set_boolean (value, view->priv->background_set);
233         break;
234       default:
235         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
236         break;
237     }
238 }
239
240 static void
241 gtk_cell_view_set_property (GObject      *object,
242                             guint         param_id,
243                             const GValue *value,
244                             GParamSpec   *pspec)
245 {
246   GtkCellView *view = GTK_CELL_VIEW (object);
247
248   switch (param_id)
249     {
250       case PROP_BACKGROUND:
251         {
252           GdkColor color;
253
254           if (!g_value_get_string (value))
255             gtk_cell_view_set_background_color (view, NULL);
256           else if (gdk_color_parse (g_value_get_string (value), &color))
257             gtk_cell_view_set_background_color (view, &color);
258           else
259             g_warning ("Don't know color `%s'", g_value_get_string (value));
260
261           g_object_notify (object, "background_gdk");
262         }
263         break;
264       case PROP_BACKGROUND_GDK:
265         gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
266         break;
267       case PROP_BACKGROUND_SET:
268         view->priv->background_set = g_value_get_boolean (value);
269         break;
270       default:
271         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
272         break;
273     }
274 }
275
276 static void
277 gtk_cell_view_init (GtkCellView *cellview)
278 {
279   GTK_WIDGET_SET_FLAGS (cellview, GTK_NO_WINDOW);
280
281   cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
282 }
283
284 static void
285 gtk_cell_view_style_set (GtkWidget *widget,
286                          GtkStyle  *previous_style)
287 {
288   if (previous_style && GTK_WIDGET_REALIZED (widget))
289     gdk_window_set_background (widget->window,
290                                &widget->style->base[GTK_WIDGET_STATE (widget)]);
291 }
292
293 static void
294 gtk_cell_view_finalize (GObject *object)
295 {
296   GtkCellView *cellview = GTK_CELL_VIEW (object);
297
298   gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview));
299
300   if (cellview->priv->model)
301      g_object_unref (cellview->priv->model);
302
303   if (cellview->priv->displayed_row)
304      gtk_tree_row_reference_free (cellview->priv->displayed_row);
305
306   (* G_OBJECT_CLASS (parent_class)->finalize) (object);
307 }
308
309 static void
310 gtk_cell_view_size_request (GtkWidget      *widget,
311                             GtkRequisition *requisition)
312 {
313   GList *i;
314   gboolean first_cell = TRUE;
315   GtkCellView *cellview;
316
317   cellview = GTK_CELL_VIEW (widget);
318
319   requisition->width = 0;
320   requisition->height = 0;
321
322   if (cellview->priv->displayed_row)
323     gtk_cell_view_set_cell_data (cellview);
324
325   for (i = cellview->priv->cell_list; i; i = i->next)
326     {
327       gint width, height;
328       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
329
330       if (!info->cell->visible)
331         continue;
332
333       if (!first_cell)
334         requisition->width += cellview->priv->spacing;
335
336       gtk_cell_renderer_get_size (info->cell, widget, NULL, NULL, NULL,
337                                   &width, &height);
338
339       info->requested_width = width;
340       requisition->width += width;
341       requisition->height = MAX (requisition->height, height);
342
343       first_cell = FALSE;
344     }
345 }
346
347 static void
348 gtk_cell_view_size_allocate (GtkWidget     *widget,
349                              GtkAllocation *allocation)
350 {
351   GList *i;
352   gint expand_cell_count = 0;
353   gint full_requested_width = 0;
354   gint extra_space;
355   GtkCellView *cellview;
356
357   widget->allocation = *allocation;
358
359   cellview = GTK_CELL_VIEW (widget);
360
361   /* checking how much extra space we have */
362   for (i = cellview->priv->cell_list; i; i = i->next)
363     {
364       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
365
366       if (!info->cell->visible)
367         continue;
368
369       if (info->expand)
370         expand_cell_count++;
371
372       full_requested_width += info->requested_width;
373     }
374
375   extra_space = widget->allocation.width - full_requested_width;
376   if (extra_space < 0)
377     extra_space = 0;
378   else if (extra_space > 0 && expand_cell_count > 0)
379     extra_space /= expand_cell_count;
380
381   /* iterate list for PACK_START cells */
382   for (i = cellview->priv->cell_list; i; i = i->next)
383     {
384       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
385
386       if (info->pack == GTK_PACK_END)
387         continue;
388
389       if (!info->cell->visible)
390         continue;
391
392       info->real_width = info->requested_width + (info->expand?extra_space:0);
393     }
394
395   /* iterate list for PACK_END cells */
396   for (i = cellview->priv->cell_list; i; i = i->next)
397     {
398       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
399
400       if (info->pack == GTK_PACK_START)
401         continue;
402
403       if (!info->cell->visible)
404         continue;
405
406       info->real_width = info->requested_width + (info->expand?extra_space:0);
407     }
408 }
409
410 static gboolean
411 gtk_cell_view_expose (GtkWidget      *widget,
412                       GdkEventExpose *event)
413 {
414   GList *i;
415   GtkCellView *cellview;
416   GdkRectangle area;
417   GtkCellRendererState state;
418   gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
419
420   cellview = GTK_CELL_VIEW (widget);
421
422   if (! GTK_WIDGET_DRAWABLE (widget))
423     return FALSE;
424
425   /* "blank" background */
426   if (cellview->priv->background_set)
427     {
428       GdkGC *gc;
429
430       gc = gdk_gc_new (GTK_WIDGET (cellview)->window);
431       gdk_gc_set_rgb_fg_color (gc, &cellview->priv->background);
432
433       gdk_draw_rectangle (GTK_WIDGET (cellview)->window,
434                           gc,
435                           TRUE,
436
437                           /*0, 0,*/
438                           widget->allocation.x,
439                           widget->allocation.y,
440
441                           widget->allocation.width,
442                           widget->allocation.height);
443
444       g_object_unref (G_OBJECT (gc));
445     }
446
447   /* set cell data (if available) */
448   if (cellview->priv->displayed_row)
449     gtk_cell_view_set_cell_data (cellview);
450   else if (cellview->priv->model)
451     return FALSE;
452
453   /* render cells */
454   area = widget->allocation;
455
456   /* we draw on our very own window, initialize x and y to zero */
457   area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); 
458   area.y = widget->allocation.y;
459
460   if (GTK_WIDGET_STATE (widget) == GTK_STATE_PRELIGHT)
461     state = GTK_CELL_RENDERER_PRELIT;
462   else
463     state = 0;
464       
465   /* PACK_START */
466   for (i = cellview->priv->cell_list; i; i = i->next)
467     {
468       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
469
470       if (info->pack == GTK_PACK_END)
471         continue;
472
473       if (!info->cell->visible)
474         continue;
475
476       area.width = info->real_width;
477       if (rtl)                                             
478          area.x -= area.width;
479
480       gtk_cell_renderer_render (info->cell,
481                                 event->window,
482                                 widget,
483                                 /* FIXME! */
484                                 &area, &area, &event->area, state);
485
486       if (!rtl)                                           
487          area.x += info->real_width;
488     }
489
490    area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);  
491
492   /* PACK_END */
493   for (i = cellview->priv->cell_list; i; i = i->next)
494     {
495       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
496
497       if (info->pack == GTK_PACK_START)
498         continue;
499
500       if (!info->cell->visible)
501         continue;
502
503       area.width = info->real_width;
504       if (!rtl)
505          area.x -= area.width;   
506
507       gtk_cell_renderer_render (info->cell,
508                                 widget->window,
509                                 widget,
510                                 /* FIXME ! */
511                                 &area, &area, &event->area, state);
512       if (rtl)
513          area.x += info->real_width;
514     }
515
516   return FALSE;
517 }
518
519 static GtkCellViewCellInfo *
520 gtk_cell_view_get_cell_info (GtkCellView     *cellview,
521                              GtkCellRenderer *renderer)
522 {
523   GList *i;
524
525   for (i = cellview->priv->cell_list; i; i = i->next)
526     {
527       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
528
529       if (info->cell == renderer)
530         return info;
531     }
532
533   return NULL;
534 }
535
536 void
537 gtk_cell_view_set_cell_data (GtkCellView *cellview)
538 {
539   GList *i;
540   GtkTreeIter iter;
541   GtkTreePath *path;
542
543   g_return_if_fail (cellview->priv->displayed_row != NULL);
544
545   path = gtk_tree_row_reference_get_path (cellview->priv->displayed_row);
546   gtk_tree_model_get_iter (cellview->priv->model, &iter, path);
547   gtk_tree_path_free (path);
548
549   for (i = cellview->priv->cell_list; i; i = i->next)
550     {
551       GSList *j;
552       GtkCellViewCellInfo *info = i->data;
553
554       g_object_freeze_notify (G_OBJECT (info->cell));
555
556       for (j = info->attributes; j && j->next; j = j->next->next)
557         {
558           gchar *property = j->data;
559           gint column = GPOINTER_TO_INT (j->next->data);
560           GValue value = {0, };
561
562           gtk_tree_model_get_value (cellview->priv->model, &iter,
563                                     column, &value);
564           g_object_set_property (G_OBJECT (info->cell),
565                                  property, &value);
566           g_value_unset (&value);
567         }
568
569       if (info->func)
570         (* info->func) (GTK_CELL_LAYOUT (cellview),
571                         info->cell,
572                         cellview->priv->model,
573                         &iter,
574                         info->func_data);
575
576       g_object_thaw_notify (G_OBJECT (info->cell));
577     }
578 }
579
580 /* GtkCellLayout implementation */
581 static void
582 gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
583                                       GtkCellRenderer *renderer,
584                                       gboolean         expand)
585 {
586   GtkCellViewCellInfo *info;
587   GtkCellView *cellview = GTK_CELL_VIEW (layout);
588
589   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
590   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
591   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
592
593   g_object_ref (G_OBJECT (renderer));
594   gtk_object_sink (GTK_OBJECT (renderer));
595
596   info = g_new0 (GtkCellViewCellInfo, 1);
597   info->cell = renderer;
598   info->expand = expand ? TRUE : FALSE;
599   info->pack = GTK_PACK_START;
600
601   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
602 }
603
604 static void
605 gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
606                                     GtkCellRenderer *renderer,
607                                     gboolean         expand)
608 {
609   GtkCellViewCellInfo *info;
610   GtkCellView *cellview = GTK_CELL_VIEW (layout);
611
612   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
613   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
614   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
615
616   g_object_ref (G_OBJECT (renderer));
617   gtk_object_sink (GTK_OBJECT (renderer));
618
619   info = g_new0 (GtkCellViewCellInfo, 1);
620   info->cell = renderer;
621   info->expand = expand ? TRUE : FALSE;
622   info->pack = GTK_PACK_END;
623
624   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
625 }
626
627 static void
628 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout   *layout,
629                                          GtkCellRenderer *renderer,
630                                          const gchar     *attribute,
631                                          gint             column)
632 {
633   GtkCellViewCellInfo *info;
634   GtkCellView *cellview = GTK_CELL_VIEW (layout);
635
636   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
637   info = gtk_cell_view_get_cell_info (cellview, renderer);
638   g_return_if_fail (info != NULL);
639
640   info->attributes = g_slist_prepend (info->attributes,
641                                       GINT_TO_POINTER (column));
642   info->attributes = g_slist_prepend (info->attributes,
643                                       g_strdup (attribute));
644 }
645
646 static void
647 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
648 {
649   GtkCellView *cellview = GTK_CELL_VIEW (layout);
650
651   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
652
653   while (cellview->priv->cell_list)
654     {
655       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data;
656
657       gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
658       g_object_unref (G_OBJECT (info->cell));
659       g_free (info);
660       cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, 
661                                                       cellview->priv->cell_list);
662     }
663 }
664
665 static void
666 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
667                                               GtkCellRenderer       *cell,
668                                               GtkCellLayoutDataFunc  func,
669                                               gpointer               func_data,
670                                               GDestroyNotify         destroy)
671 {
672   GtkCellView *cellview = GTK_CELL_VIEW (layout);
673   GtkCellViewCellInfo *info;
674
675   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
676
677   info = gtk_cell_view_get_cell_info (cellview, cell);
678   g_return_if_fail (info != NULL);
679
680   if (info->destroy)
681     {
682       GDestroyNotify d = info->destroy;
683
684       info->destroy = NULL;
685       d (info->func_data);
686     }
687
688   info->func = func;
689   info->func_data = func_data;
690   info->destroy = destroy;
691 }
692
693 static void
694 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
695                                             GtkCellRenderer *renderer)
696 {
697   GtkCellViewCellInfo *info;
698   GtkCellView *cellview = GTK_CELL_VIEW (layout);
699   GSList *list;
700
701   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
702   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
703
704   info = gtk_cell_view_get_cell_info (cellview, renderer);
705   g_return_if_fail (info != NULL);
706
707   list = info->attributes;
708   while (list && list->next)
709     {
710       g_free (list->data);
711       list = list->next->next;
712     }
713
714   g_slist_free (info->attributes);
715   info->attributes = NULL;
716 }
717
718 static void
719 gtk_cell_view_cell_layout_reorder (GtkCellLayout   *layout,
720                                    GtkCellRenderer *cell,
721                                    gint             position)
722 {
723   GList *link;
724   GtkCellViewCellInfo *info;
725   GtkCellView *cellview = GTK_CELL_VIEW (layout);
726
727   g_return_if_fail (GTK_IS_CELL_VIEW (cellview));
728   g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
729
730   info = gtk_cell_view_get_cell_info (cellview, cell);
731
732   g_return_if_fail (info != NULL);
733   g_return_if_fail (position >= 0);
734
735   link = g_list_find (cellview->priv->cell_list, info);
736
737   g_return_if_fail (link != NULL);
738
739   cellview->priv->cell_list = g_list_remove_link (cellview->priv->cell_list,
740                                                   link);
741   cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list,
742                                              info, position);
743
744   gtk_widget_queue_draw (GTK_WIDGET (cellview));
745 }
746
747 /* public API */
748 GtkWidget *
749 gtk_cell_view_new (void)
750 {
751   GtkCellView *cellview;
752
753   cellview = GTK_CELL_VIEW (g_object_new (gtk_cell_view_get_type (), NULL));
754
755   return GTK_WIDGET (cellview);
756 }
757
758 GtkWidget *
759 gtk_cell_view_new_with_text (const gchar *text)
760 {
761   GtkCellView *cellview;
762   GtkCellRenderer *renderer;
763   GValue value = {0, };
764
765   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
766
767   renderer = gtk_cell_renderer_text_new ();
768   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
769                                         renderer, TRUE);
770
771   g_value_init (&value, G_TYPE_STRING);
772   g_value_set_string (&value, text);
773   gtk_cell_view_set_values (cellview, renderer, "text", &value, NULL);
774   g_value_unset (&value);
775
776   return GTK_WIDGET (cellview);
777 }
778
779 GtkWidget *
780 gtk_cell_view_new_with_markup (const gchar *markup)
781 {
782   GtkCellView *cellview;
783   GtkCellRenderer *renderer;
784   GValue value = {0, };
785
786   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
787
788   renderer = gtk_cell_renderer_text_new ();
789   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
790                                         renderer, TRUE);
791
792   g_value_init (&value, G_TYPE_STRING);
793   g_value_set_string (&value, markup);
794   gtk_cell_view_set_values (cellview, renderer, "markup", &value, NULL);
795   g_value_unset (&value);
796
797   return GTK_WIDGET (cellview);
798 }
799
800 GtkWidget *
801 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
802 {
803   GtkCellView *cellview;
804   GtkCellRenderer *renderer;
805   GValue value = {0, };
806
807   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
808
809   renderer = gtk_cell_renderer_pixbuf_new ();
810   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
811                                         renderer, TRUE);
812
813   g_value_init (&value, GDK_TYPE_PIXBUF);
814   g_value_set_object (&value, pixbuf);
815   gtk_cell_view_set_values (cellview, renderer, "pixbuf", &value, NULL);
816   g_value_unset (&value);
817
818   return GTK_WIDGET (cellview);
819 }
820
821 void
822 gtk_cell_view_set_value (GtkCellView     *cell_view,
823                          GtkCellRenderer *renderer,
824                          gchar           *property,
825                          GValue          *value)
826 {
827   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
828   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
829
830   g_object_set_property (G_OBJECT (renderer), property, value);
831
832   /* force resize and redraw */
833   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
834   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
835 }
836
837 static void
838 gtk_cell_view_set_valuesv (GtkCellView     *cell_view,
839                            GtkCellRenderer *renderer,
840                            va_list          args)
841 {
842   gchar *attribute;
843   GValue *value;
844
845   attribute = va_arg (args, gchar *);
846
847   while (attribute)
848     {
849       value = va_arg (args, GValue *);
850       gtk_cell_view_set_value (cell_view, renderer, attribute, value);
851       attribute = va_arg (args, gchar *);
852     }
853 }
854
855 void
856 gtk_cell_view_set_values (GtkCellView     *cell_view,
857                           GtkCellRenderer *renderer,
858                           ...)
859 {
860   va_list args;
861
862   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
863   g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
864   g_return_if_fail (gtk_cell_view_get_cell_info (cell_view, renderer));
865
866   va_start (args, renderer);
867   gtk_cell_view_set_valuesv (cell_view, renderer, args);
868   va_end (args);
869 }
870
871 void
872 gtk_cell_view_set_model (GtkCellView  *cell_view,
873                          GtkTreeModel *model)
874 {
875   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
876   g_return_if_fail (GTK_IS_TREE_MODEL (model));
877
878   if (cell_view->priv->model)
879     {
880       if (cell_view->priv->displayed_row)
881         gtk_tree_row_reference_free (cell_view->priv->displayed_row);
882       cell_view->priv->displayed_row = NULL;
883
884       g_object_unref (G_OBJECT (cell_view->priv->model));
885       cell_view->priv->model = NULL;
886     }
887
888   cell_view->priv->model = model;
889
890   if (cell_view->priv->model)
891     g_object_ref (G_OBJECT (cell_view->priv->model));
892 }
893
894 /**
895  * gtk_cell_view_set_displayed_row:
896  * @cell_view: a #GtkCellView
897  * @path: a #GtkTreePath or %NULL to unset.
898  * 
899  * Sets the row of the model that is currently displayed
900  * by the #GtkCellView. If the path is unset, then the
901  * contents of the cellview "stick" at their last value;
902  * this is not normally a desired result, but may be
903  * a needed intermediate state if say, the model for
904  * the #GtkCellView becomes temporarily empty.
905  **/
906 void
907 gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
908                                  GtkTreePath *path)
909 {
910   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
911   g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
912
913   if (cell_view->priv->displayed_row)
914     gtk_tree_row_reference_free (cell_view->priv->displayed_row);
915
916   if (path)
917     {
918       cell_view->priv->displayed_row =
919         gtk_tree_row_reference_new (cell_view->priv->model, path);
920     }
921   else
922     cell_view->priv->displayed_row = NULL;
923
924   /* force resize and redraw */
925   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
926   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
927 }
928
929 GtkTreePath *
930 gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
931 {
932   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
933
934   if (!cell_view->priv->displayed_row)
935     return NULL;
936
937   return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
938 }
939
940 gboolean
941 gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
942                                GtkTreePath    *path,
943                                GtkRequisition *requisition)
944 {
945   GtkTreeRowReference *tmp;
946
947   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), FALSE);
948   g_return_val_if_fail (path != NULL, FALSE);
949   g_return_val_if_fail (requisition != NULL, FALSE);
950
951   tmp = cell_view->priv->displayed_row;
952   cell_view->priv->displayed_row =
953     gtk_tree_row_reference_new (cell_view->priv->model, path);
954
955   gtk_cell_view_size_request (GTK_WIDGET (cell_view), requisition);
956
957   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
958   cell_view->priv->displayed_row = tmp;
959
960   return TRUE;
961 }
962
963 void
964 gtk_cell_view_set_background_color (GtkCellView    *view,
965                                     const GdkColor *color)
966 {
967   g_return_if_fail (GTK_IS_CELL_VIEW (view));
968
969   if (color)
970     {
971       if (!view->priv->background_set)
972         {
973           view->priv->background_set = TRUE;
974           g_object_notify (G_OBJECT (view), "background_set");
975         }
976
977       view->priv->background = *color;
978     }
979   else
980     {
981       if (view->priv->background_set)
982         {
983           view->priv->background_set = FALSE;
984           g_object_notify (G_OBJECT (view), "background_set");
985         }
986     }
987 }
988
989 GList *
990 gtk_cell_view_get_cell_renderers (GtkCellView *cell_view)
991 {
992   GList *retval = NULL, *list;
993
994   g_return_val_if_fail (cell_view != NULL, NULL);
995
996   for (list = cell_view->priv->cell_list; list; list = list->next)
997     {
998       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
999
1000       retval = g_list_prepend (retval, info->cell);
1001     }
1002
1003   return g_list_reverse (retval);
1004 }