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