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