1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_PART_PROTECTED
6 #define EFL_UI_POPUP_PROTECTED
7 #define EFL_PART_PROTECTED
8 #define EFL_UI_WIDGET_SCROLLABLE_CONTENT_PROTECTED
9 #include <Elementary.h>
10 
11 #include "elm_priv.h"
12 #include "efl_ui_popup_private.h"
13 #include "efl_ui_popup_part_backwall.eo.h"
14 #include "elm_part_helper.h"
15 
16 #define MY_CLASS EFL_UI_POPUP_CLASS
17 #define MY_CLASS_NAME "Efl.Ui.Popup"
18 
19 static const char PART_NAME_BACKWALL[] = "backwall";
20 
21 static void
_calc_align(Eo * obj)22 _calc_align(Eo *obj)
23 {
24    Efl_Ui_Popup_Data *pd = efl_data_scope_get(obj, MY_CLASS);
25 
26    Eina_Rect p_geom = efl_gfx_entity_geometry_get(pd->win_parent);
27 
28    Eina_Rect o_geom = efl_gfx_entity_geometry_get(obj);
29 
30    Evas_Coord pw, ph;
31    pw = p_geom.w;
32    ph = p_geom.h;
33 
34    Evas_Coord ow, oh;
35    ow = o_geom.w;
36    oh = o_geom.h;
37 
38    switch (pd->align)
39      {
40       case EFL_UI_POPUP_ALIGN_CENTER:
41          efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), EINA_POSITION2D((pw - ow ) / 2, (ph - oh) / 2));
42          break;
43       case EFL_UI_POPUP_ALIGN_LEFT:
44          efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), EINA_POSITION2D(0, (ph - oh) / 2));
45          break;
46       case EFL_UI_POPUP_ALIGN_RIGHT:
47          efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), EINA_POSITION2D(pw - ow, (ph - oh) / 2));
48          break;
49       case EFL_UI_POPUP_ALIGN_TOP:
50          efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), EINA_POSITION2D((pw - ow) / 2, 0));
51          break;
52       case EFL_UI_POPUP_ALIGN_BOTTOM:
53          efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), EINA_POSITION2D((pw - ow) / 2, ph - oh));
54          break;
55       default:
56          break;
57      }
58 }
59 
60 static void
_anchor_calc(Eo * obj)61 _anchor_calc(Eo *obj)
62 {
63    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
64    EFL_UI_POPUP_DATA_GET_OR_RETURN(obj, pd);
65 
66    if (!pd->anchor) return;
67 
68    Eina_Position2D pos = {0, 0};
69 
70    Eina_Rect a_geom = efl_gfx_entity_geometry_get(pd->anchor);
71    Eina_Rect o_geom = efl_gfx_entity_geometry_get(obj);
72    Eina_Rect p_geom = efl_gfx_entity_geometry_get(pd->win_parent);
73 
74    pd->used_align = EFL_UI_POPUP_ALIGN_NONE;
75 
76    /* 1. Find align which display popup.
77          It enables to shifting popup from exact position.
78          LEFT, RIGHT - shift only y position within anchor object's height
79          TOP, BOTTOM - shift only x position within anchor object's width
80          CENTER - shift both x, y position within anchor object's area
81     */
82 
83    for (int idx = 0; idx < 6; idx++)
84      {
85         Efl_Ui_Popup_Align cur_align;
86 
87         if (idx == 0)
88           cur_align = pd->align;
89         else
90           cur_align = pd->priority[idx - 1];
91 
92         if (cur_align == EFL_UI_POPUP_ALIGN_NONE)
93           continue;
94 
95         switch(cur_align)
96           {
97            case EFL_UI_POPUP_ALIGN_TOP:
98               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
99               pos.y = (a_geom.y - o_geom.h);
100 
101               if ((pos.y < 0) ||
102                   ((pos.y + o_geom.h) > p_geom.h) ||
103                   (o_geom.w > p_geom.w))
104                 continue;
105               break;
106 
107            case EFL_UI_POPUP_ALIGN_LEFT:
108               pos.x = (a_geom.x - o_geom.w);
109               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
110 
111               if ((pos.x < 0) ||
112                   ((pos.x + o_geom.w) > p_geom.w) ||
113                   (o_geom.h > p_geom.h))
114                 continue;
115               break;
116 
117            case EFL_UI_POPUP_ALIGN_RIGHT:
118               pos.x = (a_geom.x + a_geom.w);
119               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
120 
121               if ((pos.x < 0) ||
122                   ((pos.x + o_geom.w) > p_geom.w) ||
123                   (o_geom.h > p_geom.h))
124                 continue;
125               break;
126 
127            case EFL_UI_POPUP_ALIGN_BOTTOM:
128               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
129               pos.y = (a_geom.y + a_geom.h);
130 
131               if ((pos.y < 0) ||
132                   ((pos.y + o_geom.h) > p_geom.h) ||
133                   (o_geom.w > p_geom.w))
134                 continue;
135               break;
136 
137            case EFL_UI_POPUP_ALIGN_CENTER:
138               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
139               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
140 
141               if ((o_geom.w > p_geom.w) || (o_geom.h > p_geom.h))
142                 continue;
143               break;
144 
145            default:
146               continue;
147           }
148 
149         if ((cur_align == EFL_UI_POPUP_ALIGN_TOP) ||
150             (cur_align == EFL_UI_POPUP_ALIGN_BOTTOM) ||
151             (cur_align == EFL_UI_POPUP_ALIGN_CENTER))
152           {
153              if (pos.x < 0)
154                pos.x = 0;
155              if ((pos.x + o_geom.w) > p_geom.w)
156                pos.x = p_geom.w - o_geom.w;
157 
158              if ((pos.x > (a_geom.x + a_geom.w)) ||
159                  ((pos.x + o_geom.w) < a_geom.x))
160                continue;
161           }
162 
163         if ((cur_align == EFL_UI_POPUP_ALIGN_LEFT) ||
164             (cur_align == EFL_UI_POPUP_ALIGN_RIGHT) ||
165             (cur_align == EFL_UI_POPUP_ALIGN_CENTER))
166           {
167              if (pos.y < 0)
168                pos.y = 0;
169              if ((pos.y + o_geom.h) > p_geom.h)
170                pos.y = p_geom.h - o_geom.h;
171 
172              if ((pos.y > (a_geom.y + a_geom.h)) ||
173                  ((pos.y + o_geom.h) < a_geom.y))
174                continue;
175           }
176 
177         pd->used_align = cur_align;
178         goto end;
179      }
180 
181    /* 2. Move popup to fit first valid align although entire popup can't display */
182 
183    for (int idx = 0; idx < 6; idx++)
184      {
185         Efl_Ui_Popup_Align cur_align;
186 
187         if (idx == 0)
188           cur_align = pd->align;
189         else
190           cur_align = pd->priority[idx - 1];
191 
192         if (cur_align == EFL_UI_POPUP_ALIGN_NONE)
193           continue;
194 
195         switch(cur_align)
196           {
197            case EFL_UI_POPUP_ALIGN_TOP:
198               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
199               pos.y = (a_geom.y - o_geom.h);
200               pd->used_align = cur_align;
201               goto end;
202               break;
203 
204            case EFL_UI_POPUP_ALIGN_LEFT:
205               pos.x = (a_geom.x - o_geom.w);
206               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
207               pd->used_align = cur_align;
208               goto end;
209               break;
210 
211            case EFL_UI_POPUP_ALIGN_RIGHT:
212               pos.x = (a_geom.x + a_geom.w);
213               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
214               pd->used_align = cur_align;
215               goto end;
216               break;
217 
218            case EFL_UI_POPUP_ALIGN_BOTTOM:
219               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
220               pos.y = (a_geom.y + a_geom.h);
221               pd->used_align = cur_align;
222               goto end;
223               break;
224 
225            case EFL_UI_POPUP_ALIGN_CENTER:
226               pos.x = a_geom.x + ((a_geom.w - o_geom.w) / 2);
227               pos.y = a_geom.y + ((a_geom.h - o_geom.h) / 2);
228               pd->used_align = cur_align;
229               goto end;
230               break;
231 
232            default:
233               break;
234           }
235      }
236 
237 end:
238    if (pd->used_align != EFL_UI_POPUP_ALIGN_NONE)
239      efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
240 }
241 
242 static void
_anchor_geom_cb(void * data,const Efl_Event * ev EINA_UNUSED)243 _anchor_geom_cb(void *data, const Efl_Event *ev EINA_UNUSED)
244 {
245    _anchor_calc(data);
246 }
247 
248 static void
_anchor_del_cb(void * data,const Efl_Event * ev EINA_UNUSED)249 _anchor_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
250 {
251    EFL_UI_POPUP_DATA_GET_OR_RETURN(data, pd);
252 
253    efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _anchor_geom_cb, data);
254 
255    pd->anchor = NULL;
256    _anchor_calc(data);
257 }
258 
259 static void
_anchor_detach(Eo * obj,Efl_Ui_Popup_Data * pd)260 _anchor_detach(Eo *obj, Efl_Ui_Popup_Data *pd)
261 {
262    if (!pd->anchor) return;
263 
264    efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _anchor_geom_cb, obj);
265    efl_event_callback_del(pd->anchor, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _anchor_geom_cb, obj);
266    efl_event_callback_del(pd->anchor, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _anchor_geom_cb, obj);
267    efl_event_callback_del(pd->anchor, EFL_EVENT_DEL, _anchor_del_cb, obj);
268 }
269 
270 EOLIAN static void
_efl_ui_popup_anchor_set(Eo * obj,Efl_Ui_Popup_Data * pd,Eo * anchor)271 _efl_ui_popup_anchor_set(Eo *obj, Efl_Ui_Popup_Data *pd, Eo *anchor)
272 {
273    _anchor_detach(obj, pd);
274    pd->anchor = anchor;
275 
276    if (anchor)
277      {
278         efl_event_callback_add(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _anchor_geom_cb, obj);
279         efl_event_callback_add(anchor, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _anchor_geom_cb, obj);
280         efl_event_callback_add(anchor, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _anchor_geom_cb, obj);
281         efl_event_callback_add(anchor, EFL_EVENT_DEL, _anchor_del_cb, obj);
282         _anchor_calc(obj);
283      }
284    else
285      _calc_align(obj);
286 }
287 
288 EOLIAN static Efl_Object *
_efl_ui_popup_anchor_get(const Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd)289 _efl_ui_popup_anchor_get(const Eo *obj EINA_UNUSED, Efl_Ui_Popup_Data *pd)
290 {
291    return pd->anchor;
292 }
293 
294 EOLIAN static void
_efl_ui_popup_align_priority_set(Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd,Efl_Ui_Popup_Align first,Efl_Ui_Popup_Align second,Efl_Ui_Popup_Align third,Efl_Ui_Popup_Align fourth,Efl_Ui_Popup_Align fifth)295 _efl_ui_popup_align_priority_set(Eo *obj EINA_UNUSED,
296                                         Efl_Ui_Popup_Data *pd,
297                                         Efl_Ui_Popup_Align first,
298                                         Efl_Ui_Popup_Align second,
299                                         Efl_Ui_Popup_Align third,
300                                         Efl_Ui_Popup_Align fourth,
301                                         Efl_Ui_Popup_Align fifth)
302 {
303    pd->priority[0] = first;
304    pd->priority[1] = second;
305    pd->priority[2] = third;
306    pd->priority[3] = fourth;
307    pd->priority[4] = fifth;
308 }
309 
310 EOLIAN static void
_efl_ui_popup_align_priority_get(const Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd,Efl_Ui_Popup_Align * first,Efl_Ui_Popup_Align * second,Efl_Ui_Popup_Align * third,Efl_Ui_Popup_Align * fourth,Efl_Ui_Popup_Align * fifth)311 _efl_ui_popup_align_priority_get(const Eo *obj EINA_UNUSED,
312                                         Efl_Ui_Popup_Data *pd,
313                                         Efl_Ui_Popup_Align *first,
314                                         Efl_Ui_Popup_Align *second,
315                                         Efl_Ui_Popup_Align *third,
316                                         Efl_Ui_Popup_Align *fourth,
317                                         Efl_Ui_Popup_Align *fifth)
318 {
319    if (first) *first = pd->priority[0];
320    if (second) *second = pd->priority[1];
321    if (third) *third = pd->priority[2];
322    if (fourth) *fourth = pd->priority[3];
323    if (fifth) *fifth = pd->priority[4];
324 }
325 
326 
327 static void
_backwall_clicked_cb(void * data,Eo * o EINA_UNUSED,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)328 _backwall_clicked_cb(void *data,
329                      Eo *o EINA_UNUSED,
330                      const char *emission EINA_UNUSED,
331                      const char *source EINA_UNUSED)
332 {
333    Eo *obj = data;
334    efl_event_callback_call(obj, EFL_UI_POPUP_EVENT_BACKWALL_CLICKED, NULL);
335 }
336 
337 EOLIAN static void
_efl_ui_popup_efl_gfx_entity_position_set(Eo * obj,Efl_Ui_Popup_Data * pd,Eina_Position2D pos)338 _efl_ui_popup_efl_gfx_entity_position_set(Eo *obj, Efl_Ui_Popup_Data *pd, Eina_Position2D pos)
339 {
340    pd->align = EFL_UI_POPUP_ALIGN_NONE;
341    _anchor_detach(obj, pd);
342 
343    pd->anchor = NULL;
344    efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
345 }
346 
347 EOLIAN static void
_efl_ui_popup_efl_gfx_entity_size_set(Eo * obj,Efl_Ui_Popup_Data * pd,Eina_Size2D size)348 _efl_ui_popup_efl_gfx_entity_size_set(Eo *obj, Efl_Ui_Popup_Data *pd, Eina_Size2D size)
349 {
350    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), size);
351 
352    if (!pd->in_calc)
353      efl_canvas_group_change(obj);
354 }
355 
356 static void
_parent_geom_cb(void * data,const Efl_Event * ev EINA_UNUSED)357 _parent_geom_cb(void *data, const Efl_Event *ev EINA_UNUSED)
358 {
359    Eo *obj = data;
360 
361    EFL_UI_POPUP_DATA_GET_OR_RETURN(obj, pd);
362 
363    efl_canvas_group_change(obj);
364 }
365 
366 static void
_hints_changed_cb(void * data,const Efl_Event * ev EINA_UNUSED)367 _hints_changed_cb(void *data, const Efl_Event *ev EINA_UNUSED)
368 {
369    Efl_Ui_Popup_Data *pd = data;
370 
371    if (!pd->in_calc)
372      efl_canvas_group_change(ev->object);
373 }
374 
375 EOLIAN static void
_efl_ui_popup_efl_ui_widget_widget_parent_set(Eo * obj,Efl_Ui_Popup_Data * pd,Eo * parent)376 _efl_ui_popup_efl_ui_widget_widget_parent_set(Eo *obj, Efl_Ui_Popup_Data *pd, Eo *parent)
377 {
378    if (!parent)
379      {
380         /* unsetting parent, probably before deletion */
381         if (pd->win_parent)
382           {
383              efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _parent_geom_cb, obj);
384              efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _parent_geom_cb, obj);
385           }
386         goto end;
387      }
388    pd->win_parent = efl_provider_find(obj, EFL_UI_WIN_CLASS);
389    if (!pd->win_parent)
390      {
391         ERR("Cannot find window parent");
392         return;
393      }
394 
395    Eina_Rect p_geom = efl_gfx_entity_geometry_get(pd->win_parent);
396 
397    efl_gfx_entity_position_set(pd->backwall, EINA_POSITION2D(p_geom.x, p_geom.y));
398    efl_gfx_entity_size_set(pd->backwall, EINA_SIZE2D(p_geom.w, p_geom.h));
399 
400    efl_event_callback_add(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _parent_geom_cb, obj);
401    efl_event_callback_add(pd->win_parent, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _parent_geom_cb, obj);
402 end:
403    efl_ui_widget_parent_set(efl_super(obj, MY_CLASS), parent);
404 }
405 
406 EOLIAN static void
_efl_ui_popup_align_set(Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd,Efl_Ui_Popup_Align type)407 _efl_ui_popup_align_set(Eo *obj EINA_UNUSED, Efl_Ui_Popup_Data *pd, Efl_Ui_Popup_Align type)
408 {
409    pd->align = type;
410 
411    efl_canvas_group_change(obj);
412 }
413 
414 EOLIAN static Efl_Ui_Popup_Align
_efl_ui_popup_align_get(const Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd)415 _efl_ui_popup_align_get(const Eo *obj EINA_UNUSED, Efl_Ui_Popup_Data *pd)
416 {
417    return pd->align;
418 }
419 
420 static Eina_Bool
_timer_cb(void * data)421 _timer_cb(void *data)
422 {
423    Eo *popup = data;
424    efl_event_callback_call(popup, EFL_UI_POPUP_EVENT_TIMEOUT, NULL);
425    efl_del(popup);
426 
427    return ECORE_CALLBACK_CANCEL;
428 }
429 
430 static void
_timer_del(Efl_Ui_Popup_Data * pd)431 _timer_del(Efl_Ui_Popup_Data *pd)
432 {
433    if (pd->timer)
434      {
435         ecore_timer_del(pd->timer);
436         pd->timer = NULL;
437      }
438 }
439 
440 static void
_timer_init(Eo * obj,Efl_Ui_Popup_Data * pd)441 _timer_init(Eo *obj, Efl_Ui_Popup_Data *pd)
442 {
443    if (pd->timeout > 0.0)
444      pd->timer = ecore_timer_add(pd->timeout, _timer_cb, obj);
445 }
446 
447 EOLIAN static void
_efl_ui_popup_efl_gfx_entity_visible_set(Eo * obj,Efl_Ui_Popup_Data * pd,Eina_Bool v)448 _efl_ui_popup_efl_gfx_entity_visible_set(Eo *obj, Efl_Ui_Popup_Data *pd, Eina_Bool v)
449 {
450    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, v))
451      return;
452 
453    efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), v);
454 
455    if (v)
456      {
457         _timer_del(pd);
458         _timer_init(obj, pd);
459      }
460 }
461 
462 EOLIAN static void
_efl_ui_popup_closing_timeout_set(Eo * obj,Efl_Ui_Popup_Data * pd,double time)463 _efl_ui_popup_closing_timeout_set(Eo *obj, Efl_Ui_Popup_Data *pd, double time)
464 {
465    if (time < 0.0)
466      time = 0.0;
467 
468    pd->timeout = time;
469 
470    _timer_del(pd);
471 
472    if (efl_gfx_entity_visible_get(obj))
473      _timer_init(obj, pd);
474 }
475 
476 EOLIAN static double
_efl_ui_popup_closing_timeout_get(const Eo * obj EINA_UNUSED,Efl_Ui_Popup_Data * pd)477 _efl_ui_popup_closing_timeout_get(const Eo *obj EINA_UNUSED, Efl_Ui_Popup_Data *pd)
478 {
479    return pd->timeout;
480 }
481 
482 /* this will ONLY be called during _sizing_eval() */
483 static void
_scrollable_content_size_cb(void * data EINA_UNUSED,const Efl_Event * ev)484 _scrollable_content_size_cb(void *data EINA_UNUSED, const Efl_Event *ev)
485 {
486    Eina_Size2D *size = ev->info;
487 
488    efl_gfx_entity_size_set(ev->object, *size);
489    /* finish group calc chain */
490    efl_canvas_group_calculate(efl_super(ev->object, EFL_UI_WIDGET_SCROLLABLE_CONTENT_MIXIN));
491 }
492 
493 static void
_sizing_eval(Eo * obj)494 _sizing_eval(Eo *obj)
495 {
496    Eina_Size2D min;
497 
498    /* trigger layout calc */
499    efl_canvas_group_calculate(efl_super(obj, MY_CLASS));
500    if (efl_ui_widget_scrollable_content_did_group_calc_get(obj)) return;
501    min = efl_gfx_hint_size_combined_min_get(obj);
502 
503    Eina_Size2D size = efl_gfx_entity_size_get(obj);
504 
505    Eina_Size2D new_size;
506    new_size.w = (min.w > size.w ? min.w : size.w);
507    new_size.h = (min.h > size.h ? min.h : size.h);
508    efl_gfx_entity_size_set(obj, new_size);
509 }
510 
511 EOLIAN static void
_efl_ui_popup_efl_canvas_group_group_calculate(Eo * obj,Efl_Ui_Popup_Data * pd)512 _efl_ui_popup_efl_canvas_group_group_calculate(Eo *obj, Efl_Ui_Popup_Data *pd)
513 {
514    /* When efl_canvas_group_change() is called, just flag is set instead of size
515     * calculation.
516     * The actual size calculation is done here when the object is rendered to
517     * avoid duplicate size calculations. */
518    efl_canvas_group_need_recalculate_set(obj, EINA_FALSE);
519    pd->in_calc = EINA_TRUE;
520    _sizing_eval(obj);
521    pd->in_calc = EINA_FALSE;
522    if (pd->anchor)
523      _anchor_calc(obj);
524    else
525      _calc_align(obj);
526 
527    Eina_Rect p_geom = efl_gfx_entity_geometry_get(pd->win_parent);
528 
529    efl_gfx_entity_position_set(pd->backwall, EINA_POSITION2D(0, 0));
530    efl_gfx_entity_size_set(pd->backwall, EINA_SIZE2D(p_geom.w, p_geom.h));
531 }
532 
533 EOLIAN static Eo *
_efl_ui_popup_efl_object_constructor(Eo * obj,Efl_Ui_Popup_Data * pd)534 _efl_ui_popup_efl_object_constructor(Eo *obj, Efl_Ui_Popup_Data *pd)
535 {
536    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
537 
538    if (!elm_widget_theme_klass_get(obj))
539      elm_widget_theme_klass_set(obj, "popup");
540    obj = efl_constructor(efl_super(obj, MY_CLASS));
541    efl_canvas_object_type_set(obj, MY_CLASS_NAME);
542    efl_event_callback_add(obj, EFL_GFX_ENTITY_EVENT_HINTS_CHANGED, _hints_changed_cb, pd);
543    efl_event_callback_add(obj, EFL_UI_WIDGET_SCROLLABLE_CONTENT_EVENT_OPTIMAL_SIZE_CALC, _scrollable_content_size_cb, pd);
544 
545    elm_widget_can_focus_set(obj, EINA_TRUE);
546    if (elm_widget_theme_object_set(obj, wd->resize_obj,
547                                        elm_widget_theme_klass_get(obj),
548                                        elm_widget_theme_element_get(obj),
549                                        elm_widget_theme_style_get(obj)) == EFL_UI_THEME_APPLY_ERROR_GENERIC)
550      CRI("Failed to set layout!");
551 
552    pd->backwall = edje_object_add(evas_object_evas_get(obj));
553    elm_widget_element_update(obj, pd->backwall, PART_NAME_BACKWALL);
554    evas_object_smart_member_add(pd->backwall, obj);
555    evas_object_stack_below(pd->backwall, wd->resize_obj);
556 
557    edje_object_signal_callback_add(pd->backwall, "efl,action,click", "*",
558                                    _backwall_clicked_cb, obj);
559 
560    pd->align = EFL_UI_POPUP_ALIGN_CENTER;
561 
562    pd->priority[0] = EFL_UI_POPUP_ALIGN_TOP;
563    pd->priority[1] = EFL_UI_POPUP_ALIGN_LEFT;
564    pd->priority[2] = EFL_UI_POPUP_ALIGN_RIGHT;
565    pd->priority[3] = EFL_UI_POPUP_ALIGN_BOTTOM;
566    pd->priority[4] = EFL_UI_POPUP_ALIGN_CENTER;
567    return obj;
568 }
569 
570 EOLIAN static void
_efl_ui_popup_efl_object_invalidate(Eo * obj,Efl_Ui_Popup_Data * pd)571 _efl_ui_popup_efl_object_invalidate(Eo *obj, Efl_Ui_Popup_Data *pd)
572 {
573    ELM_SAFE_DEL(pd->backwall);
574    efl_invalidate(efl_super(obj, MY_CLASS));
575 }
576 
577 EOLIAN static void
_efl_ui_popup_efl_object_destructor(Eo * obj,Efl_Ui_Popup_Data * pd)578 _efl_ui_popup_efl_object_destructor(Eo *obj, Efl_Ui_Popup_Data *pd)
579 {
580    _anchor_detach(obj, pd);
581 
582    efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_SIZE_CHANGED, _parent_geom_cb,
583                           obj);
584    efl_event_callback_del(pd->win_parent, EFL_GFX_ENTITY_EVENT_POSITION_CHANGED, _parent_geom_cb,
585                           obj);
586 
587    efl_destructor(efl_super(obj, MY_CLASS));
588 }
589 
590 /* Standard widget overrides */
591 
ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_popup,Efl_Ui_Popup_Data)592 ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_popup, Efl_Ui_Popup_Data)
593 
594 EOLIAN static Eo *
595 _efl_ui_popup_efl_part_part_get(const Eo *obj, Efl_Ui_Popup_Data *_pd EINA_UNUSED, const char *part)
596 {
597    EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
598 
599    if (eina_streq(part, PART_NAME_BACKWALL))
600      return ELM_PART_IMPLEMENT(EFL_UI_POPUP_PART_BACKWALL_CLASS, obj, part);
601 
602    return efl_part_get(efl_super(obj, MY_CLASS), part);
603 }
604 
605 EOLIAN static void
_efl_ui_popup_part_backwall_repeat_events_set(Eo * obj,void * _pd EINA_UNUSED,Eina_Bool repeat)606 _efl_ui_popup_part_backwall_repeat_events_set(Eo *obj, void *_pd EINA_UNUSED, Eina_Bool repeat)
607 {
608    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
609    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
610 
611    efl_canvas_object_repeat_events_set(sd->backwall, repeat);
612 }
613 
614 EOLIAN static Eina_Bool
_efl_ui_popup_part_backwall_repeat_events_get(const Eo * obj,void * _pd EINA_UNUSED)615 _efl_ui_popup_part_backwall_repeat_events_get(const Eo *obj, void *_pd EINA_UNUSED)
616 {
617    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
618    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
619 
620    return efl_canvas_object_repeat_events_get(sd->backwall);
621 }
622 
623 EOLIAN static Eina_Stringshare *
_efl_ui_popup_part_backwall_efl_file_file_get(const Eo * obj,void * _pd EINA_UNUSED)624 _efl_ui_popup_part_backwall_efl_file_file_get(const Eo *obj, void *_pd EINA_UNUSED)
625 {
626    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
627    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
628 
629    Eo *content = edje_object_part_swallow_get(sd->backwall, "efl.content");
630    return content ? efl_file_get(content) : NULL;
631 }
632 
633 EOLIAN static Eina_Stringshare *
_efl_ui_popup_part_backwall_efl_file_key_get(const Eo * obj,void * _pd EINA_UNUSED)634 _efl_ui_popup_part_backwall_efl_file_key_get(const Eo *obj, void *_pd EINA_UNUSED)
635 {
636    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
637    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
638 
639    Eo *content = edje_object_part_swallow_get(sd->backwall, "efl.content");
640    return content ? efl_file_key_get(content) : NULL;
641 }
642 
643 EOLIAN static void
_efl_ui_popup_part_backwall_efl_file_unload(Eo * obj,void * _pd EINA_UNUSED)644 _efl_ui_popup_part_backwall_efl_file_unload(Eo *obj, void *_pd EINA_UNUSED)
645 {
646    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
647    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
648 
649    efl_file_unload(efl_super(obj, EFL_UI_POPUP_PART_BACKWALL_CLASS));
650    Eo *prev_obj = edje_object_part_swallow_get(sd->backwall, "efl.content");
651    if (prev_obj)
652      {
653         edje_object_signal_emit(sd->backwall, "efl,state,content,unset", "efl");
654         edje_object_part_unswallow(sd->backwall, prev_obj);
655         efl_del(prev_obj);
656      }
657 }
658 
659 EOLIAN static Eina_Error
_efl_ui_popup_part_backwall_efl_file_load(Eo * obj,void * _pd EINA_UNUSED)660 _efl_ui_popup_part_backwall_efl_file_load(Eo *obj, void *_pd EINA_UNUSED)
661 {
662    Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
663    Efl_Ui_Popup_Data *sd = efl_data_scope_get(pd->obj, EFL_UI_POPUP_CLASS);
664 
665    Eina_Error err;
666 
667    if (efl_file_loaded_get(obj)) return 0;
668 
669    err = efl_file_load(efl_super(obj, EFL_UI_POPUP_PART_BACKWALL_CLASS));
670    if (err) return err;
671 
672    Eo *prev_obj = edje_object_part_swallow_get(sd->backwall, "efl.content");
673    if (prev_obj)
674      {
675         edje_object_signal_emit(sd->backwall, "efl,state,content,unset", "efl");
676         edje_object_part_unswallow(sd->backwall, prev_obj);
677         efl_del(prev_obj);
678      }
679 
680    Eo *image = efl_add(EFL_UI_IMAGE_CLASS, pd->obj);
681    Eina_Bool ret;
682    const Eina_File *f;
683 
684    f = efl_file_mmap_get(obj);
685    if (f)
686      ret = efl_file_simple_mmap_load(image, f, efl_file_key_get(obj));
687    else
688      ret = efl_file_simple_load(image, efl_file_get(obj), efl_file_key_get(obj));
689    if (!ret)
690      {
691         efl_del(image);
692         return EFL_GFX_IMAGE_LOAD_ERROR_GENERIC;
693      }
694    edje_object_part_swallow(sd->backwall, "efl.content", image);
695    edje_object_signal_emit(sd->backwall, "efl,state,content,set", "efl");
696 
697    return 0;
698 }
699 
700 #include "efl_ui_popup_part_backwall.eo.c"
701 
702 /* Efl.Part end */
703 
704 #include "efl_ui_popup.eo.c"
705