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