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