1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 #include <errno.h>
4 
5 #define MY_CLASS EVAS_GRID_CLASS
6 
7 typedef struct _Evas_Grid_Data              Evas_Grid_Data;
8 typedef struct _Evas_Object_Grid_Option     Evas_Object_Grid_Option;
9 typedef struct _Evas_Object_Grid_Iterator   Evas_Object_Grid_Iterator;
10 typedef struct _Evas_Object_Grid_Accessor   Evas_Object_Grid_Accessor;
11 
12 struct _Evas_Object_Grid_Option
13 {
14    Evas_Object *obj;
15    Eina_List *l;
16    int x, y, w, h;
17 };
18 
19 struct _Evas_Grid_Data
20 {
21    Evas_Object_Smart_Clipped_Data base;
22    Eina_List *children;
23    struct {
24       int w, h;
25    } size;
26    Eina_Bool is_mirrored : 1;
27 };
28 
29 struct _Evas_Object_Grid_Iterator
30 {
31    Eina_Iterator iterator;
32 
33    Eina_Iterator *real_iterator;
34    const Evas_Object *grid;
35 };
36 
37 struct _Evas_Object_Grid_Accessor
38 {
39    Eina_Accessor accessor;
40 
41    Eina_Accessor *real_accessor;
42    const Evas_Object *grid;
43 };
44 
45 #define EVAS_OBJECT_GRID_DATA_GET(o, ptr)			\
46   Evas_Grid_Data *ptr = efl_data_scope_get(o, MY_CLASS)
47 
48 #define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, ptr)			\
49   EVAS_OBJECT_GRID_DATA_GET(o, ptr);					\
50   if (!ptr)								\
51     {									\
52       ERR("No widget data for object %p (%s)",				\
53 	   o, evas_object_type_get(o));					\
54        return;								\
55     }
56 
57 #define EVAS_OBJECT_GRID_DATA_GET_OR_RETURN_VAL(o, ptr, val)		\
58   EVAS_OBJECT_GRID_DATA_GET(o, ptr);					\
59   if (!ptr)								\
60     {									\
61        ERR("No widget data for object %p (%s)",	                \
62 	       o, evas_object_type_get(o));				\
63        return val;							\
64     }
65 
66 static const char EVAS_OBJECT_GRID_OPTION_KEY[] = "|EvGd";
67 
68 static Eina_Bool
_evas_object_grid_iterator_next(Evas_Object_Grid_Iterator * it,void ** data)69 _evas_object_grid_iterator_next(Evas_Object_Grid_Iterator *it, void **data)
70 {
71    Evas_Object_Grid_Option *opt;
72 
73    if (!eina_iterator_next(it->real_iterator, (void **)&opt))
74      return EINA_FALSE;
75    if (data) *data = opt->obj;
76    return EINA_TRUE;
77 }
78 
79 static Evas_Object *
_evas_object_grid_iterator_get_container(Evas_Object_Grid_Iterator * it)80 _evas_object_grid_iterator_get_container(Evas_Object_Grid_Iterator *it)
81 {
82    return (Evas_Object *)it->grid;
83 }
84 
85 static void
_evas_object_grid_iterator_free(Evas_Object_Grid_Iterator * it)86 _evas_object_grid_iterator_free(Evas_Object_Grid_Iterator *it)
87 {
88    eina_iterator_free(it->real_iterator);
89    free(it);
90 }
91 
92 static Eina_Bool
_evas_object_grid_accessor_get_at(Evas_Object_Grid_Accessor * it,unsigned int idx,void ** data)93 _evas_object_grid_accessor_get_at(Evas_Object_Grid_Accessor *it, unsigned int idx, void **data)
94 {
95    Evas_Object_Grid_Option *opt = NULL;
96 
97    if (!eina_accessor_data_get(it->real_accessor, idx, (void **)&opt))
98      return EINA_FALSE;
99    if (data) *data = opt->obj;
100    return EINA_TRUE;
101 }
102 
103 static Evas_Object *
_evas_object_grid_accessor_get_container(Evas_Object_Grid_Accessor * it)104 _evas_object_grid_accessor_get_container(Evas_Object_Grid_Accessor *it)
105 {
106    return (Evas_Object *)it->grid;
107 }
108 
109 static void
_evas_object_grid_accessor_free(Evas_Object_Grid_Accessor * it)110 _evas_object_grid_accessor_free(Evas_Object_Grid_Accessor *it)
111 {
112    eina_accessor_free(it->real_accessor);
113    free(it);
114 }
115 
116 static Evas_Object_Grid_Option *
_evas_object_grid_option_get(Evas_Object * o)117 _evas_object_grid_option_get(Evas_Object *o)
118 {
119    return evas_object_data_get(o, EVAS_OBJECT_GRID_OPTION_KEY);
120 }
121 
122 static void
_evas_object_grid_option_set(Evas_Object * o,const Evas_Object_Grid_Option * opt)123 _evas_object_grid_option_set(Evas_Object *o, const Evas_Object_Grid_Option *opt)
124 {
125    evas_object_data_set(o, EVAS_OBJECT_GRID_OPTION_KEY, opt);
126 }
127 
128 static Evas_Object_Grid_Option *
_evas_object_grid_option_del(Evas_Object * o)129 _evas_object_grid_option_del(Evas_Object *o)
130 {
131    return evas_object_data_del(o, EVAS_OBJECT_GRID_OPTION_KEY);
132 }
133 
134 static void
_on_child_del(void * data,Evas * evas EINA_UNUSED,Evas_Object * child,void * einfo EINA_UNUSED)135 _on_child_del(void *data, Evas *evas EINA_UNUSED, Evas_Object *child, void *einfo EINA_UNUSED)
136 {
137    Evas_Object *grid = data;
138    evas_object_grid_unpack(grid, child);
139 }
140 
141 static void
_evas_object_grid_child_connect(Evas_Object * o,Evas_Object * child)142 _evas_object_grid_child_connect(Evas_Object *o, Evas_Object *child)
143 {
144    evas_object_event_callback_add
145      (child, EVAS_CALLBACK_DEL, _on_child_del, o);
146 }
147 
148 static void
_evas_object_grid_child_disconnect(Evas_Object * o,Evas_Object * child)149 _evas_object_grid_child_disconnect(Evas_Object *o, Evas_Object *child)
150 {
151    evas_object_event_callback_del_full
152      (child, EVAS_CALLBACK_DEL, _on_child_del, o);
153 }
154 
155 EVAS_SMART_SUBCLASS_NEW("Evas_Object_Grid", _evas_object_grid,
156 			Evas_Smart_Class, Evas_Smart_Class,
157 			evas_object_smart_clipped_class_get, NULL)
158 
159 static void
_evas_object_grid_smart_add(Evas_Object * o)160 _evas_object_grid_smart_add(Evas_Object *o)
161 {
162    Evas_Object_Smart_Clipped_Data *base;
163    Evas_Grid_Data *priv;
164 
165    // Grid is an ugly mix of legacy & eo...
166    base = evas_object_smart_data_get(o);
167    priv = efl_data_scope_get(o, MY_CLASS);
168    priv->base = *base;
169    evas_object_smart_data_set(o, priv);
170 
171    priv->size.w = 100;
172    priv->size.h = 100;
173 }
174 
175 static void
_evas_object_grid_smart_del(Evas_Object * o)176 _evas_object_grid_smart_del(Evas_Object *o)
177 {
178    EVAS_OBJECT_GRID_DATA_GET(o, priv);
179 
180    while (priv->children)
181      {
182         Evas_Object_Grid_Option *opt = priv->children->data;
183         _evas_object_grid_child_disconnect(o, opt->obj);
184         _evas_object_grid_option_del(opt->obj);
185         free(opt);
186         priv->children = eina_list_remove_list(priv->children, priv->children);
187      }
188    //Free the clipper resource properly,
189    Eo *clipper = evas_object_smart_clipped_clipper_get(o);
190    if (clipper) evas_object_del(clipper);
191    /*  below deletion occurs the recursive member remove hell. */
192    //   _evas_object_grid_parent_sc->del(o);
193 }
194 
195 static void
_evas_object_grid_smart_resize(Evas_Object * o,Evas_Coord w,Evas_Coord h)196 _evas_object_grid_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
197 {
198    Evas_Coord ow, oh;
199    evas_object_geometry_get(o, NULL, NULL, &ow, &oh);
200    if ((ow == w) && (oh == h)) return;
201    evas_object_smart_changed(o);
202 }
203 
204 static void
_evas_object_grid_smart_calculate(Evas_Object * o)205 _evas_object_grid_smart_calculate(Evas_Object *o)
206 {
207    Eina_List *l;
208    Evas_Object_Grid_Option *opt;
209    Evas *e;
210    Evas_Coord x, y, w, h;
211    long long xl, yl, wl, hl, vwl, vhl;
212    Eina_Bool mirror;
213 
214    EVAS_OBJECT_GRID_DATA_GET_OR_RETURN(o, priv);
215    if (!priv->children) return;
216 
217    e = evas_object_evas_get(o);
218    evas_event_freeze(e);
219 
220    evas_object_geometry_get(o, &x, &y, &w, &h);
221    xl = x;
222    yl = y;
223    wl = w;
224    hl = h;
225    mirror = priv->is_mirrored;
226    vwl = priv->size.w;
227    vhl = priv->size.h;
228    EINA_LIST_FOREACH(priv->children, l, opt)
229      {
230         long long x1, y1, x2, y2;
231 
232         if (vwl > 0)
233           {
234              if (!mirror)
235                {
236                   x1 = xl + ((wl * (long long)opt->x) / vwl);
237                   x2 = xl + ((wl * (long long)(opt->x + opt->w)) / vwl);
238                }
239              else
240                {
241                   x1 = xl + ((wl * (vwl - (long long)(opt->x + opt->w))) / vwl);
242                   x2 = xl + ((wl * (vwl - (long long)opt->x)) / vwl);
243                }
244           }
245         else
246           {
247              x1 = xl;
248              x2 = xl;
249           }
250         if (vhl > 0)
251           {
252              y1 = yl + ((hl * (long long)opt->y) / vhl);
253              y2 = yl + ((hl * (long long)(opt->y + opt->h)) / vhl);
254           }
255         else
256           {
257              y1 = yl;
258              y2 = yl;
259           }
260         evas_object_move(opt->obj, x1, y1);
261         evas_object_resize(opt->obj, x2 - x1, y2 - y1);
262      }
263 
264    evas_event_thaw(e);
265 }
266 
267 static void
_evas_object_grid_smart_set_user(Evas_Smart_Class * sc)268 _evas_object_grid_smart_set_user(Evas_Smart_Class *sc)
269 {
270    sc->add = _evas_object_grid_smart_add;
271    sc->del = _evas_object_grid_smart_del;
272    sc->resize = _evas_object_grid_smart_resize;
273    sc->calculate = _evas_object_grid_smart_calculate;
274 }
275 
276 EAPI Evas_Object *
evas_object_grid_add(Evas * evas)277 evas_object_grid_add(Evas *evas)
278 {
279    evas = evas_find(evas);
280    EINA_SAFETY_ON_FALSE_RETURN_VAL(efl_isa(evas, EVAS_CANVAS_CLASS), NULL);
281    return efl_add(MY_CLASS, evas, efl_canvas_object_legacy_ctor(efl_added));
282 }
283 
284 EOLIAN static Eo *
_evas_grid_efl_object_constructor(Eo * obj,Evas_Grid_Data * class_data EINA_UNUSED)285 _evas_grid_efl_object_constructor(Eo *obj, Evas_Grid_Data *class_data EINA_UNUSED)
286 {
287    efl_canvas_group_clipped_set(obj, EINA_TRUE);
288    obj = efl_constructor(efl_super(obj, MY_CLASS));
289    evas_object_smart_attach(obj, _evas_object_grid_smart_class_new());
290 
291    return obj;
292 }
293 
294 EOLIAN static Evas_Object*
_evas_grid_add_to(Eo * parent,Evas_Grid_Data * _pd EINA_UNUSED)295 _evas_grid_add_to(Eo *parent, Evas_Grid_Data *_pd EINA_UNUSED)
296 {
297    Evas *evas;
298    Evas_Object *ret;
299    evas = evas_object_evas_get(parent);
300    ret = evas_object_grid_add(evas);
301    evas_object_smart_member_add(ret, parent);
302 
303    return ret;
304 }
305 
306 EOLIAN static void
_evas_grid_grid_size_set(Eo * o,Evas_Grid_Data * priv,int w,int h)307 _evas_grid_grid_size_set(Eo *o, Evas_Grid_Data *priv, int w, int h)
308 {
309    if ((priv->size.w == w) && (priv->size.h == h)) return;
310    priv->size.w = w;
311    priv->size.h = h;
312    evas_object_smart_changed(o);
313 }
314 
315 EOLIAN static void
_evas_grid_grid_size_get(const Eo * o EINA_UNUSED,Evas_Grid_Data * priv,int * w,int * h)316 _evas_grid_grid_size_get(const Eo *o EINA_UNUSED, Evas_Grid_Data *priv, int *w, int *h)
317 {
318    if (w) *w = priv->size.w;
319    if (h) *h = priv->size.h;
320 }
321 
322 EOLIAN static Eina_Bool
_evas_grid_pack(Eo * o,Evas_Grid_Data * priv,Evas_Object * child,int x,int y,int w,int h)323 _evas_grid_pack(Eo *o, Evas_Grid_Data *priv, Evas_Object *child, int x, int y, int w, int h)
324 {
325    Evas_Object_Grid_Option *opt;
326    Eina_Bool newobj = EINA_FALSE;
327 
328    opt = _evas_object_grid_option_get(child);
329    if (!opt)
330      {
331         opt = malloc(sizeof(*opt));
332         if (!opt)
333           {
334              ERR("could not allocate grid option data.");
335              return EINA_FALSE;
336           }
337         newobj = EINA_TRUE;
338      }
339 
340    opt->x = x;
341    opt->y = y;
342    opt->w = w;
343    opt->h = h;
344 
345    if (newobj)
346      {
347         opt->obj = child;
348         priv->children = eina_list_append(priv->children, opt);
349         opt->l = eina_list_last(priv->children);
350         _evas_object_grid_option_set(child, opt);
351         evas_object_smart_member_add(child, o);
352         _evas_object_grid_child_connect(o, child);
353      }
354    // FIXME: we could keep a changed list
355    evas_object_smart_changed(o);
356 
357    return EINA_TRUE;
358 }
359 
360 static void
_evas_object_grid_remove_opt(Evas_Grid_Data * priv,Evas_Object_Grid_Option * opt)361 _evas_object_grid_remove_opt(Evas_Grid_Data *priv, Evas_Object_Grid_Option *opt)
362 {
363    priv->children = eina_list_remove_list(priv->children, opt->l);
364    opt->l = NULL;
365 }
366 
367 EOLIAN static Eina_Bool
_evas_grid_unpack(Eo * o,Evas_Grid_Data * priv,Evas_Object * child)368 _evas_grid_unpack(Eo *o, Evas_Grid_Data *priv, Evas_Object *child)
369 {
370    Evas_Object_Grid_Option *opt;
371 
372    if (o != evas_object_smart_parent_get(child))
373      {
374 	ERR("cannot unpack child from incorrect grid!");
375         return EINA_FALSE;
376      }
377 
378    opt = _evas_object_grid_option_del(child);
379    if (!opt)
380      {
381 	ERR("cannot unpack child with no packing option!");
382         return EINA_FALSE;
383      }
384 
385    _evas_object_grid_child_disconnect(o, child);
386    _evas_object_grid_remove_opt(priv, opt);
387    evas_object_smart_member_del(child);
388    free(opt);
389 
390    return EINA_TRUE;
391 }
392 
393 EOLIAN static void
_evas_grid_clear(Eo * o,Evas_Grid_Data * priv,Eina_Bool clear)394 _evas_grid_clear(Eo *o, Evas_Grid_Data *priv, Eina_Bool clear)
395 {
396    Evas_Object_Grid_Option *opt;
397 
398    EINA_LIST_FREE(priv->children, opt)
399      {
400 	_evas_object_grid_child_disconnect(o, opt->obj);
401 	_evas_object_grid_option_del(opt->obj);
402 	evas_object_smart_member_del(opt->obj);
403 	if (clear)
404 	  evas_object_del(opt->obj);
405 	free(opt);
406      }
407 }
408 
409 EOLIAN static Eina_Bool
_evas_grid_pack_get(const Eo * o EINA_UNUSED,Evas_Grid_Data * _pd EINA_UNUSED,Evas_Object * child,int * x,int * y,int * w,int * h)410 _evas_grid_pack_get(const Eo *o EINA_UNUSED, Evas_Grid_Data *_pd EINA_UNUSED, Evas_Object *child, int *x, int *y, int *w, int *h)
411 {
412    Evas_Object_Grid_Option *opt;
413 
414    if (x) *x = 0;
415    if (y) *y = 0;
416    if (w) *w = 0;
417    if (h) *h = 0;
418    opt = _evas_object_grid_option_get(child);
419    if (!opt) return 0;
420    if (x) *x = opt->x;
421    if (y) *y = opt->y;
422    if (w) *w = opt->w;
423    if (h) *h = opt->h;
424 
425    return 1;
426 }
427 
428 EOLIAN static Eina_Iterator*
_evas_grid_iterator_new(const Eo * o,Evas_Grid_Data * priv)429 _evas_grid_iterator_new(const Eo *o, Evas_Grid_Data *priv)
430 {
431    Evas_Object_Grid_Iterator *it;
432 
433    if (!priv->children) return NULL;
434 
435    it = calloc(1, sizeof(Evas_Object_Grid_Iterator));
436    if (!it) return NULL;
437 
438    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
439 
440    it->real_iterator = eina_list_iterator_new(priv->children);
441    it->grid = o;
442 
443    it->iterator.next = FUNC_ITERATOR_NEXT(_evas_object_grid_iterator_next);
444    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_evas_object_grid_iterator_get_container);
445    it->iterator.free = FUNC_ITERATOR_FREE(_evas_object_grid_iterator_free);
446 
447    return &it->iterator;
448 }
449 
450 EOLIAN static Eina_Accessor*
_evas_grid_accessor_new(const Eo * o,Evas_Grid_Data * priv)451 _evas_grid_accessor_new(const Eo *o, Evas_Grid_Data *priv)
452 {
453    Evas_Object_Grid_Accessor *it;
454 
455    if (!priv->children) return NULL;
456 
457    it = calloc(1, sizeof(Evas_Object_Grid_Accessor));
458    if (!it) return NULL;
459 
460    EINA_MAGIC_SET(&it->accessor, EINA_MAGIC_ACCESSOR);
461 
462    it->real_accessor = eina_list_accessor_new(priv->children);
463    it->grid = o;
464 
465    it->accessor.get_at = FUNC_ACCESSOR_GET_AT(_evas_object_grid_accessor_get_at);
466    it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(_evas_object_grid_accessor_get_container);
467    it->accessor.free = FUNC_ACCESSOR_FREE(_evas_object_grid_accessor_free);
468 
469    return &it->accessor;
470 }
471 
472 EOLIAN static Eina_List*
_evas_grid_children_get(const Eo * o EINA_UNUSED,Evas_Grid_Data * priv)473 _evas_grid_children_get(const Eo *o EINA_UNUSED, Evas_Grid_Data *priv)
474 {
475    Eina_List *new_list = NULL, *l;
476    Evas_Object_Grid_Option *opt;
477 
478    EINA_LIST_FOREACH(priv->children, l, opt)
479       new_list = eina_list_append(new_list, opt->obj);
480 
481    return new_list;
482 }
483 
484 EOLIAN static Eina_Bool
_evas_grid_efl_ui_i18n_mirrored_get(const Eo * o EINA_UNUSED,Evas_Grid_Data * priv)485 _evas_grid_efl_ui_i18n_mirrored_get(const Eo *o EINA_UNUSED, Evas_Grid_Data *priv)
486 {
487    return priv->is_mirrored;
488 }
489 
490 EOLIAN static void
_evas_grid_efl_ui_i18n_mirrored_set(Eo * o EINA_UNUSED,Evas_Grid_Data * priv,Eina_Bool mirrored)491 _evas_grid_efl_ui_i18n_mirrored_set(Eo *o EINA_UNUSED, Evas_Grid_Data *priv, Eina_Bool mirrored)
492 {
493    mirrored = !!mirrored;
494    if (priv->is_mirrored != mirrored)
495      {
496         priv->is_mirrored = mirrored;
497         _evas_object_grid_smart_calculate(o);
498      }
499 }
500 
501 EAPI void
evas_object_grid_mirrored_set(Evas_Grid * obj,Eina_Bool mirrored)502 evas_object_grid_mirrored_set(Evas_Grid *obj, Eina_Bool mirrored)
503 {
504    efl_ui_mirrored_set(obj, mirrored);
505 }
506 
507 EAPI Eina_Bool
evas_object_grid_mirrored_get(const Evas_Grid * obj)508 evas_object_grid_mirrored_get(const Evas_Grid *obj)
509 {
510    return efl_ui_mirrored_get(obj);
511 }
512 
513 #include "canvas/evas_grid_eo.c"
514