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