1 #include "efl_ui_relative_container_private.h"
2 
3 #define MY_CLASS EFL_UI_RELATIVE_CONTAINER_CLASS
4 #define MY_CLASS_NAME "Efl.Ui.Relative_Container"
5 
6 #define LEFT               0
7 #define RIGHT              1
8 #define TOP                2
9 #define BOTTOM             3
10 
11 #define START              (axis ? TOP : LEFT)
12 #define END                (axis ? BOTTOM : RIGHT)
13 
14 static void _child_calc(Efl_Ui_Relative_Container_Child *child, Eina_Bool axis);
15 
16 static int
_chain_sort_cb(const void * l1,const void * l2)17 _chain_sort_cb(const void *l1, const void *l2)
18 {
19    Efl_Ui_Relative_Container_Calc *calc1, *calc2;
20 
21    calc1 = EINA_INLIST_CONTAINER_GET(l1, Efl_Ui_Relative_Container_Calc);
22    calc2 = EINA_INLIST_CONTAINER_GET(l2, Efl_Ui_Relative_Container_Calc);
23 
24    return calc2->comp_factor <= calc1->comp_factor ? -1 : 1;
25 }
26 
27 static void
_on_child_size_changed(void * data,const Efl_Event * event EINA_UNUSED)28 _on_child_size_changed(void *data, const Efl_Event *event EINA_UNUSED)
29 {
30    Efl_Ui_Relative_Container *obj = data;
31 
32    efl_pack_layout_request(obj);
33 }
34 
35 static void
_on_child_hints_changed(void * data,const Efl_Event * event EINA_UNUSED)36 _on_child_hints_changed(void *data, const Efl_Event *event EINA_UNUSED)
37 {
38    Efl_Ui_Relative_Container *obj = data;
39 
40    efl_pack_layout_request(obj);
41 }
42 
43 static void
_on_child_del(void * data,const Efl_Event * event)44 _on_child_del(void *data, const Efl_Event *event)
45 {
46    Efl_Ui_Relative_Container *obj = data;
47 
48    efl_pack_unpack(obj, event->object);
49 }
50 
51 EFL_CALLBACKS_ARRAY_DEFINE(efl_ui_relative_container_callbacks,
52   { EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _on_child_size_changed },
53   { EFL_GFX_ENTITY_EVENT_HINTS_CHANGED, _on_child_hints_changed },
54   { EFL_EVENT_DEL, _on_child_del }
55 );
56 
57 static Efl_Ui_Relative_Container_Child *
_efl_ui_relative_container_register(Efl_Ui_Relative_Container_Data * pd,Eo * child)58 _efl_ui_relative_container_register(Efl_Ui_Relative_Container_Data *pd, Eo *child)
59 {
60    Efl_Ui_Relative_Container_Child *rc;
61 
62    if (!efl_ui_widget_sub_object_add(pd->obj, child))
63      return NULL;
64 
65    rc = calloc(1, sizeof(Efl_Ui_Relative_Container_Child));
66    if (!rc) return NULL;
67 
68    rc->obj = child;
69    rc->layout = pd->obj;
70    rc->rel[LEFT].to = rc->layout;
71    rc->rel[LEFT].relative_position = 0.0;
72    rc->rel[RIGHT].to = rc->layout;
73    rc->rel[RIGHT].relative_position = 1.0;
74    rc->rel[TOP].to = rc->layout;
75    rc->rel[TOP].relative_position = 0.0;
76    rc->rel[BOTTOM].to = rc->layout;
77    rc->rel[BOTTOM].relative_position = 1.0;
78 
79    efl_key_data_set(child, "_elm_leaveme", pd->obj);
80    efl_canvas_object_clipper_set(child, pd->clipper);
81    efl_event_callback_array_add(child, efl_ui_relative_container_callbacks(), pd->obj);
82    efl_canvas_group_member_add(pd->obj, child);
83    efl_canvas_group_change(pd->obj);
84 
85    eina_hash_add(pd->children, &child, rc);
86 
87    return rc;
88 }
89 
90 static Efl_Ui_Relative_Container_Child *
_relative_child_get(Efl_Ui_Relative_Container_Data * pd,Eo * child)91 _relative_child_get(Efl_Ui_Relative_Container_Data *pd, Eo *child)
92 {
93    Efl_Ui_Relative_Container_Child *rc;
94 
95    rc = eina_hash_find(pd->children, &child);
96    if (!rc)
97      rc = _efl_ui_relative_container_register(pd, child);
98 
99    return rc;
100 }
101 
102 static Efl_Ui_Relative_Container_Child *
_relative_child_find(Efl_Ui_Relative_Container_Data * pd,Eo * target)103 _relative_child_find(Efl_Ui_Relative_Container_Data *pd, Eo *target)
104 {
105    Efl_Ui_Relative_Container_Child *child;
106 
107    if (pd->obj == target)
108      return pd->base;
109 
110    child = eina_hash_find(pd->children, &target);
111    if (!child)
112      {
113         ERR("target(%p(%s)) is not registered", target, efl_class_name_get(target));
114         child = pd->base;
115      }
116 
117    return child;
118 }
119 
120 static void
_child_aspect_calc(Efl_Ui_Relative_Container_Child * child,Eina_Bool axis)121 _child_aspect_calc(Efl_Ui_Relative_Container_Child *child, Eina_Bool axis)
122 {
123    Efl_Ui_Relative_Container_Calc *calc = &child->calc;
124    double temph;
125 
126    if ((calc->aspect[0] <= 0) || (calc->aspect[1] <= 0))
127      {
128         ERR("Invalid aspect parameter for obj(%p), aspect(%d, %d) ",
129             child->obj, calc->aspect[0], calc->aspect[1]);
130         return;
131      }
132 
133    switch (calc->aspect_type)
134      {
135       case EFL_GFX_HINT_ASPECT_HORIZONTAL:
136         if (axis) _child_calc(child, !axis);
137         calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0];
138         break;
139       case EFL_GFX_HINT_ASPECT_VERTICAL:
140         if (!axis) _child_calc(child, !axis);
141         calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1];
142         break;
143       case EFL_GFX_HINT_ASPECT_BOTH:
144         if (calc->state[!axis] != RELATIVE_CALC_ON)
145           _child_calc(child, !axis);
146         temph = calc->want[axis].length * calc->aspect[!axis] / calc->aspect[axis];
147         if (temph > calc->want[!axis].length)
148           {
149              temph = calc->want[!axis].length;
150              calc->want[axis].length = temph * calc->aspect[axis] / calc->aspect[!axis];
151           }
152         else
153           calc->want[!axis].length = temph;
154         break;
155       default:
156         if (calc->state[!axis] != RELATIVE_CALC_ON)
157           _child_calc(child, !axis);
158         temph = calc->want[axis].length * calc->aspect[!axis] / calc->aspect[axis];
159         if (temph < calc->want[!axis].length)
160           {
161              temph = calc->want[!axis].length;
162              calc->want[axis].length = temph * calc->aspect[axis] / calc->aspect[!axis];
163           }
164         else
165           calc->want[!axis].length = temph;
166      }
167 
168    //calculate max size
169    if (calc->want[0].length > calc->max[0])
170      {
171         calc->want[0].length = calc->max[0];
172         calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0];
173      }
174    if (calc->want[1].length > calc->max[1])
175      {
176         calc->want[1].length = calc->max[1];
177         calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1];
178      }
179    //calculate min size
180    if (calc->aspect[1] > calc->aspect[0])
181      calc->min[1] = calc->min[0] * calc->aspect[1] / calc->aspect[0];
182    else
183      calc->min[0] = calc->min[1] * calc->aspect[0] / calc->aspect[1];
184 
185    if (calc->want[0].length < calc->min[0])
186      {
187         calc->want[0].length = calc->min[0];
188         calc->want[1].length = calc->want[0].length * calc->aspect[1] / calc->aspect[0];
189      }
190    if (calc->want[1].length < calc->min[1])
191      {
192         calc->want[1].length = calc->min[1];
193         calc->want[0].length = calc->want[1].length * calc->aspect[0] / calc->aspect[1];
194      }
195 
196    //calculate align
197    calc->want[!axis].position =
198       calc->space[!axis].position +
199       (calc->space[!axis].length - calc->want[!axis].length) * calc->align[!axis];
200 }
201 
202 static Eina_Bool
_child_chain_calc(Efl_Ui_Relative_Container_Child * child,Eina_Bool axis)203 _child_chain_calc(Efl_Ui_Relative_Container_Child *child, Eina_Bool axis)
204 {
205    Efl_Ui_Relative_Container_Child *head, *tail, *o;
206    Efl_Gfx_Hint_Aspect aspect_type;
207    int space, min_sum = 0;
208    double weight_sum = 0, cur_pos;
209    Eina_Inlist *chain = NULL;
210 
211    if (child->calc.chain_state[axis] == RELATIVE_CALC_DONE)
212      return EINA_TRUE;
213 
214    if ((child != child->calc.to[START]->calc.to[END]) &&
215        (child != child->calc.to[END]->calc.to[START]))
216      return EINA_FALSE;
217 
218    // find head
219    head = child;
220    while (head == head->calc.to[START]->calc.to[END])
221      {
222         head = head->calc.to[START];
223         if (head == child)
224           {
225              ERR("%c-axis circular dependency when calculating \"%s\"(%p).",
226                  axis ? 'Y' : 'X', efl_class_name_get(child->obj), child->obj);
227              return EINA_TRUE;
228           }
229      }
230 
231    //calculate weight_sum
232    aspect_type = !axis ? EFL_GFX_HINT_ASPECT_VERTICAL : EFL_GFX_HINT_ASPECT_HORIZONTAL;
233    o = head;
234    do
235      {
236         if ((o->calc.aspect[0] > 0) && (o->calc.aspect[1] > 0) &&
237             (o->calc.aspect_type == aspect_type))
238           {
239              _child_calc(o, !axis);
240              if (o->calc.want[axis].length > o->calc.min[axis])
241                o->calc.min[axis] = o->calc.want[axis].length;
242           }
243         else if ((o->calc.aspect[0] <= 0) ^ (o->calc.aspect[1] <= 0))
244           {
245              ERR("Invalid aspect parameter for obj(%p), aspect(%d, %d) ",
246                  o->obj, o->calc.aspect[0], o->calc.aspect[1]);
247           }
248 
249         o->calc.space[axis].length = o->calc.min[axis] +
250                                      o->calc.margin[START] + o->calc.margin[END];
251         min_sum += o->calc.space[axis].length;
252         weight_sum += o->calc.weight[axis];
253 
254         tail = o;
255         o = o->calc.to[END];
256      }
257    while (o->calc.to[START] == tail);
258 
259    _child_calc(head->calc.to[START], axis);
260    _child_calc(tail->calc.to[END], axis);
261 
262    cur_pos = head->calc.to[START]->calc.want[axis].position +
263              (head->calc.to[START]->calc.want[axis].length * head->rel[START].relative_position);
264    space = tail->calc.to[END]->calc.want[axis].position +
265            (tail->calc.to[END]->calc.want[axis].length * tail->rel[END].relative_position) - cur_pos;
266 
267    if ((space <= min_sum) || EINA_DBL_EQ(weight_sum, 0.0))
268      cur_pos += (space - min_sum) * head->calc.align[axis];
269    else
270      {
271         Efl_Ui_Relative_Container_Calc *calc;
272         double weight_len, orig_space = space, orig_weight = weight_sum;
273 
274         // Calculate compare factor
275         for (o = head; o != tail->calc.to[END]; o = o->calc.to[END])
276           {
277              double denom;
278 
279              calc = &o->calc;
280              denom = (calc->weight[axis] * orig_space) - (orig_weight * calc->min[axis]);
281              if (denom > 0)
282                {
283                   calc->comp_factor = (calc->weight[axis] * orig_space) / denom;
284                   chain = eina_inlist_sorted_insert(chain, EINA_INLIST_GET(calc),
285                                                     _chain_sort_cb);
286                }
287              else
288                {
289                   space -= calc->space[axis].length;
290                   weight_sum -= calc->weight[axis];
291                }
292           }
293 
294         EINA_INLIST_FOREACH(chain, calc)
295           {
296              weight_len = (space * calc->weight[axis]) / weight_sum;
297 
298              if (calc->space[axis].length < weight_len)
299                calc->space[axis].length = weight_len;
300              else
301                {
302                   weight_sum -= calc->weight[axis];
303                   space -= calc->space[axis].length;
304                }
305           }
306      }
307 
308    for (o = head; o != tail->calc.to[END]; o = o->calc.to[END])
309      {
310         o->calc.space[axis].position = cur_pos + o->calc.margin[START] + 0.5;
311         cur_pos += o->calc.space[axis].length;
312         o->calc.space[axis].length -= o->calc.margin[START] + o->calc.margin[END];
313         o->calc.chain_state[axis] = RELATIVE_CALC_DONE;
314         child->calc.m0[axis] += o->calc.min[axis];
315      }
316 
317    child->calc.mi[axis] = head->rel[START].relative_position * (head->calc.to[START]->calc.mj[axis] -
318                     head->calc.to[START]->calc.mi[axis]) + head->calc.to[START]->calc.mi[axis];
319    child->calc.mj[axis] = tail->rel[END].relative_position * (tail->calc.to[END]->calc.mj[axis] -
320                     tail->calc.to[END]->calc.mi[axis]) + tail->calc.to[END]->calc.mi[axis];
321    child->calc.m0[axis] += -child->calc.min[axis] +
322             (head->calc.to[START]->calc.m0[axis] * head->rel[START].relative_position) +
323             (tail->calc.to[END]->calc.m0[axis] * (1 - tail->rel[END].relative_position));
324 
325    return EINA_TRUE;
326 }
327 
328 static void
_child_calc(Efl_Ui_Relative_Container_Child * child,Eina_Bool axis)329 _child_calc(Efl_Ui_Relative_Container_Child *child, Eina_Bool axis)
330 {
331    Efl_Ui_Relative_Container_Calc *calc = &child->calc;
332 
333    if (calc->state[axis] == RELATIVE_CALC_DONE)
334      return;
335 
336    if (calc->state[axis] == RELATIVE_CALC_ON)
337      {
338         ERR("%c-axis circular dependency when calculating part \"%s\"(%p).",
339             axis ? 'Y' : 'X', efl_class_name_get(child->obj), child->obj);
340         return;
341      }
342 
343    calc->state[axis] = RELATIVE_CALC_ON;
344 
345    if (!_child_chain_calc(child, axis))
346      {
347         _child_calc(calc->to[START], axis);
348         _child_calc(calc->to[END], axis);
349 
350         calc->space[axis].position = calc->to[START]->calc.want[axis].position
351                         + (calc->to[START]->calc.want[axis].length * child->rel[START].relative_position)
352                         + calc->margin[START];
353         calc->space[axis].length = calc->to[END]->calc.want[axis].position
354                         + (calc->to[END]->calc.want[axis].length * child->rel[END].relative_position)
355                         - calc->margin[END] - calc->space[axis].position;
356      }
357 
358    if (calc->fill[axis] && (calc->weight[axis] > 0))
359      calc->want[axis].length = calc->space[axis].length;
360 
361    if (!calc->aspect[0] && !calc->aspect[1])
362      {
363         if (calc->want[axis].length > calc->max[axis])
364           calc->want[axis].length = calc->max[axis];
365 
366         if (calc->want[axis].length < calc->min[axis])
367           calc->want[axis].length = calc->min[axis];
368      }
369    else
370      {
371         _child_aspect_calc(child, axis);
372      }
373 
374    //calculate align
375    calc->want[axis].position =
376       calc->space[axis].position +
377       (calc->space[axis].length - calc->want[axis].length) * calc->align[axis];
378 
379    child->calc.state[axis] = RELATIVE_CALC_DONE;
380    if (child->calc.chain_state[axis] == RELATIVE_CALC_DONE)
381      return;
382 
383    //calculate relative layout min
384    calc->mi[axis] = child->rel[START].relative_position * (calc->to[START]->calc.mj[axis] -
385                     calc->to[START]->calc.mi[axis]) + calc->to[START]->calc.mi[axis];
386    calc->mj[axis] = child->rel[END].relative_position * (calc->to[END]->calc.mj[axis] -
387                     calc->to[END]->calc.mi[axis]) + calc->to[END]->calc.mi[axis];
388    calc->m0[axis] = calc->to[START]->calc.m0[axis] * child->rel[START].relative_position;
389 
390    if ((calc->to[START] == calc->to[END]) &&
391        EINA_DBL_EQ(child->rel[START].relative_position, child->rel[END].relative_position))
392      {
393         double r, a; // relative, align
394         r = calc->mi[axis] +
395            (child->rel[START].relative_position * (calc->mj[axis] - calc->mi[axis]));
396         a = calc->align[axis];
397         calc->m0[axis] += (calc->min[axis] + calc->margin[START] + calc->margin[END]) *
398            ((EINA_DBL_EQ(r, 0.0) || (!EINA_DBL_EQ(r, 1.0) && (a < r))) ?
399             ((1 - a) / (1 - r)) : (a / r));
400      }
401    else
402      {
403         calc->m0[axis] += calc->to[END]->calc.m0[axis] * (1 - child->rel[END].relative_position);
404      }
405 
406 }
407 
408 static void
_hash_free_cb(void * data)409 _hash_free_cb(void *data)
410 {
411    Efl_Ui_Relative_Container_Child *child = data;
412 
413    efl_canvas_group_member_remove(child->layout, child->obj);
414    efl_canvas_object_clipper_set(child->obj, NULL);
415    efl_key_data_set(child->obj, "_elm_leaveme", NULL);
416    efl_event_callback_array_del(child->obj, efl_ui_relative_container_callbacks(),
417                                 child->layout);
418 
419    if (!efl_invalidated_get(child->obj))
420      _elm_widget_sub_object_redirect_to_top(child->layout, child->obj);
421 
422    free(child);
423 }
424 
425 static void
_hash_clear_cb(void * data)426 _hash_clear_cb(void *data)
427 {
428    Efl_Ui_Relative_Container_Child *child = data;
429 
430    efl_event_callback_array_del(child->obj, efl_ui_relative_container_callbacks(),
431                                 child->layout);
432    efl_del(child->obj);
433 }
434 
435 static Eina_Bool
_hash_child_calc_foreach_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)436 _hash_child_calc_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
437                             void *data, void *fdata)
438 {
439    Efl_Ui_Relative_Container_Child *child = data;
440    Efl_Ui_Relative_Container_Calc *calc = &(child->calc);
441    Efl_Ui_Relative_Container_Data *pd = fdata;
442    Eina_Rect want;
443    int axis, layout_min;
444    double min_len;
445 
446    _child_calc(child, 0);
447    _child_calc(child, 1);
448 
449    want.x = calc->want[0].position;
450    want.w = calc->want[0].length;
451    want.y = calc->want[1].position;
452    want.h = calc->want[1].length;
453 
454    for (axis = 0; axis < 2; axis++)
455      {
456         layout_min = 0;
457         min_len = calc->mj[axis] - calc->mi[axis];
458         if (EINA_DBL_EQ(min_len, 0.0))
459           layout_min = calc->m0[axis];
460         else
461           layout_min = ((calc->min[axis] + calc->margin[START] +
462                    calc->margin[END] + calc->m0[axis]) / fabs(min_len)) + 0.5;
463 
464         if (pd->base->calc.min[axis] < layout_min)
465           pd->base->calc.min[axis] = layout_min;
466      }
467 
468    efl_gfx_entity_geometry_set(child->obj, want);
469    return EINA_TRUE;
470 }
471 
472 
473 static Eina_Bool
_hash_child_init_foreach_cb(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)474 _hash_child_init_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED,
475                             void *data, void *fdata)
476 {
477    Eina_Size2D max, min, aspect;
478    Efl_Ui_Relative_Container_Child *child = data;
479    Efl_Ui_Relative_Container_Calc *calc = &(child->calc);
480    Efl_Ui_Relative_Container_Data *pd = fdata;
481 
482    calc->to[LEFT] = _relative_child_find(pd, child->rel[LEFT].to);
483    calc->to[RIGHT] = _relative_child_find(pd, child->rel[RIGHT].to);
484    calc->to[TOP] = _relative_child_find(pd, child->rel[TOP].to);
485    calc->to[BOTTOM] = _relative_child_find(pd, child->rel[BOTTOM].to);
486 
487    calc->state[0] = RELATIVE_CALC_NONE;
488    calc->state[1] = RELATIVE_CALC_NONE;
489    calc->chain_state[0] = RELATIVE_CALC_NONE;
490    calc->chain_state[1] = RELATIVE_CALC_NONE;
491 
492    efl_gfx_hint_weight_get(child->obj, &calc->weight[0], &calc->weight[1]);
493    efl_gfx_hint_align_get(child->obj, &calc->align[0], &calc->align[1]);
494    efl_gfx_hint_fill_get(child->obj, &calc->fill[0], &calc->fill[1]);
495    efl_gfx_hint_aspect_get(child->obj, &calc->aspect_type, &aspect);
496    calc->aspect[0] = aspect.w;
497    calc->aspect[1] = aspect.h;
498    efl_gfx_hint_margin_get(child->obj, &calc->margin[LEFT], &calc->margin[RIGHT],
499                            &calc->margin[TOP], &calc->margin[BOTTOM]);
500    max = efl_gfx_hint_size_combined_max_get(child->obj);
501    min = efl_gfx_hint_size_combined_min_get(child->obj);
502    calc->max[0] = max.w;
503    calc->max[1] = max.h;
504    calc->min[0] = min.w;
505    calc->min[1] = min.h;
506    calc->m0[0] = 0.0;
507    calc->m0[1] = 0.0;
508 
509    calc->want[0].position = 0;
510    calc->want[0].length = 0;
511    calc->want[1].position = 0;
512    calc->want[1].length = 0;
513    calc->space[0].position = 0;
514    calc->space[0].length = 0;
515    calc->space[1].position = 0;
516    calc->space[1].length = 0;
517 
518    if (calc->weight[0] < 0) calc->weight[0] = 0;
519    if (calc->weight[1] < 0) calc->weight[1] = 0;
520 
521    if (calc->align[0] < 0) calc->align[0] = 0;
522    if (calc->align[1] < 0) calc->align[1] = 0;
523    if (calc->align[0] > 1) calc->align[0] = 1;
524    if (calc->align[1] > 1) calc->align[1] = 1;
525 
526    if (calc->max[0] < 0) calc->max[0] = INT_MAX;
527    if (calc->max[1] < 0) calc->max[1] = INT_MAX;
528    if (calc->aspect[0] < 0) calc->aspect[0] = 0;
529    if (calc->aspect[1] < 0) calc->aspect[1] = 0;
530 
531    return EINA_TRUE;
532 }
533 
534 static void
_efl_ui_relative_container_hints_changed_cb(void * data EINA_UNUSED,const Efl_Event * ev)535 _efl_ui_relative_container_hints_changed_cb(void *data EINA_UNUSED, const Efl_Event *ev)
536 {
537    efl_pack_layout_request(ev->object);
538 }
539 
540 EOLIAN static void
_efl_ui_relative_container_efl_pack_layout_layout_update(Eo * obj,Efl_Ui_Relative_Container_Data * pd)541 _efl_ui_relative_container_efl_pack_layout_layout_update(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
542 {
543    Eina_Rect want = efl_gfx_entity_geometry_get(obj);
544    pd->base->calc.want[0].position = want.x;
545    pd->base->calc.want[0].length = want.w;
546    pd->base->calc.want[1].position = want.y;
547    pd->base->calc.want[1].length = want.h;
548    pd->base->calc.min[0] = 0;
549    pd->base->calc.min[1] = 0;
550 
551    eina_hash_foreach(pd->children, _hash_child_init_foreach_cb, pd);
552    eina_hash_foreach(pd->children, _hash_child_calc_foreach_cb, pd);
553 
554    efl_gfx_hint_size_restricted_min_set(obj, EINA_SIZE2D(pd->base->calc.min[0], pd->base->calc.min[1]));
555 
556    efl_event_callback_call(obj, EFL_PACK_EVENT_LAYOUT_UPDATED, NULL);
557 }
558 
559 EOLIAN static void
_efl_ui_relative_container_efl_pack_layout_layout_request(Eo * obj,Efl_Ui_Relative_Container_Data * pd EINA_UNUSED)560 _efl_ui_relative_container_efl_pack_layout_layout_request(Eo *obj, Efl_Ui_Relative_Container_Data *pd EINA_UNUSED)
561 {
562    efl_canvas_group_need_recalculate_set(obj, EINA_TRUE);
563 }
564 
565 EOLIAN static void
_efl_ui_relative_container_efl_canvas_group_group_calculate(Eo * obj,Efl_Ui_Relative_Container_Data * pd EINA_UNUSED)566 _efl_ui_relative_container_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Relative_Container_Data *pd EINA_UNUSED)
567 {
568    efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
569    efl_pack_layout_update(obj);
570 }
571 
572 EOLIAN static void
_efl_ui_relative_container_efl_gfx_entity_size_set(Eo * obj,Efl_Ui_Relative_Container_Data * pd EINA_UNUSED,Eina_Size2D sz)573 _efl_ui_relative_container_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Relative_Container_Data *pd EINA_UNUSED, Eina_Size2D sz)
574 {
575    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz);
576    efl_canvas_group_change(obj);
577 }
578 
579 EOLIAN static void
_efl_ui_relative_container_efl_gfx_entity_position_set(Eo * obj,Efl_Ui_Relative_Container_Data * pd EINA_UNUSED,Eina_Position2D pos)580 _efl_ui_relative_container_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Relative_Container_Data *pd EINA_UNUSED, Eina_Position2D pos)
581 {
582    efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
583    efl_canvas_group_change(obj);
584 }
585 
586 EOLIAN static void
_efl_ui_relative_container_efl_canvas_group_group_add(Eo * obj,Efl_Ui_Relative_Container_Data * pd EINA_UNUSED)587 _efl_ui_relative_container_efl_canvas_group_group_add(Eo *obj, Efl_Ui_Relative_Container_Data *pd EINA_UNUSED)
588 {
589    pd->clipper = efl_add(EFL_CANVAS_RECTANGLE_CLASS, obj);
590    evas_object_static_clip_set(pd->clipper, EINA_TRUE);
591    efl_gfx_entity_geometry_set(pd->clipper, EINA_RECT(-49999, -49999, 99999, 99999));
592    efl_canvas_group_member_add(obj, pd->clipper);
593    efl_ui_widget_sub_object_add(obj, pd->clipper);
594 
595    efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED,
596                           _efl_ui_relative_container_hints_changed_cb, NULL);
597    efl_canvas_group_add(efl_super(obj, MY_CLASS));
598 
599    elm_widget_highlight_ignore_set(obj, EINA_TRUE);
600 }
601 
602 EOLIAN static Eo *
_efl_ui_relative_container_efl_object_constructor(Eo * obj,Efl_Ui_Relative_Container_Data * pd)603 _efl_ui_relative_container_efl_object_constructor(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
604 {
605    obj = efl_constructor(efl_super(obj, MY_CLASS));
606    efl_canvas_object_type_set(obj, MY_CLASS_NAME);
607    efl_access_object_access_type_set(obj, EFL_ACCESS_TYPE_SKIPPED);
608    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_FILLER);
609 
610    pd->obj = obj;
611    pd->children = eina_hash_pointer_new(_hash_free_cb);
612 
613    pd->base = calloc(1, sizeof(Efl_Ui_Relative_Container_Child));
614    if (!pd->base) return NULL;
615 
616    pd->base->obj = obj;
617    pd->base->layout = obj;
618    pd->base->rel[LEFT].to = obj;
619    pd->base->rel[LEFT].relative_position = 0.0;
620    pd->base->rel[RIGHT].to = obj;
621    pd->base->rel[RIGHT].relative_position = 1.0;
622    pd->base->rel[TOP].to = obj;
623    pd->base->rel[TOP].relative_position = 0.0;
624    pd->base->rel[BOTTOM].to = obj;
625    pd->base->rel[BOTTOM].relative_position = 1.0;
626    pd->base->calc.mi[0] = pd->base->calc.mi[1] = 0.0;
627    pd->base->calc.mj[0] = pd->base->calc.mj[1] = 1.0;
628    pd->base->calc.state[0] = RELATIVE_CALC_DONE;
629    pd->base->calc.state[1] = RELATIVE_CALC_DONE;
630    pd->base->calc.chain_state[0] = RELATIVE_CALC_DONE;
631    pd->base->calc.chain_state[1] = RELATIVE_CALC_DONE;
632 
633    return obj;
634 }
635 
636 EOLIAN static void
_efl_ui_relative_container_efl_object_invalidate(Eo * obj,Efl_Ui_Relative_Container_Data * pd)637 _efl_ui_relative_container_efl_object_invalidate(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
638 {
639    efl_invalidate(efl_super(obj, MY_CLASS));
640 
641    eina_hash_free_buckets(pd->children);
642 }
643 
644 EOLIAN static void
_efl_ui_relative_container_efl_object_destructor(Eo * obj,Efl_Ui_Relative_Container_Data * pd)645 _efl_ui_relative_container_efl_object_destructor(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
646 {
647    efl_event_callback_del(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED,
648                           _efl_ui_relative_container_hints_changed_cb, NULL);
649    eina_hash_free(pd->children);
650    if (pd->base) free(pd->base);
651    efl_destructor(efl_super(obj, MY_CLASS));
652 }
653 
654 EOLIAN static Eina_Bool
_efl_ui_relative_container_efl_pack_pack(Eo * obj EINA_UNUSED,Efl_Ui_Relative_Container_Data * pd,Efl_Gfx_Entity * subobj)655 _efl_ui_relative_container_efl_pack_pack(Eo *obj EINA_UNUSED, Efl_Ui_Relative_Container_Data *pd, Efl_Gfx_Entity *subobj)
656 {
657    EINA_SAFETY_ON_FALSE_RETURN_VAL(subobj, EINA_FALSE);
658    EINA_SAFETY_ON_TRUE_RETURN_VAL(!!eina_hash_find(pd->children, &subobj), EINA_FALSE);
659 
660    return !!_efl_ui_relative_container_register(pd, subobj);
661 }
662 
663 EOLIAN static Eina_Bool
_efl_ui_relative_container_efl_pack_unpack(Eo * obj,Efl_Ui_Relative_Container_Data * pd,Efl_Object * child)664 _efl_ui_relative_container_efl_pack_unpack(Eo *obj, Efl_Ui_Relative_Container_Data *pd, Efl_Object *child)
665 {
666    if (!eina_hash_del_by_key(pd->children, &child))
667      {
668         ERR("child(%p(%s)) is not registered", child, efl_class_name_get(child));
669         return EINA_FALSE;
670      }
671 
672    efl_pack_layout_request(obj);
673 
674    return EINA_TRUE;
675 }
676 
677 EOLIAN static Eina_Bool
_efl_ui_relative_container_efl_pack_unpack_all(Eo * obj,Efl_Ui_Relative_Container_Data * pd)678 _efl_ui_relative_container_efl_pack_unpack_all(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
679 {
680    eina_hash_free_buckets(pd->children);
681    efl_pack_layout_request(obj);
682 
683    return EINA_TRUE;
684 }
685 
686 EOLIAN static Eina_Bool
_efl_ui_relative_container_efl_pack_pack_clear(Eo * obj,Efl_Ui_Relative_Container_Data * pd)687 _efl_ui_relative_container_efl_pack_pack_clear(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
688 {
689    eina_hash_free_cb_set(pd->children, _hash_clear_cb);
690    eina_hash_free_buckets(pd->children);
691    eina_hash_free_cb_set(pd->children, _hash_free_cb);
692 
693    efl_pack_layout_request(obj);
694 
695    return EINA_TRUE;
696 }
697 
698 static Eina_Bool
_efl_ui_relative_container_content_iterator_next(Efl_Ui_Relative_Container_Content_Iterator * it,void ** data)699 _efl_ui_relative_container_content_iterator_next(Efl_Ui_Relative_Container_Content_Iterator *it, void **data)
700 {
701    Efl_Ui_Relative_Container_Child *child;
702 
703    if (!eina_iterator_next(it->real_iterator, (void **) &child))
704      return EINA_FALSE;
705 
706    if (data) *data = child->obj;
707    return EINA_TRUE;
708 }
709 
710 static Eo *
_efl_ui_relative_container_content_iterator_get_container(Efl_Ui_Relative_Container_Content_Iterator * it)711 _efl_ui_relative_container_content_iterator_get_container(Efl_Ui_Relative_Container_Content_Iterator *it)
712 {
713    return it->relative_container;
714 }
715 
716 static void
_efl_ui_relative_container_content_iterator_free(Efl_Ui_Relative_Container_Content_Iterator * it)717 _efl_ui_relative_container_content_iterator_free(Efl_Ui_Relative_Container_Content_Iterator *it)
718 {
719    eina_iterator_free(it->real_iterator);
720    free(it);
721 }
722 
723 EOLIAN static Eina_Iterator *
_efl_ui_relative_container_efl_container_content_iterate(Eo * obj,Efl_Ui_Relative_Container_Data * pd)724 _efl_ui_relative_container_efl_container_content_iterate(Eo *obj, Efl_Ui_Relative_Container_Data *pd)
725 {
726    Efl_Ui_Relative_Container_Content_Iterator *it;
727 
728    it = calloc(1, sizeof(*it));
729    if (!it) return NULL;
730 
731    EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
732 
733    it->relative_container = obj;
734    it->real_iterator = eina_hash_iterator_data_new(pd->children);
735 
736    it->iterator.version = EINA_ITERATOR_VERSION;
737    it->iterator.next = FUNC_ITERATOR_NEXT(_efl_ui_relative_container_content_iterator_next);
738    it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
739      _efl_ui_relative_container_content_iterator_get_container);
740    it->iterator.free = FUNC_ITERATOR_FREE(_efl_ui_relative_container_content_iterator_free);
741 
742    return &it->iterator;
743 }
744 
745 EOLIAN static int
_efl_ui_relative_container_efl_container_content_count(Eo * obj EINA_UNUSED,Efl_Ui_Relative_Container_Data * pd)746 _efl_ui_relative_container_efl_container_content_count(Eo *obj EINA_UNUSED, Efl_Ui_Relative_Container_Data *pd)
747 {
748    return eina_hash_population(pd->children);
749 }
750 
751 EFL_UI_RELATIVE_CONTAINER_RELATION_SET_GET(left, LEFT);
752 EFL_UI_RELATIVE_CONTAINER_RELATION_SET_GET(right, RIGHT);
753 EFL_UI_RELATIVE_CONTAINER_RELATION_SET_GET(top, TOP);
754 EFL_UI_RELATIVE_CONTAINER_RELATION_SET_GET(bottom, BOTTOM);
755 
756 /* Internal EO APIs and hidden overrides */
757 
758 #define EFL_UI_RELATIVE_CONTAINER_EXTRA_OPS \
759    EFL_CANVAS_GROUP_ADD_OPS(efl_ui_relative_container)
760 
761 #include "efl_ui_relative_container.eo.c"
762