]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellview.c
GtkCellView refactoring for extended layout
[~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 <string.h>
22 #include "gtkcellview.h"
23 #include "gtkcelllayout.h"
24 #include "gtkintl.h"
25 #include "gtkcellrenderertext.h"
26 #include "gtkcellrendererpixbuf.h"
27 #include "gtkextendedlayout.h"
28 #include "gtkextendedcell.h"
29 #include "gtkprivate.h"
30 #include <gobject/gmarshal.h>
31 #include "gtkbuildable.h"
32 #include "gtkalias.h"
33
34 typedef struct _GtkCellViewCellInfo GtkCellViewCellInfo;
35 struct _GtkCellViewCellInfo
36 {
37   GtkCellRenderer *cell;
38
39   gint requested_width;
40   gint natural_width;
41   gint real_width;
42   guint expand : 1;
43   guint pack : 1;
44
45   GSList *attributes;
46
47   GtkCellLayoutDataFunc func;
48   gpointer func_data;
49   GDestroyNotify destroy;
50 };
51
52 struct _GtkCellViewPrivate
53 {
54   GtkTreeModel *model;
55   GtkTreeRowReference *displayed_row;
56   GList *cell_list;
57   gint spacing;
58
59   GdkColor background;
60   gboolean background_set;
61 };
62
63
64 static void        gtk_cell_view_cell_layout_init         (GtkCellLayoutIface *iface);
65 static void        gtk_cell_view_get_property             (GObject           *object,
66                                                            guint             param_id,
67                                                            GValue           *value,
68                                                            GParamSpec       *pspec);
69 static void        gtk_cell_view_set_property             (GObject          *object,
70                                                            guint             param_id,
71                                                            const GValue     *value,
72                                                            GParamSpec       *pspec);
73 static void        gtk_cell_view_finalize                 (GObject          *object);
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_value                (GtkCellView     *cell_view,
79                                                            GtkCellRenderer *renderer,
80                                                            gchar           *property,
81                                                            GValue          *value);
82 static GtkCellViewCellInfo *gtk_cell_view_get_cell_info   (GtkCellView      *cellview,
83                                                            GtkCellRenderer  *renderer);
84 static void        gtk_cell_view_set_cell_data            (GtkCellView      *cell_view);
85
86
87 static void        gtk_cell_view_cell_layout_pack_start        (GtkCellLayout         *layout,
88                                                                 GtkCellRenderer       *renderer,
89                                                                 gboolean               expand);
90 static void        gtk_cell_view_cell_layout_pack_end          (GtkCellLayout         *layout,
91                                                                 GtkCellRenderer       *renderer,
92                                                                 gboolean               expand);
93 static void        gtk_cell_view_cell_layout_add_attribute     (GtkCellLayout         *layout,
94                                                                 GtkCellRenderer       *renderer,
95                                                                 const gchar           *attribute,
96                                                                 gint                   column);
97 static void       gtk_cell_view_cell_layout_clear              (GtkCellLayout         *layout);
98 static void       gtk_cell_view_cell_layout_clear_attributes   (GtkCellLayout         *layout,
99                                                                 GtkCellRenderer       *renderer);
100 static void       gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
101                                                                 GtkCellRenderer       *cell,
102                                                                 GtkCellLayoutDataFunc  func,
103                                                                 gpointer               func_data,
104                                                                 GDestroyNotify         destroy);
105 static void       gtk_cell_view_cell_layout_reorder            (GtkCellLayout         *layout,
106                                                                 GtkCellRenderer       *cell,
107                                                                 gint                   position);
108 static GList *    gtk_cell_view_cell_layout_get_cells          (GtkCellLayout         *layout);
109
110 /* buildable */
111 static void       gtk_cell_view_buildable_init                 (GtkBuildableIface     *iface);
112 static gboolean   gtk_cell_view_buildable_custom_tag_start     (GtkBuildable          *buildable,
113                                                                 GtkBuilder            *builder,
114                                                                 GObject               *child,
115                                                                 const gchar           *tagname,
116                                                                 GMarkupParser         *parser,
117                                                                 gpointer              *data);
118 static void       gtk_cell_view_buildable_custom_tag_end       (GtkBuildable          *buildable,
119                                                                 GtkBuilder            *builder,
120                                                                 GObject               *child,
121                                                                 const gchar           *tagname,
122                                                                 gpointer              *data);
123
124 static void       gtk_cell_view_extended_layout_init             (GtkExtendedLayoutIface *iface);
125 static void       gtk_cell_view_extended_layout_get_desired_size (GtkExtendedLayout *layout,
126                                                                   GtkRequisition    *minimal_size,
127                                                                   GtkRequisition    *natural_size);
128
129 static GtkBuildableIface *parent_buildable_iface;
130
131 #define GTK_CELL_VIEW_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_CELL_VIEW, GtkCellViewPrivate))
132
133 enum
134 {
135   PROP_0,
136   PROP_BACKGROUND,
137   PROP_BACKGROUND_GDK,
138   PROP_BACKGROUND_SET,
139   PROP_MODEL
140 };
141
142 G_DEFINE_TYPE_WITH_CODE (GtkCellView, gtk_cell_view, GTK_TYPE_WIDGET, 
143                          G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
144                                                 gtk_cell_view_cell_layout_init)
145                          G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
146                                                 gtk_cell_view_buildable_init)
147                          G_IMPLEMENT_INTERFACE (GTK_TYPE_EXTENDED_LAYOUT,
148                                                 gtk_cell_view_extended_layout_init))
149
150
151 static void
152 gtk_cell_view_class_init (GtkCellViewClass *klass)
153 {
154   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
155   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
156
157   gobject_class->get_property = gtk_cell_view_get_property;
158   gobject_class->set_property = gtk_cell_view_set_property;
159   gobject_class->finalize = gtk_cell_view_finalize;
160
161   widget_class->expose_event = gtk_cell_view_expose;
162   widget_class->size_allocate = gtk_cell_view_size_allocate;
163
164   /* properties */
165   g_object_class_install_property (gobject_class,
166                                    PROP_BACKGROUND,
167                                    g_param_spec_string ("background",
168                                                         P_("Background color name"),
169                                                         P_("Background color as a string"),
170                                                         NULL,
171                                                         GTK_PARAM_WRITABLE));
172   g_object_class_install_property (gobject_class,
173                                    PROP_BACKGROUND_GDK,
174                                    g_param_spec_boxed ("background-gdk",
175                                                       P_("Background color"),
176                                                       P_("Background color as a GdkColor"),
177                                                       GDK_TYPE_COLOR,
178                                                       GTK_PARAM_READWRITE));
179
180   /**
181    * GtkCellView:model
182    *
183    * The model for cell view
184    *
185    * since 2.10
186    */
187   g_object_class_install_property (gobject_class,
188                                    PROP_MODEL,
189                                    g_param_spec_object  ("model",
190                                                          P_("CellView model"),
191                                                          P_("The model for cell view"),
192                                                          GTK_TYPE_TREE_MODEL,
193                                                          GTK_PARAM_READWRITE));
194   
195 #define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE))
196
197   ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET,
198                 P_("Background set"),
199                 P_("Whether this tag affects the background color"));
200
201   g_type_class_add_private (gobject_class, sizeof (GtkCellViewPrivate));
202 }
203
204 static void
205 gtk_cell_view_buildable_init (GtkBuildableIface *iface)
206 {
207   parent_buildable_iface = g_type_interface_peek_parent (iface);
208   iface->add_child = _gtk_cell_layout_buildable_add_child;
209   iface->custom_tag_start = gtk_cell_view_buildable_custom_tag_start;
210   iface->custom_tag_end = gtk_cell_view_buildable_custom_tag_end;
211 }
212
213 static void
214 gtk_cell_view_cell_layout_init (GtkCellLayoutIface *iface)
215 {
216   iface->pack_start = gtk_cell_view_cell_layout_pack_start;
217   iface->pack_end = gtk_cell_view_cell_layout_pack_end;
218   iface->clear = gtk_cell_view_cell_layout_clear;
219   iface->add_attribute = gtk_cell_view_cell_layout_add_attribute;
220   iface->set_cell_data_func = gtk_cell_view_cell_layout_set_cell_data_func;
221   iface->clear_attributes = gtk_cell_view_cell_layout_clear_attributes;
222   iface->reorder = gtk_cell_view_cell_layout_reorder;
223   iface->get_cells = gtk_cell_view_cell_layout_get_cells;
224 }
225
226 static void
227 gtk_cell_view_get_property (GObject    *object,
228                             guint       param_id,
229                             GValue     *value,
230                             GParamSpec *pspec)
231 {
232   GtkCellView *view = GTK_CELL_VIEW (object);
233
234   switch (param_id)
235     {
236       case PROP_BACKGROUND_GDK:
237         {
238           GdkColor color;
239
240           color = view->priv->background;
241
242           g_value_set_boxed (value, &color);
243         }
244         break;
245       case PROP_BACKGROUND_SET:
246         g_value_set_boolean (value, view->priv->background_set);
247         break;
248       case PROP_MODEL:
249         g_value_set_object (value, view->priv->model);
250         break;
251       default:
252         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
253         break;
254     }
255 }
256
257 static void
258 gtk_cell_view_set_property (GObject      *object,
259                             guint         param_id,
260                             const GValue *value,
261                             GParamSpec   *pspec)
262 {
263   GtkCellView *view = GTK_CELL_VIEW (object);
264
265   switch (param_id)
266     {
267       case PROP_BACKGROUND:
268         {
269           GdkColor color;
270
271           if (!g_value_get_string (value))
272             gtk_cell_view_set_background_color (view, NULL);
273           else if (gdk_color_parse (g_value_get_string (value), &color))
274             gtk_cell_view_set_background_color (view, &color);
275           else
276             g_warning ("Don't know color `%s'", g_value_get_string (value));
277
278           g_object_notify (object, "background-gdk");
279         }
280         break;
281       case PROP_BACKGROUND_GDK:
282         gtk_cell_view_set_background_color (view, g_value_get_boxed (value));
283         break;
284       case PROP_BACKGROUND_SET:
285         view->priv->background_set = g_value_get_boolean (value);
286         break;
287       case PROP_MODEL:
288         gtk_cell_view_set_model (view, g_value_get_object (value));
289         break;
290     default:
291         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
292         break;
293     }
294 }
295
296 static void
297 gtk_cell_view_init (GtkCellView *cellview)
298 {
299   gtk_widget_set_has_window (GTK_WIDGET (cellview), FALSE);
300
301   cellview->priv = GTK_CELL_VIEW_GET_PRIVATE (cellview);
302 }
303
304 static void
305 gtk_cell_view_finalize (GObject *object)
306 {
307   GtkCellView *cellview = GTK_CELL_VIEW (object);
308
309   gtk_cell_view_cell_layout_clear (GTK_CELL_LAYOUT (cellview));
310
311   if (cellview->priv->model)
312      g_object_unref (cellview->priv->model);
313
314   if (cellview->priv->displayed_row)
315      gtk_tree_row_reference_free (cellview->priv->displayed_row);
316
317   G_OBJECT_CLASS (gtk_cell_view_parent_class)->finalize (object);
318 }
319
320 static void
321 gtk_cell_view_size_allocate (GtkWidget     *widget,
322                              GtkAllocation *allocation)
323 {
324   GtkCellView *cellview;
325   GList *i;
326   gint nexpand_cells = 0;
327   gint requested_width = 0;
328   gint natural_width = 0;
329   gint available, natural, extra;
330
331   widget->allocation = *allocation;
332
333   cellview = GTK_CELL_VIEW (widget);
334
335   /* checking how much extra space we have */
336   for (i = cellview->priv->cell_list; i; i = i->next)
337     {
338       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
339
340       if (!info->cell->visible)
341         continue;
342
343       if (info->expand)
344         nexpand_cells++;
345
346       requested_width += info->requested_width;
347       natural_width += info->natural_width - info->requested_width;
348     }
349
350   available = MAX (0, widget->allocation.width - requested_width);
351   natural = MIN (available, natural_width);
352   available -= natural;
353
354   if (nexpand_cells > 0)
355     extra = available / nexpand_cells;
356   else
357     extra = 0;
358
359   for (i = cellview->priv->cell_list; i; i = i->next)
360     {
361       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
362
363       if (!info->cell->visible)
364         continue;
365
366       info->real_width = info->requested_width;
367
368       if (natural_width > 0)
369           info->real_width += natural * (info->natural_width - info->requested_width) / natural_width;
370
371       if (info->expand)
372         {
373           if (nexpand_cells == 1)
374             info->real_width += available;
375           else
376             info->real_width += extra;
377
378          nexpand_cells -= 1;
379          available -= extra;
380        }
381     }
382 }
383
384 static gboolean
385 gtk_cell_view_expose (GtkWidget      *widget,
386                       GdkEventExpose *event)
387 {
388   GList *i;
389   GtkCellView *cellview;
390   GdkRectangle area;
391   GtkCellRendererState state;
392   gboolean rtl = (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL);
393
394   cellview = GTK_CELL_VIEW (widget);
395
396   if (!gtk_widget_is_drawable (widget))
397     return FALSE;
398
399   /* "blank" background */
400   if (cellview->priv->background_set)
401     {
402       cairo_t *cr = gdk_cairo_create (GTK_WIDGET (cellview)->window);
403
404       gdk_cairo_rectangle (cr, &widget->allocation);
405       cairo_set_source_rgb (cr,
406                             cellview->priv->background.red / 65535.,
407                             cellview->priv->background.green / 65535.,
408                             cellview->priv->background.blue / 65535.);
409       cairo_fill (cr);
410
411       cairo_destroy (cr);
412     }
413
414   /* set cell data (if available) */
415   if (cellview->priv->displayed_row)
416     gtk_cell_view_set_cell_data (cellview);
417   else if (cellview->priv->model)
418     return FALSE;
419
420   /* render cells */
421   area = widget->allocation;
422
423   /* we draw on our very own window, initialize x and y to zero */
424   area.x = widget->allocation.x + (rtl ? widget->allocation.width : 0); 
425   area.y = widget->allocation.y;
426
427   if (gtk_widget_get_state (widget) == GTK_STATE_PRELIGHT)
428     state = GTK_CELL_RENDERER_PRELIT;
429   else if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
430     state = GTK_CELL_RENDERER_INSENSITIVE;
431   else
432     state = 0;
433       
434   /* PACK_START */
435   for (i = cellview->priv->cell_list; i; i = i->next)
436     {
437       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
438
439       if (info->pack == GTK_PACK_END)
440         continue;
441
442       if (!info->cell->visible)
443         continue;
444
445       area.width = info->real_width;
446       if (rtl)                                             
447          area.x -= area.width;
448
449       gtk_cell_renderer_render (info->cell,
450                                 event->window,
451                                 widget,
452                                 /* FIXME! */
453                                 &area, &area, &event->area, state);
454
455       if (!rtl)                                           
456          area.x += info->real_width;
457     }
458
459    area.x = rtl ? widget->allocation.x : (widget->allocation.x + widget->allocation.width);  
460
461   /* PACK_END */
462   for (i = cellview->priv->cell_list; i; i = i->next)
463     {
464       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
465
466       if (info->pack == GTK_PACK_START)
467         continue;
468
469       if (!info->cell->visible)
470         continue;
471
472       area.width = info->real_width;
473       if (!rtl)
474          area.x -= area.width;   
475
476       gtk_cell_renderer_render (info->cell,
477                                 widget->window,
478                                 widget,
479                                 /* FIXME ! */
480                                 &area, &area, &event->area, state);
481       if (rtl)
482          area.x += info->real_width;
483     }
484
485   return FALSE;
486 }
487
488 static GtkCellViewCellInfo *
489 gtk_cell_view_get_cell_info (GtkCellView     *cellview,
490                              GtkCellRenderer *renderer)
491 {
492   GList *i;
493
494   for (i = cellview->priv->cell_list; i; i = i->next)
495     {
496       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
497
498       if (info->cell == renderer)
499         return info;
500     }
501
502   return NULL;
503 }
504
505 static void
506 gtk_cell_view_set_cell_data (GtkCellView *cell_view)
507 {
508   GList *i;
509   GtkTreeIter iter;
510   GtkTreePath *path;
511
512   g_return_if_fail (cell_view->priv->displayed_row != NULL);
513
514   path = gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
515   if (!path)
516     return;
517
518   gtk_tree_model_get_iter (cell_view->priv->model, &iter, path);
519   gtk_tree_path_free (path);
520
521   for (i = cell_view->priv->cell_list; i; i = i->next)
522     {
523       GSList *j;
524       GtkCellViewCellInfo *info = i->data;
525
526       g_object_freeze_notify (G_OBJECT (info->cell));
527
528       for (j = info->attributes; j && j->next; j = j->next->next)
529         {
530           gchar *property = j->data;
531           gint column = GPOINTER_TO_INT (j->next->data);
532           GValue value = {0, };
533
534           gtk_tree_model_get_value (cell_view->priv->model, &iter,
535                                     column, &value);
536           g_object_set_property (G_OBJECT (info->cell),
537                                  property, &value);
538           g_value_unset (&value);
539         }
540
541       if (info->func)
542         (* info->func) (GTK_CELL_LAYOUT (cell_view),
543                         info->cell,
544                         cell_view->priv->model,
545                         &iter,
546                         info->func_data);
547
548       g_object_thaw_notify (G_OBJECT (info->cell));
549     }
550 }
551
552 /* GtkCellLayout implementation */
553 static void
554 gtk_cell_view_cell_layout_pack_start (GtkCellLayout   *layout,
555                                       GtkCellRenderer *renderer,
556                                       gboolean         expand)
557 {
558   GtkCellViewCellInfo *info;
559   GtkCellView *cellview = GTK_CELL_VIEW (layout);
560
561   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
562
563   g_object_ref_sink (renderer);
564
565   info = g_slice_new0 (GtkCellViewCellInfo);
566   info->cell = renderer;
567   info->expand = expand ? TRUE : FALSE;
568   info->pack = GTK_PACK_START;
569
570   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
571
572   gtk_widget_queue_resize (cellview);
573 }
574
575 static void
576 gtk_cell_view_cell_layout_pack_end (GtkCellLayout   *layout,
577                                     GtkCellRenderer *renderer,
578                                     gboolean         expand)
579 {
580   GtkCellViewCellInfo *info;
581   GtkCellView *cellview = GTK_CELL_VIEW (layout);
582
583   g_return_if_fail (!gtk_cell_view_get_cell_info (cellview, renderer));
584
585   g_object_ref_sink (renderer);
586
587   info = g_slice_new0 (GtkCellViewCellInfo);
588   info->cell = renderer;
589   info->expand = expand ? TRUE : FALSE;
590   info->pack = GTK_PACK_END;
591
592   cellview->priv->cell_list = g_list_append (cellview->priv->cell_list, info);
593
594   gtk_widget_queue_resize (cellview);
595 }
596
597 static void
598 gtk_cell_view_cell_layout_add_attribute (GtkCellLayout   *layout,
599                                          GtkCellRenderer *renderer,
600                                          const gchar     *attribute,
601                                          gint             column)
602 {
603   GtkCellViewCellInfo *info;
604   GtkCellView *cellview = GTK_CELL_VIEW (layout);
605
606   info = gtk_cell_view_get_cell_info (cellview, renderer);
607   g_return_if_fail (info != NULL);
608
609   info->attributes = g_slist_prepend (info->attributes,
610                                       GINT_TO_POINTER (column));
611   info->attributes = g_slist_prepend (info->attributes,
612                                       g_strdup (attribute));
613 }
614
615 static void
616 gtk_cell_view_cell_layout_clear (GtkCellLayout *layout)
617 {
618   GtkCellView *cellview = GTK_CELL_VIEW (layout);
619
620   while (cellview->priv->cell_list)
621     {
622       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)cellview->priv->cell_list->data;
623
624       gtk_cell_view_cell_layout_clear_attributes (layout, info->cell);
625       g_object_unref (info->cell);
626       g_slice_free (GtkCellViewCellInfo, info);
627       cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list, 
628                                                       cellview->priv->cell_list);
629     }
630 }
631
632 static void
633 gtk_cell_view_cell_layout_set_cell_data_func (GtkCellLayout         *layout,
634                                               GtkCellRenderer       *cell,
635                                               GtkCellLayoutDataFunc  func,
636                                               gpointer               func_data,
637                                               GDestroyNotify         destroy)
638 {
639   GtkCellView *cellview = GTK_CELL_VIEW (layout);
640   GtkCellViewCellInfo *info;
641
642   info = gtk_cell_view_get_cell_info (cellview, cell);
643   g_return_if_fail (info != NULL);
644
645   if (info->destroy)
646     {
647       GDestroyNotify d = info->destroy;
648
649       info->destroy = NULL;
650       d (info->func_data);
651     }
652
653   info->func = func;
654   info->func_data = func_data;
655   info->destroy = destroy;
656 }
657
658 static void
659 gtk_cell_view_cell_layout_clear_attributes (GtkCellLayout   *layout,
660                                             GtkCellRenderer *renderer)
661 {
662   GtkCellView *cellview = GTK_CELL_VIEW (layout);
663   GtkCellViewCellInfo *info;
664   GSList *list;
665
666   info = gtk_cell_view_get_cell_info (cellview, renderer);
667   if (info != NULL)
668     {
669       list = info->attributes;
670       while (list && list->next)
671         {
672           g_free (list->data);
673           list = list->next->next;
674         }
675       
676       g_slist_free (info->attributes);
677       info->attributes = NULL;
678     }
679 }
680
681 static void
682 gtk_cell_view_cell_layout_reorder (GtkCellLayout   *layout,
683                                    GtkCellRenderer *cell,
684                                    gint             position)
685 {
686   GtkCellView *cellview = GTK_CELL_VIEW (layout);
687   GtkCellViewCellInfo *info;
688   GList *link;
689
690   info = gtk_cell_view_get_cell_info (cellview, cell);
691
692   g_return_if_fail (info != NULL);
693   g_return_if_fail (position >= 0);
694
695   link = g_list_find (cellview->priv->cell_list, info);
696
697   g_return_if_fail (link != NULL);
698
699   cellview->priv->cell_list = g_list_delete_link (cellview->priv->cell_list,
700                                                   link);
701   cellview->priv->cell_list = g_list_insert (cellview->priv->cell_list,
702                                              info, position);
703
704   gtk_widget_queue_draw (GTK_WIDGET (cellview));
705 }
706
707 /**
708  * gtk_cell_view_new:
709  *
710  * Creates a new #GtkCellView widget.
711  *
712  * Return value: A newly created #GtkCellView widget.
713  *
714  * Since: 2.6
715  */
716 GtkWidget *
717 gtk_cell_view_new (void)
718 {
719   GtkCellView *cellview;
720
721   cellview = g_object_new (gtk_cell_view_get_type (), NULL);
722
723   return GTK_WIDGET (cellview);
724 }
725
726 /**
727  * gtk_cell_view_new_with_text:
728  * @text: the text to display in the cell view
729  *
730  * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
731  * to it, and makes its show @text.
732  *
733  * Return value: A newly created #GtkCellView widget.
734  *
735  * Since: 2.6
736  */
737 GtkWidget *
738 gtk_cell_view_new_with_text (const gchar *text)
739 {
740   GtkCellView *cellview;
741   GtkCellRenderer *renderer;
742   GValue value = {0, };
743
744   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
745
746   renderer = gtk_cell_renderer_text_new ();
747   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
748                                         renderer, TRUE);
749
750   g_value_init (&value, G_TYPE_STRING);
751   g_value_set_string (&value, text);
752   gtk_cell_view_set_value (cellview, renderer, "text", &value);
753   g_value_unset (&value);
754
755   return GTK_WIDGET (cellview);
756 }
757
758 /**
759  * gtk_cell_view_new_with_markup:
760  * @markup: the text to display in the cell view
761  *
762  * Creates a new #GtkCellView widget, adds a #GtkCellRendererText 
763  * to it, and makes it show @markup. The text can be
764  * marked up with the <link linkend="PangoMarkupFormat">Pango text 
765  * markup language</link>.
766  *
767  * Return value: A newly created #GtkCellView widget.
768  *
769  * Since: 2.6
770  */
771 GtkWidget *
772 gtk_cell_view_new_with_markup (const gchar *markup)
773 {
774   GtkCellView *cellview;
775   GtkCellRenderer *renderer;
776   GValue value = {0, };
777
778   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
779
780   renderer = gtk_cell_renderer_text_new ();
781   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
782                                         renderer, TRUE);
783
784   g_value_init (&value, G_TYPE_STRING);
785   g_value_set_string (&value, markup);
786   gtk_cell_view_set_value (cellview, renderer, "markup", &value);
787   g_value_unset (&value);
788
789   return GTK_WIDGET (cellview);
790 }
791
792 /**
793  * gtk_cell_view_new_with_pixbuf:
794  * @pixbuf: the image to display in the cell view
795  *
796  * Creates a new #GtkCellView widget, adds a #GtkCellRendererPixbuf 
797  * to it, and makes its show @pixbuf. 
798  *
799  * Return value: A newly created #GtkCellView widget.
800  *
801  * Since: 2.6
802  */
803 GtkWidget *
804 gtk_cell_view_new_with_pixbuf (GdkPixbuf *pixbuf)
805 {
806   GtkCellView *cellview;
807   GtkCellRenderer *renderer;
808   GValue value = {0, };
809
810   cellview = GTK_CELL_VIEW (gtk_cell_view_new ());
811
812   renderer = gtk_cell_renderer_pixbuf_new ();
813   gtk_cell_view_cell_layout_pack_start (GTK_CELL_LAYOUT (cellview),
814                                         renderer, TRUE);
815
816   g_value_init (&value, GDK_TYPE_PIXBUF);
817   g_value_set_object (&value, pixbuf);
818   gtk_cell_view_set_value (cellview, renderer, "pixbuf", &value);
819   g_value_unset (&value);
820
821   return GTK_WIDGET (cellview);
822 }
823
824 /**
825  * gtk_cell_view_set_value:
826  * @cell_view: a #GtkCellView widget
827  * @renderer: one of the renderers of @cell_view
828  * @property: the name of the property of @renderer to set
829  * @value: the new value to set the property to
830  * 
831  * Sets a property of a cell renderer of @cell_view, and
832  * makes sure the display of @cell_view is updated.
833  *
834  * Since: 2.6
835  */
836 static void
837 gtk_cell_view_set_value (GtkCellView     *cell_view,
838                          GtkCellRenderer *renderer,
839                          gchar           *property,
840                          GValue          *value)
841 {
842   g_object_set_property (G_OBJECT (renderer), property, value);
843
844   /* force resize and redraw */
845   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
846   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
847 }
848
849 /**
850  * gtk_cell_view_set_model:
851  * @cell_view: a #GtkCellView
852  * @model: (allow-none): a #GtkTreeModel
853  *
854  * Sets the model for @cell_view.  If @cell_view already has a model
855  * set, it will remove it before setting the new model.  If @model is
856  * %NULL, then it will unset the old model.
857  *
858  * Since: 2.6
859  */
860 void
861 gtk_cell_view_set_model (GtkCellView  *cell_view,
862                          GtkTreeModel *model)
863 {
864   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
865   g_return_if_fail (model == NULL || GTK_IS_TREE_MODEL (model));
866
867   if (cell_view->priv->model)
868     {
869       if (cell_view->priv->displayed_row)
870         gtk_tree_row_reference_free (cell_view->priv->displayed_row);
871       cell_view->priv->displayed_row = NULL;
872
873       g_object_unref (cell_view->priv->model);
874       cell_view->priv->model = NULL;
875     }
876
877   cell_view->priv->model = model;
878
879   if (cell_view->priv->model)
880     g_object_ref (cell_view->priv->model);
881 }
882
883 /**
884  * gtk_cell_view_get_model:
885  * @cell_view: a #GtkCellView
886  *
887  * Returns the model for @cell_view. If no model is used %NULL is
888  * returned.
889  *
890  * Returns: a #GtkTreeModel used or %NULL
891  *
892  * Since: 2.16
893  **/
894 GtkTreeModel *
895 gtk_cell_view_get_model (GtkCellView *cell_view)
896 {
897   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
898
899   return cell_view->priv->model;
900 }
901
902 /**
903  * gtk_cell_view_set_displayed_row:
904  * @cell_view: a #GtkCellView
905  * @path: (allow-none): a #GtkTreePath or %NULL to unset.
906  *
907  * Sets the row of the model that is currently displayed
908  * by the #GtkCellView. If the path is unset, then the
909  * contents of the cellview "stick" at their last value;
910  * this is not normally a desired result, but may be
911  * a needed intermediate state if say, the model for
912  * the #GtkCellView becomes temporarily empty.
913  *
914  * Since: 2.6
915  **/
916 void
917 gtk_cell_view_set_displayed_row (GtkCellView *cell_view,
918                                  GtkTreePath *path)
919 {
920   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
921   g_return_if_fail (GTK_IS_TREE_MODEL (cell_view->priv->model));
922
923   if (cell_view->priv->displayed_row)
924     gtk_tree_row_reference_free (cell_view->priv->displayed_row);
925
926   if (path)
927     {
928       cell_view->priv->displayed_row =
929         gtk_tree_row_reference_new (cell_view->priv->model, path);
930     }
931   else
932     cell_view->priv->displayed_row = NULL;
933
934   /* force resize and redraw */
935   gtk_widget_queue_resize (GTK_WIDGET (cell_view));
936   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
937 }
938
939 /**
940  * gtk_cell_view_get_displayed_row:
941  * @cell_view: a #GtkCellView
942  *
943  * Returns a #GtkTreePath referring to the currently 
944  * displayed row. If no row is currently displayed, 
945  * %NULL is returned.
946  *
947  * Returns: the currently displayed row or %NULL
948  *
949  * Since: 2.6
950  */
951 GtkTreePath *
952 gtk_cell_view_get_displayed_row (GtkCellView *cell_view)
953 {
954   g_return_val_if_fail (GTK_IS_CELL_VIEW (cell_view), NULL);
955
956   if (!cell_view->priv->displayed_row)
957     return NULL;
958
959   return gtk_tree_row_reference_get_path (cell_view->priv->displayed_row);
960 }
961
962 /**
963  * gtk_cell_view_get_size_of_row:
964  * @cell_view: a #GtkCellView
965  * @path: a #GtkTreePath 
966  * @requisition: return location for the size 
967  *
968  * Sets @requisition to the size needed by @cell_view to display 
969  * the model row pointed to by @path.
970  * 
971  * Return value: %TRUE
972  *
973  * Since: 2.6
974  * 
975  * Deprecated: 3.0: Use gtk_cell_view_get_desired_size_of_row() instead.
976  */
977 gboolean
978 gtk_cell_view_get_size_of_row (GtkCellView    *cell_view,
979                                GtkTreePath    *path,
980                                GtkRequisition *requisition)
981 {
982   GtkRequisition req;
983
984   gtk_cell_view_get_desired_size_of_row (cell_view, path, requisition, &req);
985
986   return TRUE;
987 }
988
989
990 /**
991  * gtk_cell_view_get_desired_size_of_row:
992  * @cell_view: a #GtkCellView
993  * @path: a #GtkTreePath 
994  * @minimum_size: return location for the minimum requested size 
995  * @natural_size: return location for the desired natural size 
996  *
997  * Sets @minimum_size and @natural_size to the size desired by @cell_view 
998  * to display the model row pointed to by @path.
999  * 
1000  * Since: 3.0
1001  */
1002 void
1003 gtk_cell_view_get_desired_size_of_row (GtkCellView     *cell_view,
1004                                        GtkTreePath     *path,
1005                                        GtkRequisition  *minimum_size,
1006                                        GtkRequisition  *natural_size)
1007 {
1008   GtkTreeRowReference *tmp;
1009   GtkRequisition req, nat_req;
1010
1011   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1012   g_return_if_fail (path != NULL);
1013   g_return_if_fail (minimum_size != NULL || natural_size != NULL);
1014
1015   tmp = cell_view->priv->displayed_row;
1016   cell_view->priv->displayed_row =
1017     gtk_tree_row_reference_new (cell_view->priv->model, path);
1018
1019   gtk_cell_view_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (cell_view), 
1020                                                   minimum_size ? minimum_size : &req,
1021                                                   natural_size ? natural_size : &nat_req);
1022
1023   gtk_tree_row_reference_free (cell_view->priv->displayed_row);
1024   cell_view->priv->displayed_row = tmp;
1025
1026   /* Restore active size */
1027   gtk_cell_view_extended_layout_get_desired_size (GTK_EXTENDED_LAYOUT (cell_view), 
1028                                                   &req, &nat_req);
1029 }
1030
1031 /**
1032  * gtk_cell_view_set_background_color:
1033  * @cell_view: a #GtkCellView
1034  * @color: the new background color
1035  *
1036  * Sets the background color of @view.
1037  *
1038  * Since: 2.6
1039  */
1040 void
1041 gtk_cell_view_set_background_color (GtkCellView    *cell_view,
1042                                     const GdkColor *color)
1043 {
1044   g_return_if_fail (GTK_IS_CELL_VIEW (cell_view));
1045
1046   if (color)
1047     {
1048       if (!cell_view->priv->background_set)
1049         {
1050           cell_view->priv->background_set = TRUE;
1051           g_object_notify (G_OBJECT (cell_view), "background-set");
1052         }
1053
1054       cell_view->priv->background = *color;
1055     }
1056   else
1057     {
1058       if (cell_view->priv->background_set)
1059         {
1060           cell_view->priv->background_set = FALSE;
1061           g_object_notify (G_OBJECT (cell_view), "background-set");
1062         }
1063     }
1064
1065   gtk_widget_queue_draw (GTK_WIDGET (cell_view));
1066 }
1067
1068 static GList *
1069 gtk_cell_view_cell_layout_get_cells (GtkCellLayout *layout)
1070 {
1071   GtkCellView *cell_view = GTK_CELL_VIEW (layout);
1072   GList *retval = NULL, *list;
1073
1074   g_return_val_if_fail (cell_view != NULL, NULL);
1075
1076   gtk_cell_view_set_cell_data (cell_view);
1077
1078   for (list = cell_view->priv->cell_list; list; list = list->next)
1079     {
1080       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)list->data;
1081
1082       retval = g_list_prepend (retval, info->cell);
1083     }
1084
1085   return g_list_reverse (retval);
1086 }
1087
1088 /**
1089  * gtk_cell_view_get_cell_renderers:
1090  * @cell_view: a #GtkCellView
1091  *
1092  * Returns the cell renderers which have been added to @cell_view.
1093  *
1094  * Return value: a list of cell renderers. The list, but not the
1095  *   renderers has been newly allocated and should be freed with
1096  *   g_list_free() when no longer needed.
1097  *
1098  * Since: 2.6
1099  *
1100  * Deprecated: 2.18: use gtk_cell_layout_get_cells() instead.
1101  **/
1102 GList *
1103 gtk_cell_view_get_cell_renderers (GtkCellView *cell_view)
1104 {
1105   return gtk_cell_view_cell_layout_get_cells (GTK_CELL_LAYOUT (cell_view));
1106 }
1107
1108 static gboolean
1109 gtk_cell_view_buildable_custom_tag_start (GtkBuildable  *buildable,
1110                                           GtkBuilder    *builder,
1111                                           GObject       *child,
1112                                           const gchar   *tagname,
1113                                           GMarkupParser *parser,
1114                                           gpointer      *data)
1115 {
1116   if (parent_buildable_iface->custom_tag_start &&
1117       parent_buildable_iface->custom_tag_start (buildable, builder, child,
1118                                                 tagname, parser, data))
1119     return TRUE;
1120
1121   return _gtk_cell_layout_buildable_custom_tag_start (buildable, builder, child,
1122                                                       tagname, parser, data);
1123 }
1124
1125 static void
1126 gtk_cell_view_buildable_custom_tag_end (GtkBuildable *buildable,
1127                                         GtkBuilder   *builder,
1128                                         GObject      *child,
1129                                         const gchar  *tagname,
1130                                         gpointer     *data)
1131 {
1132   if (strcmp (tagname, "attributes") == 0)
1133     _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname,
1134                                                data);
1135   else if (parent_buildable_iface->custom_tag_end)
1136     parent_buildable_iface->custom_tag_end (buildable, builder, child, tagname,
1137                                             data);
1138 }
1139
1140 static void
1141 gtk_cell_view_extended_layout_get_desired_size (GtkExtendedLayout *layout,
1142                                                 GtkRequisition    *minimal_size,
1143                                                 GtkRequisition    *natural_size)
1144 {
1145   GList *i;
1146   GtkRequisition cell_min, cell_nat;
1147   gboolean first_cell = TRUE;
1148   GtkCellView *cellview = GTK_CELL_VIEW (layout);
1149
1150   minimal_size->width  = 0;
1151   minimal_size->height = 0;
1152   natural_size->width  = 0;
1153   natural_size->height = 0;
1154
1155   if (cellview->priv->displayed_row)
1156     gtk_cell_view_set_cell_data (cellview);
1157
1158   for (i = cellview->priv->cell_list; i; i = i->next)
1159     {
1160       GtkCellViewCellInfo *info = (GtkCellViewCellInfo *)i->data;
1161
1162       if (info->cell->visible)
1163         {
1164           
1165           if (!first_cell)
1166             {
1167               minimal_size->width += cellview->priv->spacing;
1168               natural_size->width += cellview->priv->spacing;
1169             }
1170
1171           gtk_extended_cell_get_desired_size (GTK_EXTENDED_CELL (info->cell),
1172                                               GTK_WIDGET (cellview), &cell_min, &cell_nat);
1173
1174
1175           info->requested_width = cell_min.width;
1176           info->natural_width   = cell_nat.width;
1177
1178           minimal_size->width += info->requested_width;
1179           natural_size->width += info->natural_width;
1180
1181           minimal_size->height = MAX (minimal_size->height, cell_min.height);
1182           natural_size->height = MAX (natural_size->height, cell_nat.height);
1183
1184           first_cell = FALSE;
1185         }
1186     }
1187 }
1188
1189 static void
1190 gtk_cell_view_extended_layout_init (GtkExtendedLayoutIface *iface)
1191 {
1192   iface->get_desired_size = gtk_cell_view_extended_layout_get_desired_size;
1193 }
1194
1195
1196 #define __GTK_CELL_VIEW_C__
1197 #include "gtkaliasdef.c"