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