]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellareacontext.c
Added apis to GtkCellArea for GtkIconView purposes.
[~andy/gtk] / gtk / gtkcellareacontext.c
1 /* gtkcellareacontext.c
2  *
3  * Copyright (C) 2010 Openismus GmbH
4  *
5  * Authors:
6  *      Tristan Van Berkom <tristanvb@openismus.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gtkcellareacontext
26  * @Short_Description: An object for a #GtkCellArea to store geometrical information for a series of rows.
27  * @Title: GtkCellAreaContext
28  *
29  * The #GtkCellAreaContext object is created by a given #GtkCellArea implementation via it's 
30  * #GtkCellAreaClass.create_context() virtual method and is used to store cell sizes and alignments
31  * for a series of #GtkTreeModel rows that are requested and rendered in the same context.
32  *
33  * #GtkCellLayout widgets can create any number of contexts in which to request and render
34  * groups of data rows. However its important that the same context which was used to 
35  * request sizes for a given #GtkTreeModel row also be used for the same row when calling
36  * other #GtkCellArea apis such as gtk_cell_area_render() and gtk_cell_area_event().
37  */
38 #include "config.h"
39 #include "gtkintl.h"
40 #include "gtkmarshalers.h"
41 #include "gtkcellareacontext.h"
42 #include "gtkprivate.h"
43
44 /* GObjectClass */
45 static void      gtk_cell_area_context_dispose         (GObject            *object);
46 static void      gtk_cell_area_context_get_property    (GObject            *object,
47                                                         guint               prop_id,
48                                                         GValue             *value,
49                                                         GParamSpec         *pspec);
50 static void      gtk_cell_area_context_set_property    (GObject            *object,
51                                                         guint               prop_id,
52                                                         const GValue       *value,
53                                                         GParamSpec         *pspec);
54
55 /* GtkCellAreaContextClass */
56 static void      gtk_cell_area_context_real_reset      (GtkCellAreaContext *context);
57 static void      gtk_cell_area_context_real_allocate   (GtkCellAreaContext *context,
58                                                         gint                width,
59                                                         gint                height);
60
61 struct _GtkCellAreaContextPrivate
62 {
63   GtkCellArea *cell_area;
64
65   gint         min_width;
66   gint         nat_width;
67   gint         min_height;
68   gint         nat_height;
69   gint         alloc_width;
70   gint         alloc_height;
71 };
72
73 enum {
74   PROP_0,
75   PROP_CELL_AREA,
76   PROP_MIN_WIDTH,
77   PROP_NAT_WIDTH,
78   PROP_MIN_HEIGHT,
79   PROP_NAT_HEIGHT
80 };
81
82 G_DEFINE_TYPE (GtkCellAreaContext, gtk_cell_area_context, G_TYPE_OBJECT);
83
84 static void
85 gtk_cell_area_context_init (GtkCellAreaContext *context)
86 {
87   GtkCellAreaContextPrivate *priv;
88
89   context->priv = G_TYPE_INSTANCE_GET_PRIVATE (context,
90                                                GTK_TYPE_CELL_AREA_CONTEXT,
91                                                GtkCellAreaContextPrivate);
92   priv = context->priv;
93
94   priv->min_width  = -1;
95   priv->nat_width  = -1;
96   priv->min_height = -1;
97   priv->nat_height = -1;
98 }
99
100 static void 
101 gtk_cell_area_context_class_init (GtkCellAreaContextClass *class)
102 {
103   GObjectClass     *object_class = G_OBJECT_CLASS (class);
104
105   /* GObjectClass */
106   object_class->dispose      = gtk_cell_area_context_dispose;
107   object_class->get_property = gtk_cell_area_context_get_property;
108   object_class->set_property = gtk_cell_area_context_set_property;
109
110   /* GtkCellAreaContextClass */
111   class->reset    = gtk_cell_area_context_real_reset;
112   class->allocate = gtk_cell_area_context_real_allocate;
113
114   /**
115    * GtkCellAreaContext:area:
116    *
117    * The #GtkCellArea this context was created by
118    *
119    * Since: 3.0
120    */
121   g_object_class_install_property (object_class,
122                                    PROP_CELL_AREA,
123                                    g_param_spec_object ("area",
124                                                         P_("Area"),
125                                                         P_("The Cell Area this context was created for"),
126                                                         GTK_TYPE_CELL_AREA,
127                                                         GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
128
129   /**
130    * GtkCellAreaContext:minimum-width:
131    *
132    * The minimum width for the #GtkCellArea in this context
133    * for all #GtkTreeModel rows that this context was requested
134    * for using gtk_cell_area_get_preferred_width().
135    *
136    * Since: 3.0
137    */
138   g_object_class_install_property (object_class,
139                                    PROP_MIN_WIDTH,
140                                    g_param_spec_int ("minimum-width",
141                                                      P_("Minimum Width"),
142                                                      P_("Minimum cached width"),
143                                                      -1,
144                                                      G_MAXINT,
145                                                      -1,
146                                                      G_PARAM_READABLE));
147
148   /**
149    * GtkCellAreaContext:natural-width:
150    *
151    * The natural width for the #GtkCellArea in this context
152    * for all #GtkTreeModel rows that this context was requested
153    * for using gtk_cell_area_get_preferred_width().
154    *
155    * Since: 3.0
156    */
157   g_object_class_install_property (object_class,
158                                    PROP_NAT_WIDTH,
159                                    g_param_spec_int ("natural-width",
160                                                      P_("Minimum Width"),
161                                                      P_("Minimum cached width"),
162                                                      -1,
163                                                      G_MAXINT,
164                                                      -1,
165                                                      G_PARAM_READABLE));
166
167   /**
168    * GtkCellAreaContext:minimum-height:
169    *
170    * The minimum height for the #GtkCellArea in this context
171    * for all #GtkTreeModel rows that this context was requested
172    * for using gtk_cell_area_get_preferred_height().
173    *
174    * Since: 3.0
175    */
176   g_object_class_install_property (object_class,
177                                    PROP_MIN_HEIGHT,
178                                    g_param_spec_int ("minimum-height",
179                                                      P_("Minimum Height"),
180                                                      P_("Minimum cached height"),
181                                                      -1,
182                                                      G_MAXINT,
183                                                      -1,
184                                                      G_PARAM_READABLE));
185
186   /**
187    * GtkCellAreaContext:natural-height:
188    *
189    * The natural height for the #GtkCellArea in this context
190    * for all #GtkTreeModel rows that this context was requested
191    * for using gtk_cell_area_get_preferred_height().
192    *
193    * Since: 3.0
194    */
195   g_object_class_install_property (object_class,
196                                    PROP_NAT_HEIGHT,
197                                    g_param_spec_int ("natural-height",
198                                                      P_("Minimum Height"),
199                                                      P_("Minimum cached height"),
200                                                      -1,
201                                                      G_MAXINT,
202                                                      -1,
203                                                      G_PARAM_READABLE));
204
205   g_type_class_add_private (object_class, sizeof (GtkCellAreaContextPrivate));
206 }
207
208 /*************************************************************
209  *                      GObjectClass                         *
210  *************************************************************/
211 static void
212 gtk_cell_area_context_dispose (GObject *object)
213 {
214   GtkCellAreaContext        *context = GTK_CELL_AREA_CONTEXT (object);
215   GtkCellAreaContextPrivate *priv = context->priv;
216
217   if (priv->cell_area)
218     {
219       g_object_unref (priv->cell_area);
220
221       priv->cell_area = NULL;
222     }
223
224   G_OBJECT_CLASS (gtk_cell_area_context_parent_class)->dispose (object);
225 }
226
227 static void
228 gtk_cell_area_context_set_property (GObject      *object,
229                                     guint         prop_id,
230                                     const GValue *value,
231                                     GParamSpec   *pspec)
232 {
233   GtkCellAreaContext        *context = GTK_CELL_AREA_CONTEXT (object);
234   GtkCellAreaContextPrivate *priv = context->priv;
235
236   switch (prop_id)
237     {
238     case PROP_CELL_AREA:
239       priv->cell_area = g_value_dup_object (value);
240       break;
241     default:
242       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
243       break;
244     }
245 }
246
247 static void
248 gtk_cell_area_context_get_property (GObject     *object,
249                                     guint        prop_id,
250                                     GValue      *value,
251                                     GParamSpec  *pspec)
252 {
253   GtkCellAreaContext        *context = GTK_CELL_AREA_CONTEXT (object);
254   GtkCellAreaContextPrivate *priv = context->priv;
255
256   switch (prop_id)
257     {
258     case PROP_CELL_AREA:
259       g_value_set_object (value, priv->cell_area);
260       break;
261     case PROP_MIN_WIDTH:
262       g_value_set_int (value, priv->min_width);
263       break;
264     case PROP_NAT_WIDTH:
265       g_value_set_int (value, priv->nat_width);
266       break;
267     case PROP_MIN_HEIGHT:
268       g_value_set_int (value, priv->min_height);
269       break;
270     case PROP_NAT_HEIGHT:
271       g_value_set_int (value, priv->nat_height);
272       break;
273     default:
274       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275       break;
276     }
277 }
278
279 /*************************************************************
280  *                    GtkCellAreaContextClass                   *
281  *************************************************************/
282 static void
283 gtk_cell_area_context_real_reset (GtkCellAreaContext *context)
284 {
285   GtkCellAreaContextPrivate *priv = context->priv;
286   
287   g_object_freeze_notify (G_OBJECT (context));
288
289   if (priv->min_width != -1)
290     {
291       priv->min_width = -1;
292       g_object_notify (G_OBJECT (context), "minimum-width");
293     }
294
295   if (priv->nat_width != -1)
296     {
297       priv->nat_width = -1;
298       g_object_notify (G_OBJECT (context), "natural-width");
299     }
300
301   if (priv->min_height != -1)
302     {
303       priv->min_height = -1;
304       g_object_notify (G_OBJECT (context), "minimum-height");
305     }
306
307   if (priv->nat_height != -1)
308     {
309       priv->nat_height = -1;
310       g_object_notify (G_OBJECT (context), "natural-height");
311     }
312
313   priv->alloc_width  = 0;
314   priv->alloc_height = 0;
315
316   g_object_thaw_notify (G_OBJECT (context));
317 }
318
319 static void
320 gtk_cell_area_context_real_allocate (GtkCellAreaContext *context,
321                                      gint                width,
322                                      gint                height)
323 {
324   GtkCellAreaContextPrivate *priv = context->priv;
325
326   priv->alloc_width  = width;
327   priv->alloc_height = height;
328 }
329
330 /*************************************************************
331  *                            API                            *
332  *************************************************************/
333 /**
334  * gtk_cell_area_context_get_area:
335  * @context: a #GtkCellAreaContext
336  *
337  * Fetches the #GtkCellArea this @context was created by.
338  *
339  * This is generally unneeded by layouting widgets however
340  * its important for the context implementation itself to
341  * fetch information about the area it is being used for.
342  *
343  * For instance at #GtkCellAreaContextClass.allocate() time
344  * it's important to know details about any cell spacing
345  * that the #GtkCellArea is configured with in order to 
346  * compute a proper allocation.
347  *
348  * Return value: the #GtkCellArea this context was created by.
349  *
350  * Since: 3.0
351  */
352 GtkCellArea *
353 gtk_cell_area_context_get_area (GtkCellAreaContext *context)
354 {
355   GtkCellAreaContextPrivate *priv;
356
357   g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
358
359   priv = context->priv;
360
361   return priv->cell_area;
362 }
363
364 /**
365  * gtk_cell_area_context_reset:
366  * @context: a #GtkCellAreaContext
367  *
368  * Resets any previously cached request and allocation
369  * data. 
370  *
371  * When underlying #GtkTreeModel data changes it's 
372  * important to reset the context if the content
373  * size is allowed to shrink. If the content size
374  * is only allowed to grow (this is usually an option
375  * for views rendering large data stores as a measure
376  * of optimization), then only the row that changed
377  * or was inserted needs to be (re)requested with 
378  * gtk_cell_area_get_preferred_width().
379  *
380  * When the new overall size of the context requires
381  * that the allocated size changes (or whenever this
382  * allocation changes at all), the variable row
383  * sizes need to be re-requested for every row.
384  *
385  * For instance, if the rows are displayed all with
386  * the same width from top to bottom then a change
387  * in the allocated width necessitates a recalculation
388  * of all the displayed row heights using
389  * gtk_cell_area_get_preferred_height_for_width().
390  *
391  * Since 3.0
392  */
393 void
394 gtk_cell_area_context_reset (GtkCellAreaContext *context)
395 {
396   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
397
398   GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->reset (context);
399 }
400
401 /**
402  * gtk_cell_area_context_allocate:
403  * @context: a #GtkCellAreaContext
404  * @width: the allocated width for all #GtkTreeModel rows rendered with @context, or -1.
405  * @height: the allocated height for all #GtkTreeModel rows rendered with @context, or -1.
406  *
407  * Allocates a width and/or a height for all rows which are to be rendered with @context.
408  *
409  * Usually allocation is performed only horizontally or sometimes vertically since
410  * a group of rows are usually rendered side by side vertically or horizontally and 
411  * share either the same width or the same hieght. Sometimes they are allocated in
412  * both horizontal and vertical orientations producing a homogenious effect of the
413  * rows. This is generally the case for #GtkTreeView when #GtkTreeView:fixed-height-mode
414  * is enabled.
415  *
416  * Since 3.0
417  */
418 void
419 gtk_cell_area_context_allocate (GtkCellAreaContext *context,
420                                 gint                width,
421                                 gint                height)
422 {
423   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
424
425   GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->allocate (context, width, height);
426 }
427
428 /**
429  * gtk_cell_area_context_get_preferred_width:
430  * @context: a #GtkCellAreaContext
431  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
432  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
433  *
434  * Gets the accumulative preferred width for all rows which have been requested
435  * with this context.
436  *
437  * After gtk_cell_area_context_reset() is called and/or before ever requesting
438  * the size of a #GtkCellArea, the returned values are -1.
439  *
440  * Since: 3.0 
441  */
442 void
443 gtk_cell_area_context_get_preferred_width (GtkCellAreaContext *context,
444                                            gint               *minimum_width,
445                                            gint               *natural_width)
446 {
447   GtkCellAreaContextPrivate *priv;
448
449   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
450
451   priv = context->priv;
452
453   if (minimum_width)
454     *minimum_width = priv->min_width;
455
456   if (natural_width)
457     *natural_width = priv->nat_width;
458 }
459
460 /**
461  * gtk_cell_area_context_get_preferred_height:
462  * @context: a #GtkCellAreaContext
463  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
464  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
465  *
466  * Gets the accumulative preferred height for all rows which have been requested
467  * with this context.
468  *
469  * After gtk_cell_area_context_reset() is called and/or before ever requesting
470  * the size of a #GtkCellArea, the returned values are -1.
471  *
472  * Since: 3.0
473  */
474 void
475 gtk_cell_area_context_get_preferred_height (GtkCellAreaContext *context,
476                                             gint               *minimum_height,
477                                             gint               *natural_height)
478 {
479   GtkCellAreaContextPrivate *priv;
480
481   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
482
483   priv = context->priv;
484
485   if (minimum_height)
486     *minimum_height = priv->min_height;
487
488   if (natural_height)
489     *natural_height = priv->nat_height;
490 }
491
492 /**
493  * gtk_cell_area_context_get_preferred_height_for_width:
494  * @context: a #GtkCellAreaContext
495  * @width: a proposed width for allocation
496  * @minimum_height: (out) (allow-none): location to store the minimum height, or %NULL
497  * @natural_height: (out) (allow-none): location to store the natural height, or %NULL
498  *
499  * Gets the accumulative preferred height for @width for all rows which have been 
500  * requested for the same said @width with this context.
501  *
502  * After gtk_cell_area_context_reset() is called and/or before ever requesting
503  * the size of a #GtkCellArea, the returned values are -1.
504  *
505  * Since: 3.0
506  */
507 void
508 gtk_cell_area_context_get_preferred_height_for_width (GtkCellAreaContext *context,
509                                                       gint                width,
510                                                       gint               *minimum_height,
511                                                       gint               *natural_height)
512 {
513   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
514
515   if (GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_height_for_width)
516     GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_height_for_width (context,
517                                                                                width,
518                                                                                minimum_height,
519                                                                                natural_height);
520 }
521
522 /**
523  * gtk_cell_area_context_get_preferred_width_for_height:
524  * @context: a #GtkCellAreaContext
525  * @height: a proposed height for allocation
526  * @minimum_width: (out) (allow-none): location to store the minimum width, or %NULL
527  * @natural_width: (out) (allow-none): location to store the natural width, or %NULL
528  *
529  * Gets the accumulative preferred width for @height for all rows which have 
530  * been requested for the same said @height with this context.
531  *
532  * After gtk_cell_area_context_reset() is called and/or before ever requesting
533  * the size of a #GtkCellArea, the returned values are -1.
534  *
535  * Since: 3.0 
536  */
537 void
538 gtk_cell_area_context_get_preferred_width_for_height (GtkCellAreaContext *context,
539                                                       gint                height,
540                                                       gint               *minimum_width,
541                                                       gint               *natural_width)
542 {  
543   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
544
545   if (GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_width_for_height)
546     GTK_CELL_AREA_CONTEXT_GET_CLASS (context)->get_preferred_width_for_height (context,
547                                                                                height,
548                                                                                minimum_width,
549                                                                                natural_width);
550 }
551
552 /**
553  * gtk_cell_area_context_get_allocation:
554  * @context: a #GtkCellAreaContext
555  * @width: (out) (allow-none): location to store the allocated width, or %NULL.
556  * @height: (out) (allow-none): location to store the allocated height, or %NULL.
557  *
558  * Fetches the current allocation size for @context.
559  *
560  * If the context was not allocated in width or height, or if the
561  * context was recently reset with gtk_cell_area_context_reset(),
562  * the returned value will be -1.
563  *
564  * Since: 3.0
565  */
566 void
567 gtk_cell_area_context_get_allocation (GtkCellAreaContext *context,
568                                       gint               *width,
569                                       gint               *height)
570 {
571   GtkCellAreaContextPrivate *priv;
572
573   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
574
575   priv = context->priv;
576
577   if (width)
578     *width = priv->alloc_width;
579
580   if (height)
581     *height = priv->alloc_height;
582 }
583
584 /**
585  * gtk_cell_area_context_push_preferred_width:
586  * @context: a #GtkCellAreaContext
587  * @minimum_width: the proposed new minimum width for @context.
588  * @natural_width: the proposed new natural width for @context.
589  *
590  * Causes the minimum and/or natural width to grow if the new
591  * proposed sizes exceed the current minimum and natural width.
592  *
593  * This is used by #GtkCellAreaContext implementations during
594  * the request process over a series of #GtkTreeModel rows to
595  * progressively push the requested width over a series of
596  * gtk_cell_area_get_preferred_width() requests.
597  *
598  * Since: 3.0
599  */
600 void
601 gtk_cell_area_context_push_preferred_width (GtkCellAreaContext *context,
602                                             gint                minimum_width,
603                                             gint                natural_width)
604 {
605   GtkCellAreaContextPrivate *priv;
606
607   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
608
609   priv = context->priv;
610
611   g_object_freeze_notify (G_OBJECT (context));
612
613   if (minimum_width > priv->min_width)
614     {
615       priv->min_width = minimum_width;
616
617       g_object_notify (G_OBJECT (context), "minimum-width");
618     }
619
620   if (natural_width > priv->nat_width)
621     {
622       priv->nat_width = natural_width;
623
624       g_object_notify (G_OBJECT (context), "natural-width");
625     }
626
627   g_object_thaw_notify (G_OBJECT (context));
628 }
629
630 /**
631  * gtk_cell_area_context_push_preferred_height:
632  * @context: a #GtkCellAreaContext
633  * @minimum_height: the proposed new minimum height for @context.
634  * @natural_height: the proposed new natural height for @context.
635  *
636  * Causes the minimum and/or natural height to grow if the new
637  * proposed sizes exceed the current minimum and natural height.
638  *
639  * This is used by #GtkCellAreaContext implementations during
640  * the request process over a series of #GtkTreeModel rows to
641  * progressively push the requested height over a series of
642  * gtk_cell_area_get_preferred_height() requests.
643  *
644  * Since: 3.0
645  */
646 void
647 gtk_cell_area_context_push_preferred_height (GtkCellAreaContext *context,
648                                              gint                minimum_height,
649                                              gint                natural_height)
650 {
651   GtkCellAreaContextPrivate *priv;
652   
653   g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
654
655   priv = context->priv;
656
657   g_object_freeze_notify (G_OBJECT (context));
658
659   if (minimum_height > priv->min_height)
660     {
661       priv->min_height = minimum_height;
662
663       g_object_notify (G_OBJECT (context), "minimum-height");
664     }
665
666   if (natural_height > priv->nat_height)
667     {
668       priv->nat_height = natural_height;
669
670       g_object_notify (G_OBJECT (context), "natural-height");
671     }
672
673   g_object_thaw_notify (G_OBJECT (context));
674 }