1/* gtkcellareaboxcontext.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, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "config.h"
23#include "gtkintl.h"
24#include "gtkcellareabox.h"
25#include "gtkcellareaboxcontextprivate.h"
26#include "gtkorientable.h"
27
28#include "gtkprivate.h"
29
30/* GObjectClass */
31static void _gtk_cell_area_box_context_finalize (GObject *object);
32
33/* GtkCellAreaContextClass */
34static void _gtk_cell_area_box_context_reset (GtkCellAreaContext *context);
35static void _gtk_cell_area_box_context_get_preferred_height_for_width (GtkCellAreaContext *context,
36 int width,
37 int *minimum_height,
38 int *natural_height);
39static void _gtk_cell_area_box_context_get_preferred_width_for_height (GtkCellAreaContext *context,
40 int height,
41 int *minimum_width,
42 int *natural_width);
43
44
45
46/* Internal functions */
47static void _gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context,
48 GtkOrientation orientation,
49 int for_size,
50 int *minimum_size,
51 int *natural_size);
52static void free_cache_array (GArray *array);
53static GArray *group_array_new (GtkCellAreaBoxContext *context);
54static GArray *get_array (GtkCellAreaBoxContext *context,
55 GtkOrientation orientation,
56 int for_size);
57static gboolean group_expands (GtkCellAreaBoxContext *context,
58 int group_idx);
59static int count_expand_groups (GtkCellAreaBoxContext *context);
60
61
62/* CachedSize management */
63typedef struct {
64 int min_size;
65 int nat_size;
66} CachedSize;
67
68struct _GtkCellAreaBoxContextPrivate
69{
70 /* Table of per renderer CachedSizes */
71 GArray *base_widths;
72 GArray *base_heights;
73
74 /* Table of per height/width hash tables of per renderer CachedSizes */
75 GHashTable *widths;
76 GHashTable *heights;
77
78 /* Whether each group expands */
79 gboolean *expand;
80
81 /* Whether each group is aligned */
82 gboolean *align;
83};
84
85G_DEFINE_TYPE_WITH_PRIVATE (GtkCellAreaBoxContext, _gtk_cell_area_box_context, GTK_TYPE_CELL_AREA_CONTEXT)
86
87static void
88free_cache_array (GArray *array)
89{
90 g_array_free (array, TRUE);
91}
92
93static GArray *
94group_array_new (GtkCellAreaBoxContext *context)
95{
96 GtkCellAreaBoxContextPrivate *priv = context->priv;
97 GArray *group_array;
98
99 group_array = g_array_new (FALSE, TRUE, element_size: sizeof (CachedSize));
100 g_array_set_size (array: group_array, length: priv->base_widths->len);
101
102 return group_array;
103}
104
105static GArray *
106get_array (GtkCellAreaBoxContext *context,
107 GtkOrientation orientation,
108 int for_size)
109{
110 GtkCellAreaBoxContextPrivate *priv = context->priv;
111 GArray *array;
112
113 if (for_size < 0)
114 {
115 if (orientation == GTK_ORIENTATION_HORIZONTAL)
116 array = priv->base_widths;
117 else
118 array = priv->base_heights;
119 }
120 else
121 {
122 if (orientation == GTK_ORIENTATION_HORIZONTAL)
123 {
124 array = g_hash_table_lookup (hash_table: priv->widths, GINT_TO_POINTER (for_size));
125
126 if (!array)
127 array = priv->base_widths;
128 }
129 else
130 {
131 array = g_hash_table_lookup (hash_table: priv->heights, GINT_TO_POINTER (for_size));
132
133 if (!array)
134 array = priv->base_heights;
135 }
136 }
137
138 return array;
139}
140
141static gboolean
142group_expands (GtkCellAreaBoxContext *context,
143 int group_idx)
144{
145 GtkCellAreaBoxContextPrivate *priv = context->priv;
146
147 g_assert (group_idx >= 0 && group_idx < priv->base_widths->len);
148
149 return priv->expand[group_idx];
150}
151
152static int
153count_expand_groups (GtkCellAreaBoxContext *context)
154{
155 GtkCellAreaBoxContextPrivate *priv = context->priv;
156 int i, expand = 0;
157
158 for (i = 0; i < priv->base_widths->len; i++)
159 {
160 if (priv->expand[i])
161 expand++;
162 }
163
164 return expand;
165}
166
167static void
168_gtk_cell_area_box_context_init (GtkCellAreaBoxContext *box_context)
169{
170 GtkCellAreaBoxContextPrivate *priv;
171
172 box_context->priv = _gtk_cell_area_box_context_get_instance_private (self: box_context);
173 priv = box_context->priv;
174
175 priv->base_widths = g_array_new (FALSE, TRUE, element_size: sizeof (CachedSize));
176 priv->base_heights = g_array_new (FALSE, TRUE, element_size: sizeof (CachedSize));
177
178 priv->widths = g_hash_table_new_full (hash_func: g_direct_hash, key_equal_func: g_direct_equal,
179 NULL, value_destroy_func: (GDestroyNotify)free_cache_array);
180 priv->heights = g_hash_table_new_full (hash_func: g_direct_hash, key_equal_func: g_direct_equal,
181 NULL, value_destroy_func: (GDestroyNotify)free_cache_array);
182}
183
184static void
185_gtk_cell_area_box_context_class_init (GtkCellAreaBoxContextClass *class)
186{
187 GObjectClass *object_class = G_OBJECT_CLASS (class);
188 GtkCellAreaContextClass *context_class = GTK_CELL_AREA_CONTEXT_CLASS (class);
189
190 /* GObjectClass */
191 object_class->finalize = _gtk_cell_area_box_context_finalize;
192
193 context_class->reset = _gtk_cell_area_box_context_reset;
194 context_class->get_preferred_height_for_width = _gtk_cell_area_box_context_get_preferred_height_for_width;
195 context_class->get_preferred_width_for_height = _gtk_cell_area_box_context_get_preferred_width_for_height;
196}
197
198/*************************************************************
199 * GObjectClass *
200 *************************************************************/
201static void
202_gtk_cell_area_box_context_finalize (GObject *object)
203{
204 GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (object);
205 GtkCellAreaBoxContextPrivate *priv = box_context->priv;
206
207 g_array_free (array: priv->base_widths, TRUE);
208 g_array_free (array: priv->base_heights, TRUE);
209 g_hash_table_destroy (hash_table: priv->widths);
210 g_hash_table_destroy (hash_table: priv->heights);
211
212 g_free (mem: priv->expand);
213 g_free (mem: priv->align);
214
215 G_OBJECT_CLASS (_gtk_cell_area_box_context_parent_class)->finalize (object);
216}
217
218/*************************************************************
219 * GtkCellAreaContextClass *
220 *************************************************************/
221static void
222_gtk_cell_area_box_context_reset (GtkCellAreaContext *context)
223{
224 GtkCellAreaBoxContext *box_context = GTK_CELL_AREA_BOX_CONTEXT (context);
225 GtkCellAreaBoxContextPrivate *priv = box_context->priv;
226 CachedSize *size;
227 int i;
228
229 for (i = 0; i < priv->base_widths->len; i++)
230 {
231 size = &g_array_index (priv->base_widths, CachedSize, i);
232
233 size->min_size = 0;
234 size->nat_size = 0;
235
236 size = &g_array_index (priv->base_heights, CachedSize, i);
237
238 size->min_size = 0;
239 size->nat_size = 0;
240 }
241
242 /* Reset context sizes as well */
243 g_hash_table_remove_all (hash_table: priv->widths);
244 g_hash_table_remove_all (hash_table: priv->heights);
245
246 GTK_CELL_AREA_CONTEXT_CLASS
247 (_gtk_cell_area_box_context_parent_class)->reset (context);
248}
249
250static void
251_gtk_cell_area_box_context_sum (GtkCellAreaBoxContext *context,
252 GtkOrientation orientation,
253 int for_size,
254 int *minimum_size,
255 int *natural_size)
256{
257 GtkCellAreaBoxContextPrivate *priv = context->priv;
258 GtkCellAreaBox *area;
259 GtkOrientation box_orientation;
260 GArray *array;
261 int spacing, i, last_aligned_group_idx;
262 int min_size = 0, nat_size = 0;
263
264 area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (context));
265 spacing = gtk_cell_area_box_get_spacing (box: area);
266 box_orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
267 array = get_array (context, orientation, for_size);
268
269 /* Get the last visible aligned group
270 * (we need to get space at least up till this group) */
271 for (i = array->len - 1; i >= 0; i--)
272 {
273 if (priv->align[i] &&
274 _gtk_cell_area_box_group_visible (box: area, group_idx: i))
275 break;
276 }
277 last_aligned_group_idx = i >= 0 ? i : 0;
278
279 for (i = 0; i < array->len; i++)
280 {
281 CachedSize *size = &g_array_index (array, CachedSize, i);
282
283 if (box_orientation == orientation)
284 {
285 if (i > last_aligned_group_idx &&
286 !_gtk_cell_area_box_group_visible (box: area, group_idx: i))
287 continue;
288
289 /* Dont add spacing for 0 size groups, they can be 0 size because
290 * they contain only invisible cells for this round of requests
291 */
292 if (min_size > 0 && size->nat_size > 0)
293 {
294 min_size += spacing;
295 nat_size += spacing;
296 }
297
298 min_size += size->min_size;
299 nat_size += size->nat_size;
300 }
301 else
302 {
303 min_size = MAX (min_size, size->min_size);
304 nat_size = MAX (nat_size, size->nat_size);
305 }
306 }
307
308 if (for_size < 0)
309 {
310 if (orientation == GTK_ORIENTATION_HORIZONTAL)
311 gtk_cell_area_context_push_preferred_width (GTK_CELL_AREA_CONTEXT (context), minimum_width: min_size, natural_width: nat_size);
312 else
313 gtk_cell_area_context_push_preferred_height (GTK_CELL_AREA_CONTEXT (context), minimum_height: min_size, natural_height: nat_size);
314 }
315
316 if (minimum_size)
317 *minimum_size = min_size;
318 if (natural_size)
319 *natural_size = nat_size;
320}
321
322static void
323_gtk_cell_area_box_context_get_preferred_height_for_width (GtkCellAreaContext *context,
324 int width,
325 int *minimum_height,
326 int *natural_height)
327{
328 _gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), orientation: GTK_ORIENTATION_VERTICAL,
329 for_size: width, minimum_size: minimum_height, natural_size: natural_height);
330}
331
332static void
333_gtk_cell_area_box_context_get_preferred_width_for_height (GtkCellAreaContext *context,
334 int height,
335 int *minimum_width,
336 int *natural_width)
337{
338 _gtk_cell_area_box_context_sum (GTK_CELL_AREA_BOX_CONTEXT (context), orientation: GTK_ORIENTATION_HORIZONTAL,
339 for_size: height, minimum_size: minimum_width, natural_size: natural_width);
340}
341
342/*************************************************************
343 * API *
344 *************************************************************/
345static void
346copy_size_array (GArray *src_array,
347 GArray *dest_array)
348{
349 int i;
350
351 for (i = 0; i < src_array->len; i++)
352 {
353 CachedSize *src = &g_array_index (src_array, CachedSize, i);
354 CachedSize *dest = &g_array_index (dest_array, CachedSize, i);
355
356 memcpy (dest: dest, src: src, n: sizeof (CachedSize));
357 }
358}
359
360static void
361for_size_copy (gpointer key,
362 GArray *size_array,
363 GHashTable *dest_hash)
364{
365 GArray *new_array;
366
367 new_array = g_array_new (FALSE, TRUE, element_size: sizeof (CachedSize));
368 g_array_set_size (array: new_array, length: size_array->len);
369
370 copy_size_array (src_array: size_array, dest_array: new_array);
371
372 g_hash_table_insert (hash_table: dest_hash, key, value: new_array);
373}
374
375GtkCellAreaBoxContext *
376_gtk_cell_area_box_context_copy (GtkCellAreaBox *box,
377 GtkCellAreaBoxContext *context)
378{
379 GtkCellAreaBoxContext *copy;
380
381 copy = g_object_new (GTK_TYPE_CELL_AREA_BOX_CONTEXT,
382 first_property_name: "area", box, NULL);
383
384 _gtk_cell_area_box_init_groups (box_context: copy,
385 n_groups: context->priv->base_widths->len,
386 expand_groups: context->priv->expand,
387 align_groups: context->priv->align);
388
389 /* Copy the base arrays */
390 copy_size_array (src_array: context->priv->base_widths,
391 dest_array: copy->priv->base_widths);
392 copy_size_array (src_array: context->priv->base_heights,
393 dest_array: copy->priv->base_heights);
394
395 /* Copy each for size */
396 g_hash_table_foreach (hash_table: context->priv->heights,
397 func: (GHFunc)for_size_copy, user_data: copy->priv->heights);
398 g_hash_table_foreach (hash_table: context->priv->widths,
399 func: (GHFunc)for_size_copy, user_data: copy->priv->widths);
400
401
402 return copy;
403}
404
405void
406_gtk_cell_area_box_init_groups (GtkCellAreaBoxContext *box_context,
407 guint n_groups,
408 gboolean *expand_groups,
409 gboolean *align_groups)
410{
411 GtkCellAreaBoxContextPrivate *priv;
412 gsize groups_size;
413
414 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
415 g_return_if_fail (n_groups == 0 || expand_groups != NULL);
416
417 /* When the group dimensions change, all info must be reset
418 * Note this already clears the min/nat values on the CachedSizes
419 */
420 gtk_cell_area_context_reset (GTK_CELL_AREA_CONTEXT (box_context));
421
422 priv = box_context->priv;
423 g_array_set_size (array: priv->base_widths, length: n_groups);
424 g_array_set_size (array: priv->base_heights, length: n_groups);
425
426 groups_size = n_groups * sizeof (gboolean);
427
428 g_free (mem: priv->expand);
429 priv->expand = g_memdup2 (mem: expand_groups, byte_size: groups_size);
430
431 g_free (mem: priv->align);
432 priv->align = g_memdup2 (mem: align_groups, byte_size: groups_size);
433}
434
435void
436_gtk_cell_area_box_context_push_group_width (GtkCellAreaBoxContext *box_context,
437 int group_idx,
438 int minimum_width,
439 int natural_width)
440{
441 GtkCellAreaBoxContextPrivate *priv;
442 CachedSize *size;
443 gboolean grew = FALSE;
444
445 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
446
447 priv = box_context->priv;
448 g_return_if_fail (group_idx < priv->base_widths->len);
449
450 size = &g_array_index (priv->base_widths, CachedSize, group_idx);
451 if (minimum_width > size->min_size)
452 {
453 size->min_size = minimum_width;
454 grew = TRUE;
455 }
456 if (natural_width > size->nat_size)
457 {
458 size->nat_size = natural_width;
459 grew = TRUE;
460 }
461
462 if (grew)
463 _gtk_cell_area_box_context_sum (context: box_context, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, NULL, NULL);
464}
465
466void
467_gtk_cell_area_box_context_push_group_height_for_width (GtkCellAreaBoxContext *box_context,
468 int group_idx,
469 int for_width,
470 int minimum_height,
471 int natural_height)
472{
473 GtkCellAreaBoxContextPrivate *priv;
474 GArray *group_array;
475 CachedSize *size;
476
477 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
478
479 priv = box_context->priv;
480 g_return_if_fail (group_idx < priv->base_widths->len);
481
482 group_array = g_hash_table_lookup (hash_table: priv->heights, GINT_TO_POINTER (for_width));
483 if (!group_array)
484 {
485 group_array = group_array_new (context: box_context);
486 g_hash_table_insert (hash_table: priv->heights, GINT_TO_POINTER (for_width), value: group_array);
487 }
488
489 size = &g_array_index (group_array, CachedSize, group_idx);
490 size->min_size = MAX (size->min_size, minimum_height);
491 size->nat_size = MAX (size->nat_size, natural_height);
492}
493
494void
495_gtk_cell_area_box_context_push_group_height (GtkCellAreaBoxContext *box_context,
496 int group_idx,
497 int minimum_height,
498 int natural_height)
499{
500 GtkCellAreaBoxContextPrivate *priv;
501 CachedSize *size;
502 gboolean grew = FALSE;
503
504 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
505
506 priv = box_context->priv;
507 g_return_if_fail (group_idx < priv->base_heights->len);
508
509 size = &g_array_index (priv->base_heights, CachedSize, group_idx);
510 if (minimum_height > size->min_size)
511 {
512 size->min_size = minimum_height;
513 grew = TRUE;
514 }
515 if (natural_height > size->nat_size)
516 {
517 size->nat_size = natural_height;
518 grew = TRUE;
519 }
520
521 if (grew)
522 _gtk_cell_area_box_context_sum (context: box_context, orientation: GTK_ORIENTATION_VERTICAL, for_size: -1, NULL, NULL);
523}
524
525void
526_gtk_cell_area_box_context_push_group_width_for_height (GtkCellAreaBoxContext *box_context,
527 int group_idx,
528 int for_height,
529 int minimum_width,
530 int natural_width)
531{
532 GtkCellAreaBoxContextPrivate *priv;
533 GArray *group_array;
534 CachedSize *size;
535
536 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
537
538 priv = box_context->priv;
539 g_return_if_fail (group_idx < priv->base_widths->len);
540
541 group_array = g_hash_table_lookup (hash_table: priv->widths, GINT_TO_POINTER (for_height));
542 if (!group_array)
543 {
544 group_array = group_array_new (context: box_context);
545 g_hash_table_insert (hash_table: priv->widths, GINT_TO_POINTER (for_height), value: group_array);
546 }
547
548 size = &g_array_index (group_array, CachedSize, group_idx);
549 size->min_size = MAX (size->min_size, minimum_width);
550 size->nat_size = MAX (size->nat_size, natural_width);
551}
552
553void
554_gtk_cell_area_box_context_get_group_width (GtkCellAreaBoxContext *box_context,
555 int group_idx,
556 int *minimum_width,
557 int *natural_width)
558{
559 GtkCellAreaBoxContextPrivate *priv;
560 CachedSize *size;
561
562 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
563
564 priv = box_context->priv;
565 g_return_if_fail (group_idx < priv->base_widths->len);
566
567 size = &g_array_index (priv->base_widths, CachedSize, group_idx);
568
569 if (minimum_width)
570 *minimum_width = size->min_size;
571
572 if (natural_width)
573 *natural_width = size->nat_size;
574}
575
576void
577_gtk_cell_area_box_context_get_group_height_for_width (GtkCellAreaBoxContext *box_context,
578 int group_idx,
579 int for_width,
580 int *minimum_height,
581 int *natural_height)
582{
583 GtkCellAreaBoxContextPrivate *priv;
584 GArray *group_array;
585
586 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
587
588 priv = box_context->priv;
589 g_return_if_fail (group_idx < priv->base_widths->len);
590
591 group_array = g_hash_table_lookup (hash_table: priv->heights, GINT_TO_POINTER (for_width));
592
593 if (group_array)
594 {
595 CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
596
597 if (minimum_height)
598 *minimum_height = size->min_size;
599
600 if (natural_height)
601 *natural_height = size->nat_size;
602 }
603 else
604 {
605 if (minimum_height)
606 *minimum_height = -1;
607
608 if (natural_height)
609 *natural_height = -1;
610 }
611}
612
613void
614_gtk_cell_area_box_context_get_group_height (GtkCellAreaBoxContext *box_context,
615 int group_idx,
616 int *minimum_height,
617 int *natural_height)
618{
619 GtkCellAreaBoxContextPrivate *priv;
620 CachedSize *size;
621
622 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
623
624 priv = box_context->priv;
625 g_return_if_fail (group_idx < priv->base_heights->len);
626
627 size = &g_array_index (priv->base_heights, CachedSize, group_idx);
628
629 if (minimum_height)
630 *minimum_height = size->min_size;
631
632 if (natural_height)
633 *natural_height = size->nat_size;
634}
635
636void
637_gtk_cell_area_box_context_get_group_width_for_height (GtkCellAreaBoxContext *box_context,
638 int group_idx,
639 int for_height,
640 int *minimum_width,
641 int *natural_width)
642{
643 GtkCellAreaBoxContextPrivate *priv;
644 GArray *group_array;
645
646 g_return_if_fail (GTK_IS_CELL_AREA_BOX_CONTEXT (box_context));
647
648 priv = box_context->priv;
649 g_return_if_fail (group_idx < priv->base_widths->len);
650
651 group_array = g_hash_table_lookup (hash_table: priv->widths, GINT_TO_POINTER (for_height));
652
653 if (group_array)
654 {
655 CachedSize *size = &g_array_index (group_array, CachedSize, group_idx);
656
657 if (minimum_width)
658 *minimum_width = size->min_size;
659
660 if (natural_width)
661 *natural_width = size->nat_size;
662 }
663 else
664 {
665 if (minimum_width)
666 *minimum_width = -1;
667
668 if (natural_width)
669 *natural_width = -1;
670 }
671}
672
673static GtkRequestedSize *
674_gtk_cell_area_box_context_get_requests (GtkCellAreaBoxContext *box_context,
675 GtkCellAreaBox *area,
676 GtkOrientation orientation,
677 int for_size,
678 int *n_requests)
679{
680 GtkCellAreaBoxContextPrivate *priv = box_context->priv;
681 GtkRequestedSize *requests;
682 GArray *array;
683 CachedSize *size;
684 int visible_groups = 0;
685 int last_aligned_group_idx = 0;
686 int i, j;
687
688 /* Get the last visible aligned group
689 * (we need to get space at least up till this group) */
690 for (i = priv->base_widths->len - 1; i >= 0; i--)
691 {
692 if (priv->align[i] &&
693 _gtk_cell_area_box_group_visible (box: area, group_idx: i))
694 break;
695 }
696 last_aligned_group_idx = i >= 0 ? i : 0;
697
698 priv = box_context->priv;
699 array = get_array (context: box_context, orientation, for_size);
700
701 for (i = 0; i < array->len; i++)
702 {
703 size = &g_array_index (array, CachedSize, i);
704
705 if (size->nat_size > 0 &&
706 (i <= last_aligned_group_idx ||
707 _gtk_cell_area_box_group_visible (box: area, group_idx: i)))
708 visible_groups++;
709 }
710
711 requests = g_new (GtkRequestedSize, visible_groups);
712
713 for (j = 0, i = 0; i < array->len; i++)
714 {
715 size = &g_array_index (array, CachedSize, i);
716
717 if (size->nat_size > 0 &&
718 (i <= last_aligned_group_idx ||
719 _gtk_cell_area_box_group_visible (box: area, group_idx: i)))
720 {
721 requests[j].data = GINT_TO_POINTER (i);
722 requests[j].minimum_size = size->min_size;
723 requests[j].natural_size = size->nat_size;
724 j++;
725 }
726 }
727
728 if (n_requests)
729 *n_requests = visible_groups;
730
731 return requests;
732}
733
734static GtkCellAreaBoxAllocation *
735allocate_for_orientation (GtkCellAreaBoxContext *context,
736 GtkCellAreaBox *area,
737 GtkOrientation orientation,
738 int spacing,
739 int size,
740 int for_size,
741 int *n_allocs)
742{
743 GtkCellAreaBoxContextPrivate *priv = context->priv;
744 GtkCellAreaBoxAllocation *allocs;
745 GtkRequestedSize *sizes;
746 int n_expand_groups = 0;
747 int i, n_groups, position, vis_position;
748 int extra_size, extra_extra;
749 int avail_size = size;
750
751 sizes = _gtk_cell_area_box_context_get_requests (box_context: context, area, orientation, for_size, n_requests: &n_groups);
752 n_expand_groups = count_expand_groups (context);
753
754 /* First start by naturally allocating space among groups */
755 avail_size -= (n_groups - 1) * spacing;
756 for (i = 0; i < n_groups; i++)
757 avail_size -= sizes[i].minimum_size;
758
759 if (avail_size > 0)
760 avail_size = gtk_distribute_natural_allocation (extra_space: avail_size, n_requested_sizes: n_groups, sizes);
761 else
762 avail_size = 0;
763
764 /* Calculate/distribute expand for groups */
765 if (n_expand_groups > 0)
766 {
767 extra_size = avail_size / n_expand_groups;
768 extra_extra = avail_size % n_expand_groups;
769 }
770 else
771 extra_size = extra_extra = 0;
772
773 allocs = g_new (GtkCellAreaBoxAllocation, n_groups);
774
775 for (vis_position = 0, position = 0, i = 0; i < n_groups; i++)
776 {
777 allocs[i].group_idx = GPOINTER_TO_INT (sizes[i].data);
778
779 if (priv->align[allocs[i].group_idx])
780 vis_position = position;
781
782 allocs[i].position = vis_position;
783 allocs[i].size = sizes[i].minimum_size;
784
785 if (group_expands (context, group_idx: allocs[i].group_idx))
786 {
787 allocs[i].size += extra_size;
788 if (extra_extra)
789 {
790 allocs[i].size++;
791 extra_extra--;
792 }
793 }
794
795 position += allocs[i].size;
796 position += spacing;
797
798 if (_gtk_cell_area_box_group_visible (box: area, group_idx: allocs[i].group_idx))
799 {
800 vis_position += allocs[i].size;
801 vis_position += spacing;
802 }
803 }
804
805 if (n_allocs)
806 *n_allocs = n_groups;
807
808 g_free (mem: sizes);
809
810 return allocs;
811}
812
813GtkRequestedSize *
814_gtk_cell_area_box_context_get_widths (GtkCellAreaBoxContext *box_context,
815 int *n_widths)
816{
817 GtkCellAreaBox *area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (box_context));
818
819 return _gtk_cell_area_box_context_get_requests (box_context, area, orientation: GTK_ORIENTATION_HORIZONTAL, for_size: -1, n_requests: n_widths);
820}
821
822GtkRequestedSize *
823_gtk_cell_area_box_context_get_heights (GtkCellAreaBoxContext *box_context,
824 int *n_heights)
825{
826 GtkCellAreaBox *area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (GTK_CELL_AREA_CONTEXT (box_context));
827
828 return _gtk_cell_area_box_context_get_requests (box_context, area, orientation: GTK_ORIENTATION_VERTICAL, for_size: -1, n_requests: n_heights);
829}
830
831GtkCellAreaBoxAllocation *
832_gtk_cell_area_box_context_get_orientation_allocs (GtkCellAreaBoxContext *context,
833 int *n_allocs)
834{
835 GtkCellAreaContext *ctx = GTK_CELL_AREA_CONTEXT (context);
836 GtkCellAreaBox *area;
837 GtkOrientation orientation;
838 int spacing, width, height, alloc_count = 0;
839 GtkCellAreaBoxAllocation *allocs = NULL;
840
841 area = (GtkCellAreaBox *)gtk_cell_area_context_get_area (context: ctx);
842 orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (area));
843 spacing = gtk_cell_area_box_get_spacing (box: area);
844
845 gtk_cell_area_context_get_allocation (context: ctx, width: &width, height: &height);
846
847 if (orientation == GTK_ORIENTATION_HORIZONTAL && width > 0)
848 allocs = allocate_for_orientation (context, area, orientation,
849 spacing, size: width, for_size: height,
850 n_allocs: &alloc_count);
851 else if (orientation == GTK_ORIENTATION_VERTICAL && height > 0)
852 allocs = allocate_for_orientation (context, area, orientation,
853 spacing, size: height, for_size: width,
854 n_allocs: &alloc_count);
855
856 *n_allocs = alloc_count;
857
858 return allocs;
859}
860

source code of gtk/gtk/gtkcellareaboxcontext.c