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