aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/canvas/evas_object_table.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/lib/canvas/evas_object_table.c1373
1 files changed, 1373 insertions, 0 deletions
diff --git a/libraries/evas/src/lib/canvas/evas_object_table.c b/libraries/evas/src/lib/canvas/evas_object_table.c
new file mode 100644
index 0000000..6e28fce
--- /dev/null
+++ b/libraries/evas/src/lib/canvas/evas_object_table.c
@@ -0,0 +1,1373 @@
1#include <errno.h>
2#include "evas_common.h"
3
4typedef struct _Evas_Object_Table_Data Evas_Object_Table_Data;
5typedef struct _Evas_Object_Table_Option Evas_Object_Table_Option;
6typedef struct _Evas_Object_Table_Cache Evas_Object_Table_Cache;
7typedef struct _Evas_Object_Table_Iterator Evas_Object_Table_Iterator;
8typedef struct _Evas_Object_Table_Accessor Evas_Object_Table_Accessor;
9
10struct _Evas_Object_Table_Option
11{
12 Evas_Object *obj;
13 unsigned short col, row, colspan, rowspan, end_col, end_row;
14 struct {
15 Evas_Coord w, h;
16 } min, max;
17 struct {
18 double h, v;
19 } align;
20 struct {
21 Evas_Coord l, r, t, b;
22 } pad;
23 Eina_Bool expand_h : 1; /* XXX required? */
24 Eina_Bool expand_v : 1; /* XXX required? */
25 Eina_Bool fill_h : 1;
26 Eina_Bool fill_v : 1;
27};
28
29struct _Evas_Object_Table_Cache
30{
31 struct {
32 struct {
33 double h, v;
34 } weights;
35 struct {
36 int h, v;
37 } expands;
38 struct {
39 Evas_Coord w, h;
40 } min;
41 } total;
42 struct {
43 double *h, *v;
44 } weights;
45 struct {
46 Evas_Coord *h, *v;
47 } sizes;
48 struct {
49 Eina_Bool *h, *v;
50 } expands;
51 double ___pad; // padding to make sure doubles at end can be aligned
52};
53
54struct _Evas_Object_Table_Data
55{
56 Evas_Object_Smart_Clipped_Data base;
57 Eina_List *children;
58 struct {
59 Evas_Coord h, v;
60 } pad;
61 struct {
62 double h, v;
63 } align;
64 struct {
65 int cols, rows;
66 } size;
67 Evas_Object_Table_Cache *cache;
68 Evas_Object_Table_Homogeneous_Mode homogeneous;
69 Eina_Bool hints_changed : 1;
70 Eina_Bool expand_h : 1;
71 Eina_Bool expand_v : 1;
72 Eina_Bool is_mirrored : 1;
73};
74
75struct _Evas_Object_Table_Iterator
76{
77 Eina_Iterator iterator;
78
79 Eina_Iterator *real_iterator;
80 const Evas_Object *table;
81};
82
83struct _Evas_Object_Table_Accessor
84{
85 Eina_Accessor accessor;
86
87 Eina_Accessor *real_accessor;
88 const Evas_Object *table;
89};
90
91#define EVAS_OBJECT_TABLE_DATA_GET(o, ptr) \
92 Evas_Object_Table_Data *ptr = evas_object_smart_data_get(o)
93
94#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, ptr) \
95 EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
96 if (!ptr) \
97 { \
98 CRIT("no widget data for object %p (%s)", \
99 o, evas_object_type_get(o)); \
100 abort(); \
101 return; \
102}
103
104#define EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
105 EVAS_OBJECT_TABLE_DATA_GET(o, ptr); \
106 if (!ptr) \
107 { \
108 CRIT("No widget data for object %p (%s)", \
109 o, evas_object_type_get(o)); \
110 abort(); \
111 return val; \
112 }
113
114static const char EVAS_OBJECT_TABLE_OPTION_KEY[] = "|EvTb";
115
116static Eina_Bool
117_evas_object_table_iterator_next(Evas_Object_Table_Iterator *it, void **data)
118{
119 Evas_Object_Table_Option *opt;
120
121 if (!eina_iterator_next(it->real_iterator, (void **)&opt))
122 return EINA_FALSE;
123 if (data) *data = opt->obj;
124 return EINA_TRUE;
125}
126
127static Evas_Object *
128_evas_object_table_iterator_get_container(Evas_Object_Table_Iterator *it)
129{
130 return (Evas_Object *)it->table;
131}
132
133static void
134_evas_object_table_iterator_free(Evas_Object_Table_Iterator *it)
135{
136 eina_iterator_free(it->real_iterator);
137 free(it);
138}
139
140static Eina_Bool
141_evas_object_table_accessor_get_at(Evas_Object_Table_Accessor *it, unsigned int idx, void **data)
142{
143 Evas_Object_Table_Option *opt = NULL;
144
145 if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt))
146 return EINA_FALSE;
147 if (data) *data = opt->obj;
148 return EINA_TRUE;
149}
150
151static Evas_Object *
152_evas_object_table_accessor_get_container(Evas_Object_Table_Accessor *it)
153{
154 return (Evas_Object *)it->table;
155}
156
157static void
158_evas_object_table_accessor_free(Evas_Object_Table_Accessor *it)
159{
160 eina_accessor_free(it->real_accessor);
161 free(it);
162}
163
164static Evas_Object_Table_Cache *
165_evas_object_table_cache_alloc(int cols, int rows)
166{
167 Evas_Object_Table_Cache *cache;
168 int size;
169
170 size = sizeof(Evas_Object_Table_Cache) +
171 ((cols + rows) *
172 (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool)));
173 cache = malloc(size);
174 if (!cache)
175 {
176 ERR("Could not allocate table cache %dx%d (%d bytes): %s",
177 cols, rows, size, strerror(errno));
178 return NULL;
179 }
180
181 cache->weights.h = (double *)(cache + 1);
182 cache->weights.v = (double *)(cache->weights.h + cols);
183 cache->sizes.h = (Evas_Coord *)(cache->weights.v + rows);
184 cache->sizes.v = (Evas_Coord *)(cache->sizes.h + cols);
185 cache->expands.h = (Eina_Bool *)(cache->sizes.v + rows);
186 cache->expands.v = (Eina_Bool *)(cache->expands.h + cols);
187
188 return cache;
189}
190
191static void
192_evas_object_table_cache_free(Evas_Object_Table_Cache *cache)
193{
194 free(cache);
195}
196
197static void
198_evas_object_table_cache_reset(Evas_Object_Table_Data *priv)
199{
200 Evas_Object_Table_Cache *c = priv->cache;
201 int size;
202
203 c->total.expands.v = 0;
204 c->total.expands.h = 0;
205 c->total.min.w = 0;
206 c->total.min.h = 0;
207
208 size = ((priv->size.rows + priv->size.cols) *
209 (sizeof(double) + sizeof(Evas_Coord) + sizeof(Eina_Bool)));
210 memset(c + 1, 0, size);
211}
212
213static void
214_evas_object_table_cache_invalidate(Evas_Object_Table_Data *priv)
215{
216 priv->hints_changed = 1;
217 if (priv->cache)
218 {
219 _evas_object_table_cache_free(priv->cache);
220 priv->cache = NULL;
221 }
222}
223
224static Evas_Object_Table_Option *
225_evas_object_table_option_get(Evas_Object *o)
226{
227 return evas_object_data_get(o, EVAS_OBJECT_TABLE_OPTION_KEY);
228}
229
230static void
231_evas_object_table_option_set(Evas_Object *o, const Evas_Object_Table_Option *opt)
232{
233 evas_object_data_set(o, EVAS_OBJECT_TABLE_OPTION_KEY, opt);
234}
235
236static Evas_Object_Table_Option *
237_evas_object_table_option_del(Evas_Object *o)
238{
239 return evas_object_data_del(o, EVAS_OBJECT_TABLE_OPTION_KEY);
240}
241
242static void
243_on_child_del(void *data, Evas *evas __UNUSED__, Evas_Object *child, void *einfo __UNUSED__)
244{
245 Evas_Object *table = data;
246 evas_object_table_unpack(table, child);
247}
248
249static void
250_on_child_hints_changed(void *data, Evas *evas __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
251{
252 Evas_Object *table = data;
253 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(table, priv);
254 _evas_object_table_cache_invalidate(priv);
255 evas_object_smart_changed(table);
256}
257
258static void
259_evas_object_table_child_connect(Evas_Object *o, Evas_Object *child)
260{
261 evas_object_event_callback_add
262 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
263 evas_object_event_callback_add
264 (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
265}
266
267static void
268_evas_object_table_child_disconnect(Evas_Object *o, Evas_Object *child)
269{
270 evas_object_event_callback_del_full
271 (child, EVAS_CALLBACK_DEL, _on_child_del, o);
272 evas_object_event_callback_del_full
273 (child, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_child_hints_changed, o);
274}
275
276static void
277_evas_object_table_calculate_cell(const Evas_Object_Table_Option *opt, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
278{
279 Evas_Coord cw, ch;
280
281 *w -= opt->pad.l + opt->pad.r;
282 if (*w < opt->min.w)
283 cw = opt->min.w;
284 else if ((opt->max.w > -1) && (*w > opt->max.w))
285 cw = opt->max.w;
286 else if (opt->fill_h)
287 cw = *w;
288 else
289 cw = opt->min.w;
290
291 *h -= opt->pad.t + opt->pad.b;
292 if (*h < opt->min.h)
293 ch = opt->min.h;
294 else if ((opt->max.h > -1) && (*h > opt->max.h))
295 ch = opt->max.h;
296 else if (opt->fill_v)
297 ch = *h;
298 else
299 ch = opt->min.h;
300
301 *x += opt->pad.l;
302 if (cw != *w)
303 {
304 *x += (*w - cw) * opt->align.h;
305 *w = cw;
306 }
307
308 *y += opt->pad.t;
309 if (ch != *h)
310 {
311 *y += (*h - ch) * opt->align.v;
312 *h = ch;
313 }
314}
315
316static void
317_evas_object_table_calculate_hints_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
318{
319 Eina_List *l;
320 Evas_Object_Table_Option *opt;
321 Evas_Coord minw, minh, o_minw, o_minh;
322 Eina_Bool expand_h, expand_v;
323
324 o_minw = 0;
325 o_minh = 0;
326 minw = 0;
327 minh = 0;
328 expand_h = 0;
329 expand_v = 0;
330
331 EINA_LIST_FOREACH(priv->children, l, opt)
332 {
333 Evas_Object *child = opt->obj;
334 Evas_Coord child_minw, child_minh, cell_minw, cell_minh;
335 double weightw, weighth;
336
337 evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h);
338 evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h);
339 evas_object_size_hint_padding_get
340 (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b);
341 evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v);
342 evas_object_size_hint_weight_get(child, &weightw, &weighth);
343
344 child_minw = opt->min.w + opt->pad.l + opt->pad.r;
345 child_minh = opt->min.h + opt->pad.t + opt->pad.b;
346
347 cell_minw = (child_minw + opt->colspan - 1) / opt->colspan;
348 cell_minh = (child_minh + opt->rowspan - 1) / opt->rowspan;
349
350 opt->expand_h = 0;
351 if ((weightw > 0.0) &&
352 ((opt->max.w < 0) ||
353 ((opt->max.w > -1) && (opt->min.w < opt->max.w))))
354 {
355 opt->expand_h = 1;
356 expand_h = 1;
357 }
358
359 opt->expand_v = 0;
360 if ((weighth > 0.0) &&
361 ((opt->max.h < 0) ||
362 ((opt->max.h > -1) && (opt->min.h < opt->max.h))))
363 {
364 opt->expand_v = 1;
365 expand_v = 1;
366 }
367
368 opt->fill_h = 0;
369 if (opt->align.h < 0.0)
370 {
371 opt->align.h = 0.5;
372 opt->fill_h = 1;
373 }
374 opt->fill_v = 0;
375 if (opt->align.v < 0.0)
376 {
377 opt->align.v = 0.5;
378 opt->fill_v = 1;
379 }
380
381 /* greatest mininum values, with paddings */
382 if (minw < cell_minw)
383 minw = cell_minw;
384 if (minh < cell_minh)
385 minh = cell_minh;
386 /* greatest mininum values, without paddings */
387 if (o_minw < opt->min.w)
388 o_minw = opt->min.w;
389 if (o_minh < opt->min.h)
390 o_minh = opt->min.h;
391 }
392
393 if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
394 {
395 if (o_minw < 1)
396 {
397 ERR("homogeneous table based on item size but no "
398 "horizontal mininum size specified! Using expand.");
399 expand_h = 1;
400 }
401 if (o_minh < 1)
402 {
403 ERR("homogeneous table based on item size but no "
404 "vertical mininum size specified! Using expand.");
405 expand_v = 1;
406 }
407 }
408
409 minw = priv->size.cols * (minw + priv->pad.h) - priv->pad.h;
410 minh = priv->size.rows * (minh + priv->pad.v) - priv->pad.v;
411
412 priv->hints_changed = 0;
413 priv->expand_h = expand_h;
414 priv->expand_v = expand_v;
415
416 if ((minw > 0 ) || (minh > 0))
417 evas_object_size_hint_min_set(o, minw, minh);
418
419 // XXX hint max?
420}
421
422static void
423_evas_object_table_calculate_layout_homogeneous_sizes_item(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
424{
425 Evas_Coord minw, minh;
426 Eina_Bool expand_h, expand_v;
427
428 evas_object_size_hint_min_get(o, &minw, &minh);
429 expand_h = priv->expand_h;
430 expand_v = priv->expand_v;
431
432 if (*w < minw)
433 expand_h = 0;
434 if (!expand_h)
435 {
436 *x += (*w - minw) * priv->align.h;
437 *w = minw;
438 }
439
440 if (*h < minh)
441 expand_v = 0;
442 if (!expand_v)
443 {
444 *y += (*h - minh) * priv->align.v;
445 *h = minh;
446 }
447}
448
449static void
450_evas_object_table_calculate_layout_homogeneous_sizes(const Evas_Object *o, const Evas_Object_Table_Data *priv, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h, Evas_Coord *cellw, Evas_Coord *cellh)
451{
452 evas_object_geometry_get(o, x, y, w, h);
453 if (priv->homogeneous == EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM)
454 _evas_object_table_calculate_layout_homogeneous_sizes_item
455 (o, priv, x, y, w, h);
456
457 *cellw = (*w + priv->size.cols - 1) / priv->size.cols;
458 *cellh = (*h + priv->size.rows - 1) / priv->size.rows;
459}
460
461static void
462_evas_object_table_calculate_layout_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
463{
464 Evas_Coord x = 0, y = 0, w = 0, h = 0, ww, hh, cellw = 0, cellh = 0;
465 Eina_List *l;
466 Evas_Object_Table_Option *opt;
467
468 _evas_object_table_calculate_layout_homogeneous_sizes
469 (o, priv, &x, &y, &w, &h, &cellw, &cellh);
470
471 ww = w - ((priv->size.cols - 1) * priv->pad.h);
472 hh = h - ((priv->size.rows - 1) * priv->pad.v);
473
474 if (ww < 0) ww = 0;
475 if (ww < 0) ww = 0;
476
477 EINA_LIST_FOREACH(priv->children, l, opt)
478 {
479 Evas_Object *child = opt->obj;
480 Evas_Coord cx, cy, cw, ch, cox, coy, cow, coh;
481
482 cx = x + ((opt->col * ww) / priv->size.cols);
483 cw = x + (((opt->col + opt->colspan) * ww) / priv->size.cols) - cx;
484 cy = y + ((opt->row * hh) / priv->size.rows);
485 ch = y + (((opt->row + opt->rowspan) * hh) / priv->size.rows) - cy;
486
487 cx += (opt->col) * priv->pad.h;
488 cy += (opt->row) * priv->pad.v;
489
490 cox = cx;
491 coy = cy;
492 cow = cw;
493 coh = ch;
494
495 _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch);
496 if (cw > cow)
497 {
498 cx = cox;
499 cw = cow;
500 }
501 if (ch > coh)
502 {
503 cy = coy;
504 ch = coh;
505 }
506
507 if (priv->is_mirrored)
508 {
509 evas_object_move(opt->obj, x + w - (cx - x + cw), cy);
510 }
511 else
512 {
513 evas_object_move(child, cx, cy);
514 }
515 evas_object_resize(child, cw, ch);
516 }
517}
518
519static void
520_evas_object_table_smart_calculate_homogeneous(Evas_Object *o, Evas_Object_Table_Data *priv)
521{
522 if (priv->hints_changed)
523 _evas_object_table_calculate_hints_homogeneous(o, priv);
524 _evas_object_table_calculate_layout_homogeneous(o, priv);
525}
526
527static int
528_evas_object_table_count_expands(const Eina_Bool *expands, int start, int end)
529{
530 const Eina_Bool *itr = expands + start, *itr_end = expands + end;
531 int count = 0;
532
533 for (; itr < itr_end; itr++)
534 {
535 if (*itr)
536 count++;
537 }
538
539 return count;
540}
541
542static Evas_Coord
543_evas_object_table_sum_sizes(const Evas_Coord *sizes, int start, int end)
544{
545 const Evas_Coord *itr = sizes + start, *itr_end = sizes + end;
546 Evas_Coord sum = 0;
547
548 for (; itr < itr_end; itr++)
549 sum += *itr;
550
551 return sum;
552}
553
554static void
555_evas_object_table_sizes_calc_noexpand(Evas_Coord *sizes, int start, int end, Evas_Coord space)
556{
557 Evas_Coord *itr = sizes + start, *itr_end = sizes + end - 1;
558 Evas_Coord step;
559 int units;
560
561 /* XXX move to fixed point math and spread errors among cells */
562 units = end - start;
563 step = space / units;
564 for (; itr < itr_end; itr++)
565 *itr += step;
566
567 *itr += space - step * (units - 1);
568}
569
570static void
571_evas_object_table_sizes_calc_expand(Evas_Coord *sizes, int start, int end, Evas_Coord space, const Eina_Bool *expands, int expand_count, double *weights, double weighttot)
572{
573 Evas_Coord *itr = sizes + start, *itr_end = sizes + end;
574 const Eina_Bool *itr_expand = expands + start;
575 Evas_Coord step = 0, last_space = 0;
576 int total = 0, i = start;
577
578 /* XXX move to fixed point math and spread errors among cells */
579 if (weighttot > 0.0)
580 {
581 step = space / expand_count;
582 last_space = space - step * (expand_count - 1);
583 }
584
585 for (; itr < itr_end; itr++, itr_expand++, i++)
586 {
587 if (weighttot <= 0.0)
588 {
589 if (*itr_expand)
590 {
591 expand_count--;
592 if (expand_count > 0)
593 *itr += step;
594 else
595 {
596 *itr += last_space;
597 break;
598 }
599 }
600 }
601 else
602 {
603 if (*itr_expand)
604 {
605 expand_count--;
606 if (expand_count > 0)
607 {
608 step = (weights[i] / weighttot) * space;
609 *itr += step;
610 total += step;
611 }
612 else
613 {
614 *itr += space - total;
615 break;
616 }
617 }
618 }
619 }
620}
621
622static void
623_evas_object_table_calculate_hints_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
624{
625 Evas_Object_Table_Option *opt;
626 Evas_Object_Table_Cache *c;
627 Eina_List *l;
628 double totweightw = 0.0, totweighth = 0.0;
629 int i;
630
631 if (!priv->cache)
632 {
633 priv->cache = _evas_object_table_cache_alloc
634 (priv->size.cols, priv->size.rows);
635 if (!priv->cache)
636 return;
637 }
638 c = priv->cache;
639 _evas_object_table_cache_reset(priv);
640
641 /* cache interesting data */
642 memset(c->expands.h, 1, priv->size.cols);
643 memset(c->expands.v, 1, priv->size.rows);
644 memset(c->weights.h, 0, priv->size.cols);
645 memset(c->weights.v, 0, priv->size.rows);
646 EINA_LIST_FOREACH(priv->children, l, opt)
647 {
648 Evas_Object *child = opt->obj;
649 double weightw, weighth;
650
651 evas_object_size_hint_min_get(child, &opt->min.w, &opt->min.h);
652 evas_object_size_hint_max_get(child, &opt->max.w, &opt->max.h);
653 evas_object_size_hint_padding_get
654 (child, &opt->pad.l, &opt->pad.r, &opt->pad.t, &opt->pad.b);
655 evas_object_size_hint_align_get(child, &opt->align.h, &opt->align.v);
656 evas_object_size_hint_weight_get(child, &weightw, &weighth);
657
658 opt->expand_h = 0;
659 if ((weightw > 0.0) &&
660 ((opt->max.w < 0) ||
661 ((opt->max.w > -1) && (opt->min.w < opt->max.w))))
662 opt->expand_h = 1;
663
664 opt->expand_v = 0;
665 if ((weighth > 0.0) &&
666 ((opt->max.h < 0) ||
667 ((opt->max.h > -1) && (opt->min.h < opt->max.h))))
668 opt->expand_v = 1;
669
670 opt->fill_h = 0;
671 if (opt->align.h < 0.0)
672 {
673 opt->align.h = 0.5;
674 opt->fill_h = 1;
675 }
676 opt->fill_v = 0;
677 if (opt->align.v < 0.0)
678 {
679 opt->align.v = 0.5;
680 opt->fill_v = 1;
681 }
682
683 if (!opt->expand_h)
684 memset(c->expands.h + opt->col, 0, opt->colspan);
685 else
686 {
687 for (i = opt->col; i < opt->col + opt->colspan; i++)
688 c->weights.h[i] += (weightw / (double)opt->colspan);
689 }
690 if (!opt->expand_v)
691 memset(c->expands.v + opt->row, 0, opt->rowspan);
692 else
693 {
694 for (i = opt->row; i < opt->row + opt->rowspan; i++)
695 c->weights.v[i] += (weighth / (double)opt->rowspan);
696 }
697 }
698 for (i = 0; i < priv->size.cols; i++) totweightw += c->weights.h[i];
699 for (i = 0; i < priv->size.rows; i++) totweighth += c->weights.v[i];
700
701 /* calculate sizes for each row and column */
702 EINA_LIST_FOREACH(priv->children, l, opt)
703 {
704 Evas_Coord tot, need;
705
706 /* handle horizontal */
707 tot = _evas_object_table_sum_sizes(c->sizes.h, opt->col, opt->end_col);
708 need = opt->min.w + opt->pad.l + opt->pad.r;
709 if (tot < need)
710 {
711 Evas_Coord space = need - tot;
712 int count;
713
714 count = _evas_object_table_count_expands
715 (c->expands.h, opt->col, opt->end_col);
716
717 if (count > 0)
718 _evas_object_table_sizes_calc_expand
719 (c->sizes.h, opt->col, opt->end_col, space,
720 c->expands.h, count, c->weights.h, totweightw);
721 else
722 _evas_object_table_sizes_calc_noexpand
723 (c->sizes.h, opt->col, opt->end_col, space);
724 }
725
726 /* handle vertical */
727 tot = _evas_object_table_sum_sizes(c->sizes.v, opt->row, opt->end_row);
728 need = opt->min.h + opt->pad.t + opt->pad.b;
729 if (tot < opt->min.h)
730 {
731 Evas_Coord space = need - tot;
732 int count;
733
734 count = _evas_object_table_count_expands
735 (c->expands.v, opt->row, opt->end_row);
736
737 if (count > 0)
738 _evas_object_table_sizes_calc_expand
739 (c->sizes.v, opt->row, opt->end_row, space,
740 c->expands.v, count, c->weights.v, totweighth);
741 else
742 _evas_object_table_sizes_calc_noexpand
743 (c->sizes.v, opt->row, opt->end_row, space);
744 }
745 }
746
747 c->total.weights.h = totweightw;
748 c->total.weights.v = totweighth;
749
750 c->total.expands.h = _evas_object_table_count_expands
751 (c->expands.h, 0, priv->size.cols);
752 c->total.expands.v = _evas_object_table_count_expands
753 (c->expands.v, 0, priv->size.rows);
754
755 c->total.min.w = _evas_object_table_sum_sizes
756 (c->sizes.h, 0, priv->size.cols);
757 c->total.min.h = _evas_object_table_sum_sizes
758 (c->sizes.v, 0, priv->size.rows);
759
760 c->total.min.w += priv->pad.h * (priv->size.cols - 1);
761 c->total.min.h += priv->pad.v * (priv->size.rows - 1);
762
763 if ((c->total.min.w > 0) || (c->total.min.h > 0))
764 evas_object_size_hint_min_set(o, c->total.min.w, c->total.min.h);
765
766 // XXX hint max?
767}
768
769static void
770_evas_object_table_calculate_layout_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
771{
772 Evas_Object_Table_Option *opt;
773 Evas_Object_Table_Cache *c;
774 Eina_List *l;
775 Evas_Coord *cols = NULL, *rows = NULL;
776 Evas_Coord x, y, w, h;
777
778 evas_object_geometry_get(o, &x, &y, &w, &h);
779 c = priv->cache;
780
781 /* handle horizontal */
782 if ((c->total.expands.h <= 0) || (c->total.min.w >= w))
783 {
784 x += (w - c->total.min.w) * priv->align.h;
785 w = c->total.min.w;
786 cols = c->sizes.h;
787 }
788 else
789 {
790 int size = priv->size.cols * sizeof(Evas_Coord);
791 cols = malloc(size);
792 if (!cols)
793 {
794 ERR("Could not allocate temp columns (%d bytes): %s",
795 size, strerror(errno));
796 goto end;
797 }
798 memcpy(cols, c->sizes.h, size);
799 _evas_object_table_sizes_calc_expand
800 (cols, 0, priv->size.cols, w - c->total.min.w,
801 c->expands.h, c->total.expands.h, c->weights.h, c->total.weights.h);
802 }
803
804 /* handle vertical */
805 if ((c->total.expands.v <= 0) || (c->total.min.h >= h))
806 {
807 y += (h - c->total.min.h) * priv->align.v;
808 h = c->total.min.h;
809 rows = c->sizes.v;
810 }
811 else
812 {
813 int size = priv->size.rows * sizeof(Evas_Coord);
814 rows = malloc(size);
815 if (!rows)
816 {
817 ERR("could not allocate temp rows (%d bytes): %s",
818 size, strerror(errno));
819 goto end;
820 }
821 memcpy(rows, c->sizes.v, size);
822 _evas_object_table_sizes_calc_expand
823 (rows, 0, priv->size.rows, h - c->total.min.h,
824 c->expands.v, c->total.expands.v, c->weights.v, c->total.weights.v);
825 }
826
827 EINA_LIST_FOREACH(priv->children, l, opt)
828 {
829 Evas_Object *child = opt->obj;
830 Evas_Coord cx, cy, cw, ch;
831
832 cx = x + opt->col * (priv->pad.h);
833 cx += _evas_object_table_sum_sizes(cols, 0, opt->col);
834 cw = _evas_object_table_sum_sizes(cols, opt->col, opt->end_col);
835
836 cy = y + opt->row * (priv->pad.v);
837 cy += _evas_object_table_sum_sizes(rows, 0, opt->row);
838 ch = _evas_object_table_sum_sizes(rows, opt->row, opt->end_row);
839
840 _evas_object_table_calculate_cell(opt, &cx, &cy, &cw, &ch);
841
842 if (priv->is_mirrored)
843 {
844 evas_object_move(opt->obj, x + w - (cx - x + cw), cy);
845 }
846 else
847 {
848 evas_object_move(child, cx, cy);
849 }
850 evas_object_resize(child, cw, ch);
851 }
852
853 end:
854 if (cols != c->sizes.h)
855 {
856 if (cols) free(cols);
857 }
858 if (rows != c->sizes.v)
859 {
860 if (rows) free(rows);
861 }
862}
863
864static void
865_evas_object_table_smart_calculate_regular(Evas_Object *o, Evas_Object_Table_Data *priv)
866{
867 if (priv->hints_changed)
868 _evas_object_table_calculate_hints_regular(o, priv);
869 _evas_object_table_calculate_layout_regular(o, priv);
870}
871
872EVAS_SMART_SUBCLASS_NEW("Evas_Object_Table", _evas_object_table,
873 Evas_Smart_Class, Evas_Smart_Class,
874 evas_object_smart_clipped_class_get, NULL)
875
876static void
877_evas_object_table_smart_add(Evas_Object *o)
878{
879 EVAS_SMART_DATA_ALLOC(o, Evas_Object_Table_Data)
880
881 priv->pad.h = 0;
882 priv->pad.v = 0;
883 priv->align.h = 0.5;
884 priv->align.v = 0.5;
885 priv->size.cols = 0;
886 priv->size.rows = 0;
887 priv->cache = NULL;
888 priv->homogeneous = EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE;
889 priv->hints_changed = 1;
890 priv->expand_h = 0;
891 priv->expand_v = 0;
892
893 _evas_object_table_parent_sc->add(o);
894}
895
896static void
897_evas_object_table_smart_del(Evas_Object *o)
898{
899 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
900 Eina_List *l;
901
902 l = priv->children;
903 while (l)
904 {
905 Evas_Object_Table_Option *opt = l->data;
906 _evas_object_table_child_disconnect(o, opt->obj);
907 _evas_object_table_option_del(opt->obj);
908 free(opt);
909 l = eina_list_remove_list(l, l);
910 }
911
912 if (priv->cache)
913 {
914 _evas_object_table_cache_free(priv->cache);
915 priv->cache = NULL;
916 }
917
918 _evas_object_table_parent_sc->del(o);
919}
920
921static void
922_evas_object_table_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
923{
924 Evas_Coord ow, oh;
925 evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
926 if ((ow == w) && (oh == h)) return;
927 evas_object_smart_changed(o);
928}
929
930static void
931_evas_object_table_smart_calculate(Evas_Object *o)
932{
933 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
934
935 if ((priv->size.cols < 1) || (priv->size.rows < 1))
936 {
937 DBG("Nothing to do: cols=%d, rows=%d",
938 priv->size.cols, priv->size.rows);
939 return;
940 }
941
942 if (priv->homogeneous)
943 _evas_object_table_smart_calculate_homogeneous(o, priv);
944 else
945 _evas_object_table_smart_calculate_regular(o, priv);
946}
947
948static void
949_evas_object_table_smart_set_user(Evas_Smart_Class *sc)
950{
951 sc->add = _evas_object_table_smart_add;
952 sc->del = _evas_object_table_smart_del;
953 sc->resize = _evas_object_table_smart_resize;
954 sc->calculate = _evas_object_table_smart_calculate;
955}
956
957EAPI Evas_Object *
958evas_object_table_add(Evas *evas)
959{
960 return evas_object_smart_add(evas, _evas_object_table_smart_class_new());
961}
962
963EAPI Evas_Object *
964evas_object_table_add_to(Evas_Object *parent)
965{
966 Evas *evas;
967 Evas_Object *o;
968
969 evas = evas_object_evas_get(parent);
970 o = evas_object_table_add(evas);
971 evas_object_smart_member_add(o, parent);
972 return o;
973}
974
975EAPI void
976evas_object_table_homogeneous_set(Evas_Object *o, Evas_Object_Table_Homogeneous_Mode homogeneous)
977{
978 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
979 if (priv->homogeneous == homogeneous)
980 return;
981 priv->homogeneous = homogeneous;
982 _evas_object_table_cache_invalidate(priv);
983 evas_object_smart_changed(o);
984}
985
986EAPI Evas_Object_Table_Homogeneous_Mode
987evas_object_table_homogeneous_get(const Evas_Object *o)
988{
989 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
990 return priv->homogeneous;
991}
992
993EAPI void
994evas_object_table_align_set(Evas_Object *o, double horizontal, double vertical)
995{
996 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
997 if (priv->align.h == horizontal && priv->align.v == vertical)
998 return;
999 priv->align.h = horizontal;
1000 priv->align.v = vertical;
1001 evas_object_smart_changed(o);
1002}
1003
1004EAPI void
1005evas_object_table_align_get(const Evas_Object *o, double *horizontal, double *vertical)
1006{
1007 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1008 if (priv)
1009 {
1010 if (horizontal) *horizontal = priv->align.h;
1011 if (vertical) *vertical = priv->align.v;
1012 }
1013 else
1014 {
1015 if (horizontal) *horizontal = 0.5;
1016 if (vertical) *vertical = 0.5;
1017 }
1018}
1019
1020EAPI void
1021evas_object_table_padding_set(Evas_Object *o, Evas_Coord horizontal, Evas_Coord vertical)
1022{
1023 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
1024 if (priv->pad.h == horizontal && priv->pad.v == vertical)
1025 return;
1026 priv->pad.h = horizontal;
1027 priv->pad.v = vertical;
1028 _evas_object_table_cache_invalidate(priv);
1029 evas_object_smart_changed(o);
1030}
1031
1032EAPI void
1033evas_object_table_padding_get(const Evas_Object *o, Evas_Coord *horizontal, Evas_Coord *vertical)
1034{
1035 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1036 if (priv)
1037 {
1038 if (horizontal) *horizontal = priv->pad.h;
1039 if (vertical) *vertical = priv->pad.v;
1040 }
1041 else
1042 {
1043 if (horizontal) *horizontal = 0;
1044 if (vertical) *vertical = 0;
1045 }
1046}
1047
1048EAPI Eina_Bool
1049evas_object_table_pack_get(Evas_Object *o, Evas_Object *child, unsigned short *col, unsigned short *row, unsigned short *colspan, unsigned short *rowspan)
1050{
1051 Evas_Object_Table_Option *opt;
1052
1053 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1054 opt = _evas_object_table_option_get(child);
1055 if (!opt)
1056 {
1057 if (col) *col = 0;
1058 if (row) *row = 0;
1059 if (colspan) *colspan = 0;
1060 if (rowspan) *rowspan = 0;
1061 return EINA_FALSE;
1062 }
1063 if (col) *col = opt->col;
1064 if (row) *row = opt->row;
1065 if (colspan) *colspan = opt->colspan;
1066 if (rowspan) *rowspan = opt->rowspan;
1067 return EINA_TRUE;
1068}
1069
1070EAPI Eina_Bool
1071evas_object_table_pack(Evas_Object *o, Evas_Object *child, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
1072{
1073 Evas_Object_Table_Option *opt;
1074
1075 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1076
1077 if (rowspan < 1)
1078 {
1079 ERR("rowspan < 1");
1080 return EINA_FALSE;
1081 }
1082 if (colspan < 1)
1083 {
1084 ERR("colspan < 1");
1085 return EINA_FALSE;
1086 }
1087
1088 opt = _evas_object_table_option_get(child);
1089 if (!opt)
1090 {
1091 opt = malloc(sizeof(*opt));
1092 if (!opt)
1093 {
1094 ERR("could not allocate table option data.");
1095 return EINA_FALSE;
1096 }
1097 }
1098
1099 opt->obj = child;
1100 opt->col = col;
1101 opt->row = row;
1102 opt->colspan = colspan;
1103 opt->rowspan = rowspan;
1104 opt->end_col = col + colspan;
1105 opt->end_row = row + rowspan;
1106
1107 if (evas_object_smart_parent_get(child) == o)
1108 {
1109 Eina_Bool need_shrink = EINA_FALSE;
1110
1111 if (priv->size.cols < opt->end_col)
1112 priv->size.cols = opt->end_col;
1113 else
1114 need_shrink = EINA_TRUE;
1115 if (priv->size.rows < opt->end_row)
1116 priv->size.rows = opt->end_row;
1117 else
1118 need_shrink = EINA_TRUE;
1119
1120 if (need_shrink)
1121 {
1122 Eina_List *l;
1123 Evas_Object_Table_Option *opt2;
1124 int max_row = 0, max_col = 0;
1125
1126 EINA_LIST_FOREACH(priv->children, l, opt2)
1127 {
1128 if (max_col < opt2->end_col) max_col = opt2->end_col;
1129 if (max_row < opt2->end_row) max_row = opt2->end_row;
1130 }
1131 priv->size.cols = max_col;
1132 priv->size.rows = max_row;
1133 }
1134 }
1135 else
1136 {
1137 opt->min.w = 0;
1138 opt->min.h = 0;
1139 opt->max.w = 0;
1140 opt->max.h = 0;
1141 opt->align.h = 0.5;
1142 opt->align.v = 0.5;
1143 opt->pad.l = 0;
1144 opt->pad.r = 0;
1145 opt->pad.t = 0;
1146 opt->pad.b = 0;
1147 opt->expand_h = 0;
1148 opt->expand_v = 0;
1149
1150 priv->children = eina_list_append(priv->children, opt);
1151
1152 if (priv->size.cols < opt->end_col)
1153 priv->size.cols = opt->end_col;
1154 if (priv->size.rows < opt->end_row)
1155 priv->size.rows = opt->end_row;
1156
1157 _evas_object_table_option_set(child, opt);
1158 evas_object_smart_member_add(child, o);
1159 _evas_object_table_child_connect(o, child);
1160 }
1161 _evas_object_table_cache_invalidate(priv);
1162 evas_object_smart_changed(o);
1163 return EINA_TRUE;
1164}
1165
1166static void
1167_evas_object_table_remove_opt(Evas_Object_Table_Data *priv, Evas_Object_Table_Option *opt)
1168{
1169 Eina_List *l;
1170 int max_row, max_col, was_greatest;
1171
1172 max_row = 0;
1173 max_col = 0;
1174 was_greatest = 0;
1175 l = priv->children;
1176 while (l)
1177 {
1178 Evas_Object_Table_Option *cur_opt = l->data;
1179
1180 if (cur_opt != opt)
1181 {
1182 if (max_col < cur_opt->end_col)
1183 max_col = cur_opt->end_col;
1184 if (max_row < cur_opt->end_row)
1185 max_row = cur_opt->end_row;
1186
1187 l = l->next;
1188 }
1189 else
1190 {
1191 Eina_List *tmp = l->next;
1192 priv->children = eina_list_remove_list(priv->children, l);
1193
1194 if ((priv->size.cols > opt->end_col) &&
1195 (priv->size.rows > opt->end_row))
1196 break;
1197 else
1198 {
1199 was_greatest = 1;
1200 l = tmp;
1201 }
1202 }
1203 }
1204
1205 if (was_greatest)
1206 {
1207 priv->size.cols = max_col;
1208 priv->size.rows = max_row;
1209 }
1210}
1211
1212EAPI Eina_Bool
1213evas_object_table_unpack(Evas_Object *o, Evas_Object *child)
1214{
1215 Evas_Object_Table_Option *opt;
1216
1217 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, 0);
1218
1219 if (o != evas_object_smart_parent_get(child))
1220 {
1221 ERR("cannot unpack child from incorrect table!");
1222 return EINA_FALSE;
1223 }
1224
1225 opt = _evas_object_table_option_del(child);
1226 if (!opt)
1227 {
1228 ERR("cannot unpack child with no packing option!");
1229 return EINA_FALSE;
1230 }
1231
1232 _evas_object_table_child_disconnect(o, child);
1233 _evas_object_table_remove_opt(priv, opt);
1234 evas_object_smart_member_del(child);
1235 free(opt);
1236 _evas_object_table_cache_invalidate(priv);
1237 evas_object_smart_changed(o);
1238
1239 return EINA_TRUE;
1240}
1241
1242EAPI void
1243evas_object_table_clear(Evas_Object *o, Eina_Bool clear)
1244{
1245 Evas_Object_Table_Option *opt;
1246
1247 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(o, priv);
1248
1249 EINA_LIST_FREE(priv->children, opt)
1250 {
1251 _evas_object_table_child_disconnect(o, opt->obj);
1252 _evas_object_table_option_del(opt->obj);
1253 evas_object_smart_member_del(opt->obj);
1254 if (clear)
1255 evas_object_del(opt->obj);
1256 free(opt);
1257 }
1258 priv->size.cols = 0;
1259 priv->size.rows = 0;
1260 _evas_object_table_cache_invalidate(priv);
1261 evas_object_smart_changed(o);
1262}
1263
1264EAPI void
1265evas_object_table_col_row_size_get(const Evas_Object *o, int *cols, int *rows)
1266{
1267 EVAS_OBJECT_TABLE_DATA_GET(o, priv);
1268 if (priv)
1269 {
1270 if (cols) *cols = priv->size.cols;
1271 if (rows) *rows = priv->size.rows;
1272 }
1273 else
1274 {
1275 if (cols) *cols = -1;
1276 if (rows) *rows = -1;
1277 }
1278}
1279
1280EAPI Eina_Iterator *
1281evas_object_table_iterator_new(const Evas_Object *o)
1282{
1283 Evas_Object_Table_Iterator *it;
1284
1285 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1286
1287 if (!priv->children) return NULL;
1288
1289 it = calloc(1, sizeof(Evas_Object_Table_Iterator));
1290 if (!it) return NULL;
1291
1292 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
1293
1294 it->real_iterator = eina_list_iterator_new(priv->children);
1295 it->table = o;
1296
1297 it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_table_iterator_next);
1298 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_table_iterator_get_container);
1299 it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_table_iterator_free);
1300
1301 return &it->iterator;
1302}
1303
1304EAPI Eina_Accessor *
1305evas_object_table_accessor_new(const Evas_Object *o)
1306{
1307 Evas_Object_Table_Accessor *it;
1308
1309 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1310
1311 if (!priv->children) return NULL;
1312
1313 it = calloc(1, sizeof(Evas_Object_Table_Accessor));
1314 if (!it) return NULL;
1315
1316 EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
1317
1318 it->real_accessor = eina_list_accessor_new(priv->children);
1319 it->table = o;
1320
1321 it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_table_accessor_get_at);
1322 it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_table_accessor_get_container);
1323 it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_table_accessor_free);
1324
1325 return &it->accessor;
1326}
1327
1328EAPI Eina_List *
1329evas_object_table_children_get(const Evas_Object *o)
1330{
1331 Eina_List *new_list = NULL, *l;
1332 Evas_Object_Table_Option *opt;
1333
1334 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1335
1336 EINA_LIST_FOREACH(priv->children, l, opt)
1337 new_list = eina_list_append(new_list, opt->obj);
1338
1339 return new_list;
1340}
1341
1342Evas_Object *
1343evas_object_table_child_get(const Evas_Object *o, unsigned short col, unsigned short row)
1344{
1345 Eina_List *l;
1346 Evas_Object_Table_Option *opt;
1347
1348 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(o, priv, NULL);
1349
1350 EINA_LIST_FOREACH(priv->children, l, opt)
1351 if (opt->col == col && opt->row == row)
1352 return opt->obj;
1353 return NULL;
1354}
1355
1356EAPI Eina_Bool
1357evas_object_table_mirrored_get(const Evas_Object *obj)
1358{
1359 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN_VAL(obj, priv, EINA_FALSE);
1360
1361 return priv->is_mirrored;
1362}
1363
1364EAPI void
1365evas_object_table_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
1366{
1367 EVAS_OBJECT_TABLE_DATA_GET_OR_RETURN(obj, priv);
1368 if (priv->is_mirrored != mirrored)
1369 {
1370 priv->is_mirrored = mirrored;
1371 _evas_object_table_smart_calculate(obj);
1372 }
1373}