1 /* gtkcellareaboxiter.c
3 * Copyright (C) 2010 Openismus GmbH
6 * Tristan Van Berkom <tristanvb@openismus.com>
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.
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.
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.
26 #include "gtkcellareabox.h"
27 #include "gtkcellareaboxiter.h"
28 #include "gtkorientable.h"
31 static void gtk_cell_area_box_iter_finalize (GObject *object);
33 /* GtkCellAreaIterClass */
34 static void gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter);
35 static void gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
37 static void gtk_cell_area_box_iter_flush_preferred_height (GtkCellAreaIter *iter);
38 static void gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
40 static void gtk_cell_area_box_iter_flush_allocation (GtkCellAreaIter *iter);
41 static void gtk_cell_area_box_iter_sum_preferred_width (GtkCellAreaIter *iter);
42 static void gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
44 static void gtk_cell_area_box_iter_sum_preferred_height (GtkCellAreaIter *iter);
45 static void gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
47 static void gtk_cell_area_box_iter_allocate_width (GtkCellAreaIter *iter,
49 static void gtk_cell_area_box_iter_allocate_height (GtkCellAreaIter *iter,
54 /* CachedSize management */
60 static CachedSize *cached_size_new (gint min_size, gint nat_size);
61 static void cached_size_free (CachedSize *size);
63 struct _GtkCellAreaBoxIterPrivate
65 /* Table of per renderer CachedSizes */
66 GHashTable *base_widths;
67 GHashTable *base_heights;
69 /* Table of per height/width hash tables of per renderer CachedSizes */
73 /* Allocation info for this iter if any */
76 gint n_orientation_allocs;
77 GtkCellAreaBoxAllocation *orientation_allocs;
80 G_DEFINE_TYPE (GtkCellAreaBoxIter, gtk_cell_area_box_iter, GTK_TYPE_CELL_AREA_ITER);
83 gtk_cell_area_box_iter_init (GtkCellAreaBoxIter *box_iter)
85 GtkCellAreaBoxIterPrivate *priv;
87 box_iter->priv = G_TYPE_INSTANCE_GET_PRIVATE (box_iter,
88 GTK_TYPE_CELL_AREA_BOX_ITER,
89 GtkCellAreaBoxIterPrivate);
90 priv = box_iter->priv;
92 priv->base_widths = g_hash_table_new_full (g_direct_hash, g_direct_equal,
93 NULL, (GDestroyNotify)cached_size_free);
94 priv->base_heights = g_hash_table_new_full (g_direct_hash, g_direct_equal,
95 NULL, (GDestroyNotify)cached_size_free);
97 priv->widths = g_hash_table_new_full (g_direct_hash, g_direct_equal,
98 NULL, (GDestroyNotify)g_hash_table_destroy);
99 priv->heights = g_hash_table_new_full (g_direct_hash, g_direct_equal,
100 NULL, (GDestroyNotify)g_hash_table_destroy);
102 priv->alloc_width = 0;
103 priv->alloc_height = 0;
104 priv->orientation_allocs = NULL;
105 priv->n_orientation_allocs = 0;
109 gtk_cell_area_box_iter_class_init (GtkCellAreaBoxIterClass *class)
111 GObjectClass *object_class = G_OBJECT_CLASS (class);
112 GtkCellAreaIterClass *iter_class = GTK_CELL_AREA_ITER_CLASS (class);
115 object_class->finalize = gtk_cell_area_box_iter_finalize;
117 iter_class->flush_preferred_width = gtk_cell_area_box_iter_flush_preferred_width;
118 iter_class->flush_preferred_height_for_width = gtk_cell_area_box_iter_flush_preferred_height_for_width;
119 iter_class->flush_preferred_height = gtk_cell_area_box_iter_flush_preferred_height;
120 iter_class->flush_preferred_width_for_height = gtk_cell_area_box_iter_flush_preferred_width_for_height;
121 iter_class->flush_allocation = gtk_cell_area_box_iter_flush_allocation;
123 iter_class->sum_preferred_width = gtk_cell_area_box_iter_sum_preferred_width;
124 iter_class->sum_preferred_height_for_width = gtk_cell_area_box_iter_sum_preferred_height_for_width;
125 iter_class->sum_preferred_height = gtk_cell_area_box_iter_sum_preferred_height;
126 iter_class->sum_preferred_width_for_height = gtk_cell_area_box_iter_sum_preferred_width_for_height;
128 iter_class->allocate_width = gtk_cell_area_box_iter_allocate_width;
129 iter_class->allocate_height = gtk_cell_area_box_iter_allocate_height;
131 g_type_class_add_private (object_class, sizeof (GtkCellAreaBoxIterPrivate));
134 /*************************************************************
136 *************************************************************/
138 cached_size_new (gint min_size,
141 CachedSize *size = g_slice_new (CachedSize);
143 size->min_size = min_size;
144 size->nat_size = nat_size;
150 cached_size_free (CachedSize *size)
152 g_slice_free (CachedSize, size);
155 /*************************************************************
157 *************************************************************/
159 gtk_cell_area_box_iter_finalize (GObject *object)
161 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (object);
162 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
164 g_hash_table_destroy (priv->base_widths);
165 g_hash_table_destroy (priv->base_heights);
166 g_hash_table_destroy (priv->widths);
167 g_hash_table_destroy (priv->heights);
169 g_free (priv->orientation_allocs);
171 G_OBJECT_CLASS (gtk_cell_area_box_iter_parent_class)->finalize (object);
174 /*************************************************************
175 * GtkCellAreaIterClass *
176 *************************************************************/
178 gtk_cell_area_box_iter_flush_preferred_width (GtkCellAreaIter *iter)
180 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
181 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
183 g_hash_table_remove_all (priv->base_widths);
185 GTK_CELL_AREA_ITER_GET_CLASS
186 (gtk_cell_area_box_iter_parent_class)->flush_preferred_width (iter);
190 gtk_cell_area_box_iter_flush_preferred_height_for_width (GtkCellAreaIter *iter,
193 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
194 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
196 /* Flush all sizes for special -1 value */
198 g_hash_table_remove_all (priv->heights);
200 g_hash_table_remove (priv->heights, GINT_TO_POINTER (width));
202 GTK_CELL_AREA_ITER_GET_CLASS
203 (gtk_cell_area_box_iter_parent_class)->flush_preferred_height_for_width (iter, width);
207 gtk_cell_area_box_iter_flush_preferred_height (GtkCellAreaIter *iter)
209 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
210 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
212 g_hash_table_remove_all (priv->base_heights);
214 GTK_CELL_AREA_ITER_GET_CLASS
215 (gtk_cell_area_box_iter_parent_class)->flush_preferred_height (iter);
219 gtk_cell_area_box_iter_flush_preferred_width_for_height (GtkCellAreaIter *iter,
222 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
223 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
225 /* Flush all sizes for special -1 value */
227 g_hash_table_remove_all (priv->widths);
229 g_hash_table_remove (priv->widths, GINT_TO_POINTER (height));
231 GTK_CELL_AREA_ITER_GET_CLASS
232 (gtk_cell_area_box_iter_parent_class)->flush_preferred_width_for_height (iter, height);
236 gtk_cell_area_box_iter_flush_allocation (GtkCellAreaIter *iter)
238 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
239 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
241 g_free (priv->orientation_allocs);
242 priv->orientation_allocs = NULL;
243 priv->n_orientation_allocs = 0;
253 sum_base_size (gpointer group_id,
257 if (accum->min_size > 0)
259 accum->min_size += accum->spacing;
260 accum->nat_size += accum->spacing;
263 accum->min_size += size->min_size;
264 accum->nat_size += size->nat_size;
268 sum_for_size (gpointer group_id,
272 accum->min_size = MAX (accum->min_size, size->min_size);
273 accum->nat_size = MAX (accum->nat_size, size->nat_size);
277 gtk_cell_area_box_iter_sum_preferred_width (GtkCellAreaIter *iter)
279 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
280 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
282 AccumData accum = { 0, };
284 area = gtk_cell_area_iter_get_area (iter);
285 accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
287 g_hash_table_foreach (priv->base_widths, (GHFunc)sum_base_size, &accum);
288 gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size);
292 gtk_cell_area_box_iter_sum_preferred_height_for_width (GtkCellAreaIter *iter,
295 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
296 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
297 GHashTable *group_table;
298 AccumData accum = { 0, };
300 group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (width));
304 g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum);
305 gtk_cell_area_iter_push_preferred_height_for_width (iter, width, accum.min_size, accum.nat_size);
310 gtk_cell_area_box_iter_sum_preferred_height (GtkCellAreaIter *iter)
312 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
313 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
315 AccumData accum = { 0, };
317 area = gtk_cell_area_iter_get_area (iter);
318 accum.spacing = gtk_cell_area_box_get_spacing (GTK_CELL_AREA_BOX (area));
320 g_hash_table_foreach (priv->base_heights, (GHFunc)sum_base_size, &accum);
321 gtk_cell_area_iter_push_preferred_width (iter, accum.min_size, accum.nat_size);
325 gtk_cell_area_box_iter_sum_preferred_width_for_height (GtkCellAreaIter *iter,
328 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
329 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
330 GHashTable *group_table;
331 AccumData accum = { 0, };
333 group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (height));
337 g_hash_table_foreach (priv->base_widths, (GHFunc)sum_for_size, &accum);
338 gtk_cell_area_iter_push_preferred_width_for_height (iter, height, accum.min_size, accum.nat_size);
343 gtk_cell_area_box_iter_allocate_width (GtkCellAreaIter *iter,
346 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
347 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
349 GtkOrientation orientation;
351 area = gtk_cell_area_iter_get_area (iter);
352 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
354 if (orientation == GTK_ORIENTATION_HORIZONTAL)
356 g_free (priv->orientation_allocs);
358 priv->orientation_allocs =
359 gtk_cell_area_box_allocate (GTK_CELL_AREA_BOX (area), box_iter, width,
360 &priv->n_orientation_allocs);
363 GTK_CELL_AREA_ITER_GET_CLASS (iter)->allocate_width (iter, width);
367 gtk_cell_area_box_iter_allocate_height (GtkCellAreaIter *iter,
370 GtkCellAreaBoxIter *box_iter = GTK_CELL_AREA_BOX_ITER (iter);
371 GtkCellAreaBoxIterPrivate *priv = box_iter->priv;
373 GtkOrientation orientation;
375 area = gtk_cell_area_iter_get_area (iter);
376 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
378 if (orientation == GTK_ORIENTATION_VERTICAL)
380 g_free (priv->orientation_allocs);
382 priv->orientation_allocs =
383 gtk_cell_area_box_allocate (GTK_CELL_AREA_BOX (area), box_iter, height,
384 &priv->n_orientation_allocs);
387 GTK_CELL_AREA_ITER_GET_CLASS (iter)->allocate_height (iter, height);
390 /*************************************************************
392 *************************************************************/
395 gtk_cell_area_box_iter_push_group_width (GtkCellAreaBoxIter *box_iter,
400 GtkCellAreaBoxIterPrivate *priv;
403 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
405 priv = box_iter->priv;
406 size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
410 size = cached_size_new (minimum_width, natural_width);
411 g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
415 size->min_size = MAX (size->min_size, minimum_width);
416 size->nat_size = MAX (size->nat_size, natural_width);
421 gtk_cell_area_box_iter_push_group_height_for_width (GtkCellAreaBoxIter *box_iter,
427 GtkCellAreaBoxIterPrivate *priv;
428 GHashTable *group_table;
431 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
433 priv = box_iter->priv;
434 group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
438 group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
439 NULL, (GDestroyNotify)cached_size_free);
441 g_hash_table_insert (priv->heights, GINT_TO_POINTER (for_width), group_table);
444 size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
448 size = cached_size_new (minimum_height, natural_height);
449 g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
453 size->min_size = MAX (size->min_size, minimum_height);
454 size->nat_size = MAX (size->nat_size, natural_height);
459 gtk_cell_area_box_iter_push_group_height (GtkCellAreaBoxIter *box_iter,
464 GtkCellAreaBoxIterPrivate *priv;
467 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
469 priv = box_iter->priv;
470 size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
474 size = cached_size_new (minimum_height, natural_height);
475 g_hash_table_insert (priv->base_widths, GINT_TO_POINTER (group_id), size);
479 size->min_size = MAX (size->min_size, minimum_height);
480 size->nat_size = MAX (size->nat_size, natural_height);
485 gtk_cell_area_box_iter_push_group_width_for_height (GtkCellAreaBoxIter *box_iter,
491 GtkCellAreaBoxIterPrivate *priv;
492 GHashTable *group_table;
495 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
497 priv = box_iter->priv;
498 group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
502 group_table = g_hash_table_new_full (g_direct_hash, g_direct_equal,
503 NULL, (GDestroyNotify)cached_size_free);
505 g_hash_table_insert (priv->widths, GINT_TO_POINTER (for_height), group_table);
508 size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
512 size = cached_size_new (minimum_width, natural_width);
513 g_hash_table_insert (group_table, GINT_TO_POINTER (group_id), size);
517 size->min_size = MAX (size->min_size, minimum_width);
518 size->nat_size = MAX (size->nat_size, natural_width);
523 gtk_cell_area_box_iter_get_group_width (GtkCellAreaBoxIter *box_iter,
528 GtkCellAreaBoxIterPrivate *priv;
531 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
533 priv = box_iter->priv;
534 size = g_hash_table_lookup (priv->base_widths, GINT_TO_POINTER (group_id));
539 *minimum_width = size->min_size;
542 *natural_width = size->nat_size;
555 gtk_cell_area_box_iter_get_group_height_for_width (GtkCellAreaBoxIter *box_iter,
558 gint *minimum_height,
559 gint *natural_height)
561 GtkCellAreaBoxIterPrivate *priv;
562 GHashTable *group_table;
563 CachedSize *size = NULL;
565 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
567 priv = box_iter->priv;
568 group_table = g_hash_table_lookup (priv->heights, GINT_TO_POINTER (for_width));
571 size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
576 *minimum_height = size->min_size;
579 *natural_height = size->nat_size;
584 *minimum_height = -1;
587 *natural_height = -1;
592 gtk_cell_area_box_iter_get_group_height (GtkCellAreaBoxIter *box_iter,
594 gint *minimum_height,
595 gint *natural_height)
597 GtkCellAreaBoxIterPrivate *priv;
600 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
602 priv = box_iter->priv;
603 size = g_hash_table_lookup (priv->base_heights, GINT_TO_POINTER (group_id));
608 *minimum_height = size->min_size;
611 *natural_height = size->nat_size;
616 *minimum_height = -1;
619 *natural_height = -1;
624 gtk_cell_area_box_iter_get_group_width_for_height (GtkCellAreaBoxIter *box_iter,
630 GtkCellAreaBoxIterPrivate *priv;
631 GHashTable *group_table;
632 CachedSize *size = NULL;
634 g_return_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter));
636 priv = box_iter->priv;
637 group_table = g_hash_table_lookup (priv->widths, GINT_TO_POINTER (for_height));
640 size = g_hash_table_lookup (group_table, GINT_TO_POINTER (group_id));
645 *minimum_width = size->min_size;
648 *natural_width = size->nat_size;
661 fill_requested_sizes (gpointer group_id_ptr,
662 CachedSize *cached_size,
663 GtkRequestedSize *requested)
665 gint group_id = GPOINTER_TO_INT (group_id_ptr);
667 requested[group_id].data = group_id_ptr;
668 requested[group_id].minimum_size = cached_size->min_size;
669 requested[group_id].natural_size = cached_size->nat_size;
673 gtk_cell_area_box_iter_get_widths (GtkCellAreaBoxIter *box_iter,
676 GtkCellAreaBoxIterPrivate *priv;
677 GtkRequestedSize *widths;
679 g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
681 priv = box_iter->priv;
683 *n_widths = g_hash_table_size (priv->widths);
684 widths = g_new (GtkRequestedSize, *n_widths);
686 g_hash_table_foreach (priv->widths, (GHFunc)fill_requested_sizes, widths);
692 gtk_cell_area_box_iter_get_heights (GtkCellAreaBoxIter *box_iter,
695 GtkCellAreaBoxIterPrivate *priv;
696 GtkRequestedSize *heights;
698 g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (box_iter), NULL);
700 priv = box_iter->priv;
702 *n_heights = g_hash_table_size (priv->heights);
703 heights = g_new (GtkRequestedSize, *n_heights);
705 g_hash_table_foreach (priv->heights, (GHFunc)fill_requested_sizes, heights);
710 G_CONST_RETURN GtkCellAreaBoxAllocation *
711 gtk_cell_area_box_iter_get_orientation_allocs (GtkCellAreaBoxIter *iter,
714 GtkCellAreaBoxIterPrivate *priv;
716 g_return_val_if_fail (GTK_IS_CELL_AREA_BOX_ITER (iter), NULL);
720 *n_allocs = priv->n_orientation_allocs;
722 return priv->orientation_allocs;