1 #include "e.h"
2 
3 /* FIXME: something is weird here - i had to reverse all stacking logic to make
4  * it work... */
5 
6 typedef struct _E_Smart_Data  E_Smart_Data;
7 typedef struct _E_Layout_Item E_Layout_Item;
8 
9 struct _E_Smart_Data
10 {
11    Evas_Coord    x, y, w, h;
12    Evas_Coord    vw, vh;
13    Evas_Object  *obj;
14    Evas_Object  *clip;
15    int           frozen;
16    unsigned char changed E_BITFIELD;
17    Eina_Inlist  *items;
18 };
19 
20 struct _E_Layout_Item
21 {
22    EINA_INLIST;
23    E_Smart_Data *sd;
24    Evas_Coord    x, y, w, h;
25    Evas_Object  *obj;
26 };
27 
28 /* local subsystem functions */
29 static E_Layout_Item *_e_layout_smart_adopt(E_Smart_Data *sd, Evas_Object *obj);
30 static void           _e_layout_smart_disown(Evas_Object *obj);
31 static void           _e_layout_smart_item_del_hook(void *data, Evas *e, Evas_Object *obj, void *event_info);
32 static void           _e_layout_smart_reconfigure(E_Smart_Data *sd);
33 static void           _e_layout_smart_move_resize_item(E_Layout_Item *li);
34 
35 static void           _e_layout_smart_init(void);
36 static void           _e_layout_smart_add(Evas_Object *obj);
37 static void           _e_layout_smart_del(Evas_Object *obj);
38 static void           _e_layout_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y);
39 static void           _e_layout_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h);
40 static void           _e_layout_smart_show(Evas_Object *obj);
41 static void           _e_layout_smart_hide(Evas_Object *obj);
42 static void           _e_layout_smart_color_set(Evas_Object *obj, int r, int g, int b, int a);
43 static void           _e_layout_smart_clip_set(Evas_Object *obj, Evas_Object *clip);
44 static void           _e_layout_smart_clip_unset(Evas_Object *obj);
45 
46 /* local subsystem globals */
47 static Evas_Smart *_e_smart = NULL;
48 
49 /* externally accessible functions */
50 E_API Evas_Object *
e_layout_add(Evas * evas)51 e_layout_add(Evas *evas)
52 {
53    _e_layout_smart_init();
54    return evas_object_smart_add(evas, _e_smart);
55 }
56 
57 E_API int
e_layout_freeze(Evas_Object * obj)58 e_layout_freeze(Evas_Object *obj)
59 {
60    E_Smart_Data *sd;
61 
62    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERR(0);
63    sd = evas_object_smart_data_get(obj);
64    sd->frozen++;
65    return sd->frozen;
66 }
67 
68 E_API int
e_layout_thaw(Evas_Object * obj)69 e_layout_thaw(Evas_Object *obj)
70 {
71    E_Smart_Data *sd;
72 
73    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERR(0);
74    sd = evas_object_smart_data_get(obj);
75    sd->frozen--;
76    if (sd->frozen <= 0) _e_layout_smart_reconfigure(sd);
77    return sd->frozen;
78 }
79 
80 E_API void
e_layout_virtual_size_set(Evas_Object * obj,Evas_Coord w,Evas_Coord h)81 e_layout_virtual_size_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
82 {
83    E_Smart_Data *sd;
84 
85    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR();
86    sd = evas_object_smart_data_get(obj);
87    if (w < 1) w = 1;
88    if (h < 1) h = 1;
89    if ((sd->vw == w) && (sd->vh == h)) return;
90    sd->vw = w;
91    sd->vh = h;
92    sd->changed = 1;
93    if (sd->frozen <= 0) _e_layout_smart_reconfigure(sd);
94 }
95 
96 E_API void
e_layout_virtual_size_get(Evas_Object * obj,Evas_Coord * w,Evas_Coord * h)97 e_layout_virtual_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
98 {
99    E_Smart_Data *sd;
100 
101    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR();
102    sd = evas_object_smart_data_get(obj);
103    if (w) *w = sd->vw;
104    if (h) *h = sd->vh;
105 }
106 
107 E_API void
e_layout_coord_canvas_to_virtual(Evas_Object * obj,Evas_Coord cx,Evas_Coord cy,Evas_Coord * vx,Evas_Coord * vy)108 e_layout_coord_canvas_to_virtual(Evas_Object *obj, Evas_Coord cx, Evas_Coord cy, Evas_Coord *vx, Evas_Coord *vy)
109 {
110    E_Smart_Data *sd;
111 
112    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR();
113    sd = evas_object_smart_data_get(obj);
114 
115    if (vx) *vx = (cx - sd->x) * ((double)(sd->vw) / sd->w);
116    if (vy) *vy = (cy - sd->y) * ((double)(sd->vh) / sd->h);
117 }
118 
119 E_API void
e_layout_coord_virtual_to_canvas(Evas_Object * obj,Evas_Coord vx,Evas_Coord vy,Evas_Coord * cx,Evas_Coord * cy)120 e_layout_coord_virtual_to_canvas(Evas_Object *obj, Evas_Coord vx, Evas_Coord vy, Evas_Coord *cx, Evas_Coord *cy)
121 {
122    E_Smart_Data *sd;
123 
124    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR();
125    sd = evas_object_smart_data_get(obj);
126 
127    if (cx) *cx = vx * ((double)(sd->w) / sd->vw) + sd->x;
128    if (cy) *cy = vy * ((double)(sd->h) / sd->vh) + sd->y;
129 }
130 
131 E_API void
e_layout_pack(Evas_Object * obj,Evas_Object * child)132 e_layout_pack(Evas_Object *obj, Evas_Object *child)
133 {
134    E_Smart_Data *sd;
135    E_Layout_Item *li;
136 
137    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR();
138    sd = evas_object_smart_data_get(obj);
139    li = _e_layout_smart_adopt(sd, child);
140    sd->items = eina_inlist_append(sd->items, EINA_INLIST_GET(li));
141    evas_object_lower(child);
142    if (sd->frozen <= 0) _e_layout_smart_move_resize_item(li);
143 }
144 
145 E_API void
e_layout_child_move(Evas_Object * obj,Evas_Coord x,Evas_Coord y)146 e_layout_child_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
147 {
148    E_Layout_Item *li;
149 
150    li = evas_object_data_get(obj, "e_layout_data");
151    if (!li) return;
152    if ((li->x == x) && (li->y == y)) return;
153    li->x = x;
154    li->y = y;
155    if (li->sd->frozen <= 0) _e_layout_smart_move_resize_item(li);
156 }
157 
158 E_API Evas_Object *
e_layout_child_above_get(Evas_Object * obj)159 e_layout_child_above_get(Evas_Object *obj)
160 {
161    E_Layout_Item *li;
162 
163    li = evas_object_data_get(obj, "e_layout_data");
164    EINA_SAFETY_ON_NULL_RETURN_VAL(li, NULL);
165    li = (E_Layout_Item*)EINA_INLIST_GET(li)->next;
166    return li ? li->obj : NULL;
167 }
168 
169 E_API Evas_Object *
e_layout_child_below_get(Evas_Object * obj)170 e_layout_child_below_get(Evas_Object *obj)
171 {
172    E_Layout_Item *li;
173 
174    li = evas_object_data_get(obj, "e_layout_data");
175    EINA_SAFETY_ON_NULL_RETURN_VAL(li, NULL);
176    li = (E_Layout_Item*)EINA_INLIST_GET(li)->prev;
177    return li ? li->obj : NULL;
178 }
179 
180 E_API Evas_Object *
e_layout_top_child_get(Evas_Object * obj)181 e_layout_top_child_get(Evas_Object *obj)
182 {
183    E_Smart_Data *sd;
184    E_Layout_Item *li;
185 
186    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR() NULL;
187    sd = evas_object_smart_data_get(obj);
188    if (!sd->items) return NULL;
189    li = (E_Layout_Item*)sd->items->last;
190    return li->obj;
191 }
192 
193 E_API void
e_layout_child_resize(Evas_Object * obj,Evas_Coord w,Evas_Coord h)194 e_layout_child_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
195 {
196    E_Layout_Item *li;
197 
198    li = evas_object_data_get(obj, "e_layout_data");
199    if (!li) return;
200    if (w < 0) w = 0;
201    if (h < 0) h = 0;
202    if ((li->w == w) && (li->h == h)) return;
203    li->w = w;
204    li->h = h;
205    if (li->sd->frozen <= 0) _e_layout_smart_move_resize_item(li);
206 }
207 
208 E_API void
e_layout_child_lower(Evas_Object * obj)209 e_layout_child_lower(Evas_Object *obj)
210 {
211    E_Layout_Item *li;
212 
213    li = evas_object_data_get(obj, "e_layout_data");
214    if (!li) return;
215    if ((!li->sd->items) || (!EINA_INLIST_GET(li)->next)) return;
216    li->sd->items = eina_inlist_promote(li->sd->items, EINA_INLIST_GET(li));
217    evas_object_lower(obj);
218 }
219 
220 E_API void
e_layout_child_raise(Evas_Object * obj)221 e_layout_child_raise(Evas_Object *obj)
222 {
223    E_Layout_Item *li;
224 
225    li = evas_object_data_get(obj, "e_layout_data");
226    if (!li) return;
227    if ((!li->sd->items) || (!EINA_INLIST_GET(li)->prev)) return;
228    li->sd->items = eina_inlist_demote(li->sd->items, EINA_INLIST_GET(li));
229    evas_object_raise(obj);
230 }
231 
232 E_API void
e_layout_child_lower_below(Evas_Object * obj,Evas_Object * below)233 e_layout_child_lower_below(Evas_Object *obj, Evas_Object *below)
234 {
235    E_Layout_Item *li, *li2;
236 
237    EINA_SAFETY_ON_NULL_RETURN(obj);
238    EINA_SAFETY_ON_NULL_RETURN(below);
239    if (obj == below) return;
240    li = evas_object_data_get(obj, "e_layout_data");
241    li2 = evas_object_data_get(below, "e_layout_data");
242    if ((!li) || (!li2) || (li->sd != li2->sd)) return;
243    li->sd->items = eina_inlist_remove(li->sd->items, EINA_INLIST_GET(li));
244    evas_object_stack_below(obj, below);
245    li->sd->items = eina_inlist_prepend_relative(li->sd->items, EINA_INLIST_GET(li), EINA_INLIST_GET(li2));
246 }
247 
248 E_API void
e_layout_child_raise_above(Evas_Object * obj,Evas_Object * above)249 e_layout_child_raise_above(Evas_Object *obj, Evas_Object *above)
250 {
251    E_Layout_Item *li, *li2;
252 
253    EINA_SAFETY_ON_NULL_RETURN(obj);
254    EINA_SAFETY_ON_NULL_RETURN(above);
255    if (obj == above) return;
256    li = evas_object_data_get(obj, "e_layout_data");
257    li2 = evas_object_data_get(above, "e_layout_data");
258    if ((!li) || (!li2) || (li->sd != li2->sd)) return;
259    li->sd->items = eina_inlist_remove(li->sd->items, EINA_INLIST_GET(li));
260    evas_object_stack_above(obj, above);
261    li->sd->items = eina_inlist_append_relative(li->sd->items, EINA_INLIST_GET(li), EINA_INLIST_GET(li2));
262 }
263 
264 E_API void
e_layout_child_geometry_get(Evas_Object * obj,Evas_Coord * x,Evas_Coord * y,Evas_Coord * w,Evas_Coord * h)265 e_layout_child_geometry_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
266 {
267    E_Layout_Item *li;
268 
269    li = evas_object_data_get(obj, "e_layout_data");
270    if (!li) return;
271 
272    if (x) *x = li->x;
273    if (y) *y = li->y;
274    if (w) *w = li->w;
275    if (h) *h = li->h;
276 }
277 
278 E_API void
e_layout_unpack(Evas_Object * obj)279 e_layout_unpack(Evas_Object *obj)
280 {
281    E_Layout_Item *li;
282    E_Smart_Data *sd;
283 
284    li = evas_object_data_get(obj, "e_layout_data");
285    if (!li) return;
286    sd = li->sd;
287    sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(li));
288    _e_layout_smart_disown(obj);
289 }
290 
291 E_API Eina_List *
e_layout_children_get(Evas_Object * obj)292 e_layout_children_get(Evas_Object *obj)
293 {
294    E_Smart_Data *sd;
295    Eina_List *l = NULL;
296    E_Layout_Item *li;
297 
298    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR() NULL;
299    sd = evas_object_smart_data_get(obj);
300    EINA_INLIST_FOREACH(sd->items, li)
301      l = eina_list_append(l, li->obj);
302    return l;
303 }
304 
305 E_API Evas_Object *
e_layout_top_child_at_xy_get(Evas_Object * obj,Evas_Coord x,Evas_Coord y,Eina_Bool vis,const Eina_List * ignore)306 e_layout_top_child_at_xy_get(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Eina_Bool vis, const Eina_List *ignore)
307 {
308    E_Smart_Data *sd;
309    E_Layout_Item *li;
310 
311    if (evas_object_smart_smart_get(obj) != _e_smart) SMARTERRNR() NULL;
312    sd = evas_object_smart_data_get(obj);
313    if (!sd->items) return NULL;
314    EINA_INLIST_REVERSE_FOREACH(sd->items, li)
315      if (E_INSIDE(x, y, li->x, li->y, li->w, li->h))
316        {
317           if (eina_list_data_find(ignore, li->obj)) continue;
318           if ((!vis) || evas_object_visible_get(li->obj))
319             return li->obj;
320        }
321    return NULL;
322 }
323 
324 /* local subsystem functions */
325 static E_Layout_Item *
_e_layout_smart_adopt(E_Smart_Data * sd,Evas_Object * obj)326 _e_layout_smart_adopt(E_Smart_Data *sd, Evas_Object *obj)
327 {
328    E_Layout_Item *li;
329 
330    li = evas_object_data_get(obj, "e_layout_data");
331    if (li) e_layout_unpack(obj);
332    li = calloc(1, sizeof(E_Layout_Item));
333    if (!li) return NULL;
334    li->sd = sd;
335    li->obj = obj;
336    /* defaults */
337    li->x = 0;
338    li->y = 0;
339    li->w = 0;
340    li->h = 0;
341    evas_object_clip_set(obj, sd->clip);
342    evas_object_smart_member_add(obj, li->sd->obj);
343    evas_object_data_set(obj, "e_layout_data", li);
344    evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE,
345                                   _e_layout_smart_item_del_hook, NULL);
346    if ((!evas_object_visible_get(sd->clip)) &&
347        (evas_object_visible_get(sd->obj)))
348      evas_object_show(sd->clip);
349    return li;
350 }
351 
352 static void
_e_layout_smart_disown(Evas_Object * obj)353 _e_layout_smart_disown(Evas_Object *obj)
354 {
355    E_Layout_Item *li;
356 
357    li = evas_object_data_get(obj, "e_layout_data");
358    if (!li) return;
359    if (!li->sd->items)
360      {
361         if (evas_object_visible_get(li->sd->clip))
362           evas_object_hide(li->sd->clip);
363      }
364    evas_object_event_callback_del(obj,
365                                   EVAS_CALLBACK_FREE,
366                                   _e_layout_smart_item_del_hook);
367    evas_object_smart_member_del(obj);
368    evas_object_data_del(obj, "e_layout_data");
369    free(li);
370 }
371 
372 static void
_e_layout_smart_item_del_hook(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)373 _e_layout_smart_item_del_hook(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
374 {
375    e_layout_unpack(obj);
376 }
377 
378 static void
_e_layout_smart_reconfigure(E_Smart_Data * sd)379 _e_layout_smart_reconfigure(E_Smart_Data *sd)
380 {
381    E_Layout_Item *li;
382 
383    if (!sd->changed) return;
384 
385    EINA_INLIST_FOREACH(sd->items, li)
386      _e_layout_smart_move_resize_item(li);
387    sd->changed = 0;
388 }
389 
390 static void
_e_layout_smart_move_resize_item(E_Layout_Item * li)391 _e_layout_smart_move_resize_item(E_Layout_Item *li)
392 {
393    evas_object_move(li->obj,
394                     li->sd->x + ((li->x * li->sd->w) / li->sd->vw),
395                     li->sd->y + ((li->y * li->sd->h) / li->sd->vh));
396    evas_object_resize(li->obj,
397                       MAX((li->w * li->sd->w) / li->sd->vw, 1),
398                       MAX((li->h * li->sd->h) / li->sd->vh, 1));
399 }
400 
401 static void
_e_layout_smart_init(void)402 _e_layout_smart_init(void)
403 {
404    if (_e_smart) return;
405    {
406       static const Evas_Smart_Class sc =
407       {
408          "e_layout",
409          EVAS_SMART_CLASS_VERSION,
410          _e_layout_smart_add,
411          _e_layout_smart_del,
412          _e_layout_smart_move,
413          _e_layout_smart_resize,
414          _e_layout_smart_show,
415          _e_layout_smart_hide,
416          _e_layout_smart_color_set,
417          _e_layout_smart_clip_set,
418          _e_layout_smart_clip_unset,
419          NULL,
420          NULL,
421          NULL,
422          NULL,
423          NULL,
424          NULL,
425          NULL
426       };
427       _e_smart = evas_smart_class_new(&sc);
428    }
429 }
430 
431 static void
_e_layout_smart_add(Evas_Object * obj)432 _e_layout_smart_add(Evas_Object *obj)
433 {
434    E_Smart_Data *sd;
435 
436    sd = calloc(1, sizeof(E_Smart_Data));
437    if (!sd) return;
438    sd->obj = obj;
439    sd->x = 0;
440    sd->y = 0;
441    sd->w = 0;
442    sd->h = 0;
443    sd->vw = 1;
444    sd->vh = 1;
445    sd->clip = evas_object_rectangle_add(evas_object_evas_get(obj));
446    evas_object_smart_member_add(sd->clip, obj);
447    evas_object_move(sd->clip, -100001, -100001);
448    evas_object_resize(sd->clip, 200002, 200002);
449    evas_object_color_set(sd->clip, 255, 255, 255, 255);
450    evas_object_smart_data_set(obj, sd);
451 }
452 
453 static void
_e_layout_smart_del(Evas_Object * obj)454 _e_layout_smart_del(Evas_Object *obj)
455 {
456    E_Smart_Data *sd;
457 
458    sd = evas_object_smart_data_get(obj);
459    if (!sd) return;
460    while (sd->items)
461      {
462         E_Layout_Item *li = (E_Layout_Item*)sd->items;
463         sd->items = eina_inlist_remove(sd->items, EINA_INLIST_GET(li));
464         _e_layout_smart_disown(li->obj);
465      }
466    evas_object_del(sd->clip);
467    free(sd);
468 }
469 
470 static void
_e_layout_smart_move(Evas_Object * obj,Evas_Coord x,Evas_Coord y)471 _e_layout_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
472 {
473    E_Smart_Data *sd;
474    E_Layout_Item *li;
475    Evas_Coord dx, dy;
476 
477    sd = evas_object_smart_data_get(obj);
478    if (!sd) return;
479    if ((x == sd->x) && (y == sd->y)) return;
480    dx = x - sd->x;
481    dy = y - sd->y;
482    EINA_INLIST_FOREACH(sd->items, li)
483      {
484         Evas_Coord ox, oy;
485 
486         evas_object_geometry_get(li->obj, &ox, &oy, NULL, NULL);
487         evas_object_move(li->obj, ox + dx, oy + dy);
488      }
489    sd->x = x;
490    sd->y = y;
491 }
492 
493 static void
_e_layout_smart_resize(Evas_Object * obj,Evas_Coord w,Evas_Coord h)494 _e_layout_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
495 {
496    E_Smart_Data *sd;
497 
498    sd = evas_object_smart_data_get(obj);
499    if (!sd) return;
500    if ((w == sd->w) && (h == sd->h)) return;
501    sd->w = w;
502    sd->h = h;
503    sd->changed = 1;
504    if (sd->frozen <= 0) _e_layout_smart_reconfigure(sd);
505 }
506 
507 static void
_e_layout_smart_show(Evas_Object * obj)508 _e_layout_smart_show(Evas_Object *obj)
509 {
510    E_Smart_Data *sd;
511 
512    sd = evas_object_smart_data_get(obj);
513    if (!sd) return;
514    if (sd->items) evas_object_show(sd->clip);
515 }
516 
517 static void
_e_layout_smart_hide(Evas_Object * obj)518 _e_layout_smart_hide(Evas_Object *obj)
519 {
520    E_Smart_Data *sd;
521 
522    sd = evas_object_smart_data_get(obj);
523    if (!sd) return;
524    evas_object_hide(sd->clip);
525 }
526 
527 static void
_e_layout_smart_color_set(Evas_Object * obj,int r,int g,int b,int a)528 _e_layout_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
529 {
530    E_Smart_Data *sd;
531 
532    sd = evas_object_smart_data_get(obj);
533    if (!sd) return;
534    evas_object_color_set(sd->clip, r, g, b, a);
535 }
536 
537 static void
_e_layout_smart_clip_set(Evas_Object * obj,Evas_Object * clip)538 _e_layout_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
539 {
540    E_Smart_Data *sd;
541 
542    sd = evas_object_smart_data_get(obj);
543    if (!sd) return;
544    evas_object_clip_set(sd->clip, clip);
545 }
546 
547 static void
_e_layout_smart_clip_unset(Evas_Object * obj)548 _e_layout_smart_clip_unset(Evas_Object *obj)
549 {
550    E_Smart_Data *sd;
551 
552    sd = evas_object_smart_data_get(obj);
553    if (!sd) return;
554    evas_object_clip_unset(sd->clip);
555 }
556 
557