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