1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 #define EFL_ACCESS_WIDGET_ACTION_PROTECTED
7 #define EFL_UI_FOCUS_LAYER_PROTECTED
8 #define EFL_PART_PROTECTED
9 
10 #include <Elementary.h>
11 
12 #include "elm_priv.h"
13 #include "elm_widget_panel.h"
14 
15 #include "els_box.h"
16 
17 #include "elm_panel_part.eo.h"
18 #include "elm_part_helper.h"
19 
20 #define MY_CLASS ELM_PANEL_CLASS
21 
22 #define MY_CLASS_NAME "Elm_Panel"
23 #define MY_CLASS_NAME_LEGACY "elm_panel"
24 
25 static const char ACCESS_OUTLINE_PART[] = "access.outline";
26 
27 static const char SIG_TOGGLED[] = "toggled";
28 static const char SIG_SCROLL[] = "scroll";
29 
30 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
31    {SIG_TOGGLED, ""},
32    {SIG_SCROLL, ""},
33    {SIG_LAYOUT_FOCUSED, ""}, /**< handled by elm_layout */
34    {SIG_LAYOUT_UNFOCUSED, ""}, /**< handled by elm_layout */
35    {NULL, NULL}
36 };
37 static void _panel_toggle(void *, Evas_Object *, const char *,const char *);
38 static Eina_Bool _key_action_toggle(Evas_Object *obj, const char *params);
39 static void _drawer_open(Evas_Object *, Evas_Coord , Evas_Coord , Eina_Bool );
40 static void _drawer_close(Evas_Object *, Evas_Coord , Evas_Coord , Eina_Bool);
41 
42 static const Elm_Action key_actions[] = {
43    {"toggle", _key_action_toggle},
44    {NULL, NULL}
45 };
46 
47 static void
_mirrored_set(Evas_Object * obj,Eina_Bool rtl)48 _mirrored_set(Evas_Object *obj,
49               Eina_Bool rtl)
50 {
51    ELM_PANEL_DATA_GET(obj, sd);
52 
53    if ((sd->content) && (efl_isa(sd->content, EFL_UI_WIDGET_CLASS)))
54      efl_ui_mirrored_set(sd->content, rtl);
55    elm_panel_orient_set(obj, elm_panel_orient_get(obj));
56 }
57 
58 EOLIAN static void
_elm_panel_efl_canvas_group_group_calculate(Eo * obj,Elm_Panel_Data * sd)59 _elm_panel_efl_canvas_group_group_calculate(Eo *obj, Elm_Panel_Data *sd)
60 {
61    if (sd->delete_me) return;
62 
63    if (sd->scrollable)
64      {
65         Eina_Size2D size = efl_gfx_entity_size_get(obj);
66         if (sd->hidden) _drawer_close(obj, size.w, size.h, EINA_FALSE);
67         else _drawer_open(obj, size.w, size.h, EINA_FALSE);
68      }
69 
70    efl_canvas_group_calculate(efl_super(obj, MY_CLASS));
71 }
72 
73 static char *
_access_state_cb(void * data,Evas_Object * obj EINA_UNUSED)74 _access_state_cb(void *data, Evas_Object *obj EINA_UNUSED)
75 {
76    ELM_PANEL_DATA_GET(data, sd);
77 
78    if (!sd->hidden) return strdup(E_("state: opened"));
79    else return strdup(E_("state: closed"));
80 
81    return NULL;
82 }
83 
84 static Evas_Object *
_access_object_get(const Evas_Object * obj,const char * part)85 _access_object_get(const Evas_Object *obj, const char *part)
86 {
87    Evas_Object *po, *ao, *o;
88    ELM_PANEL_DATA_GET(obj, sd);
89 
90    o = elm_layout_edje_get(sd->scr_ly);
91    edje_object_freeze(o);
92    po = (Evas_Object *)edje_object_part_object_get(o, part);
93    edje_object_thaw(o);
94    ao = evas_object_data_get(po, "_part_access_obj");
95 
96    return ao;
97 }
98 
99 static void
_access_activate_cb(void * data,Evas_Object * part_obj EINA_UNUSED,Elm_Object_Item * item EINA_UNUSED)100 _access_activate_cb(void *data,
101                     Evas_Object *part_obj EINA_UNUSED,
102                     Elm_Object_Item *item EINA_UNUSED)
103 {
104    elm_panel_hidden_set(data, EINA_TRUE);
105 }
106 
107 static void
_access_obj_process(Evas_Object * obj,Eina_Bool is_access)108 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
109 {
110    Evas_Object *ao;
111    ELM_PANEL_DATA_GET(obj, sd);
112 
113    if (is_access)
114      {
115         ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
116         if (!ao)
117           {
118              ao = _elm_access_edje_object_part_object_register
119                 (obj, elm_layout_edje_get(sd->scr_ly), ACCESS_OUTLINE_PART);
120              _elm_access_text_set(_elm_access_info_get(ao),
121                                   ELM_ACCESS_TYPE, E_("A panel is open"));
122              _elm_access_text_set(_elm_access_info_get(ao),
123                                   ELM_ACCESS_CONTEXT_INFO, E_("Double tap to close panel menu"));
124              _elm_access_activate_callback_set
125                 (_elm_access_info_get(ao), _access_activate_cb, obj);
126           }
127      }
128    else
129      {
130         _elm_access_edje_object_part_object_unregister
131            (obj, elm_layout_edje_get(sd->scr_ly), ACCESS_OUTLINE_PART);
132      }
133 }
134 
135 static void
_orient_set_do(Evas_Object * obj)136 _orient_set_do(Evas_Object *obj)
137 {
138    ELM_PANEL_DATA_GET(obj, sd);
139    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
140 
141    switch (sd->orient)
142      {
143       case ELM_PANEL_ORIENT_TOP:
144         if (!elm_layout_theme_set
145               (obj, "panel", "top", elm_widget_style_get(obj)))
146           CRI("Failed to set layout!");
147         break;
148 
149       case ELM_PANEL_ORIENT_BOTTOM:
150         if (!elm_layout_theme_set
151               (obj, "panel", "bottom", elm_widget_style_get(obj)))
152           CRI("Failed to set layout!");
153         break;
154 
155       case ELM_PANEL_ORIENT_LEFT:
156         if (!elm_layout_theme_set(obj, "panel", "left",
157                 elm_widget_style_get(obj)))
158             CRI("Failed to set layout!");
159         break;
160 
161       case ELM_PANEL_ORIENT_RIGHT:
162         if (!elm_layout_theme_set(obj, "panel", "right",
163                 elm_widget_style_get(obj)))
164             CRI("Failed to set layout!");
165         break;
166      }
167 
168    /* access */
169    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
170      {
171         Evas_Object *ao;
172         ao = _elm_access_edje_object_part_object_register
173             (obj, wd->resize_obj, "btn_icon");
174         _elm_access_text_set(_elm_access_info_get(ao),
175                              ELM_ACCESS_TYPE, E_("panel button"));
176         _elm_access_callback_set
177           (_elm_access_info_get(ao), ELM_ACCESS_STATE, _access_state_cb, obj);
178      }
179 }
180 
181 static void
_scrollable_layout_theme_set(Eo * obj,Elm_Panel_Data * sd)182 _scrollable_layout_theme_set(Eo *obj, Elm_Panel_Data *sd)
183 {
184    switch (sd->orient)
185      {
186       case ELM_PANEL_ORIENT_TOP:
187          if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/top",
188                                    elm_widget_style_get(obj)))
189            CRI("Failed to set layout!");
190          break;
191       case ELM_PANEL_ORIENT_BOTTOM:
192          if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/bottom",
193                                    elm_widget_style_get(obj)))
194            CRI("Failed to set layout!");
195          break;
196       case ELM_PANEL_ORIENT_LEFT:
197          if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/left",
198                                    elm_widget_style_get(obj)))
199            CRI("Failed to set layout!");
200          break;
201       case ELM_PANEL_ORIENT_RIGHT:
202          if (!elm_layout_theme_set(sd->scr_ly, "scroller", "panel/right",
203                                    elm_widget_style_get(obj)))
204            CRI("Failed to set layout!");
205          break;
206      }
207 
208    /* access */
209    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
210      _access_obj_process(obj, EINA_TRUE);
211 }
212 
213 EOLIAN static Eina_Error
_elm_panel_efl_ui_widget_theme_apply(Eo * obj,Elm_Panel_Data * sd)214 _elm_panel_efl_ui_widget_theme_apply(Eo *obj, Elm_Panel_Data *sd)
215 {
216    const char *str;
217    Evas_Coord minw = 0, minh = 0;
218 
219    Eina_Error int_ret = EFL_UI_THEME_APPLY_ERROR_GENERIC;
220 
221    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EFL_UI_THEME_APPLY_ERROR_GENERIC);
222 
223    int_ret = efl_ui_widget_theme_apply(efl_super(obj, MY_CLASS));
224    if (int_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC) return int_ret;
225 
226    elm_interface_scrollable_reset_signals(obj);
227    _mirrored_set(obj, efl_ui_mirrored_get(obj));
228 
229    if (sd->scrollable)
230      {
231         const char *handler_size;
232         elm_widget_theme_object_set(obj, sd->scr_edje, "scroller", "panel",
233                                     elm_widget_style_get(obj));
234         _scrollable_layout_theme_set(obj, sd);
235         handler_size = edje_object_data_get(sd->scr_edje, "handler_size");
236         if (handler_size)
237           sd->handler_size = (int) (elm_object_scale_get(obj)) * (atoi(handler_size));
238      }
239    else
240      {
241         str = edje_object_data_get
242            (wd->resize_obj, "focus_highlight");
243         if ((str) && (!strcmp(str, "on")))
244           elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
245         else
246           elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
247 
248         _orient_set_do(obj);
249 
250         evas_object_hide(sd->event);
251         elm_coords_finger_size_adjust(1, &minw, 1, &minh);
252         evas_object_size_hint_min_set(sd->event, minw, minh);
253 
254         if (edje_object_part_exists(wd->resize_obj, "elm.swallow.event"))
255           efl_content_set(efl_part(efl_super(obj, MY_CLASS), "elm.swallow.event"), sd->event);
256      }
257 
258    if (efl_finalized_get(obj))
259      elm_layout_sizing_eval(obj);
260 
261    return int_ret;
262 }
263 
264 static void
_box_layout_cb(Evas_Object * o,Evas_Object_Box_Data * priv,void * data EINA_UNUSED)265 _box_layout_cb(Evas_Object *o,
266                Evas_Object_Box_Data *priv,
267                void *data EINA_UNUSED)
268 {
269    _els_box_layout(o, priv, EINA_TRUE, EINA_FALSE, EINA_FALSE);
270 }
271 
272 static void
_handler_open(Evas_Object * obj,Evas_Coord w,Evas_Coord h)273 _handler_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
274 {
275    ELM_PANEL_DATA_GET(obj, sd);
276 
277    if (sd->handler_size == 0) return;
278 
279    switch (sd->orient)
280      {
281       case ELM_PANEL_ORIENT_TOP:
282          elm_interface_scrollable_region_bring_in
283                (obj, 0, (h * sd->content_size_ratio) - sd->handler_size, w, h);
284          break;
285       case ELM_PANEL_ORIENT_BOTTOM:
286          elm_interface_scrollable_region_bring_in
287                (obj, 0, sd->handler_size, w, h);
288          break;
289       case ELM_PANEL_ORIENT_LEFT:
290          elm_interface_scrollable_region_bring_in
291                (obj, (w * sd->content_size_ratio) - sd->handler_size, 0, w, h);
292          break;
293       case ELM_PANEL_ORIENT_RIGHT:
294          elm_interface_scrollable_region_bring_in
295                (obj, sd->handler_size, 0, w, h);
296          break;
297      }
298 }
299 
300 static void
_drawer_open(Evas_Object * obj,Evas_Coord w,Evas_Coord h,Eina_Bool anim)301 _drawer_open(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim)
302 {
303    ELM_PANEL_DATA_GET(obj, sd);
304    int x = 0, y = 0;
305 
306    if (sd->freeze)
307      {
308         elm_interface_scrollable_movement_block_set
309               (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
310         sd->freeze = EINA_FALSE;
311         elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
312      }
313 
314    switch (sd->orient)
315      {
316       case ELM_PANEL_ORIENT_TOP:
317          break;
318       case ELM_PANEL_ORIENT_LEFT:
319          if (efl_ui_mirrored_get(obj))
320            x = w * sd->content_size_ratio;
321          break;
322 
323       case ELM_PANEL_ORIENT_BOTTOM:
324          y = h * sd->content_size_ratio;
325          break;
326 
327       case ELM_PANEL_ORIENT_RIGHT:
328          if (!efl_ui_mirrored_get(obj))
329            x = w * sd->content_size_ratio;
330          break;
331      }
332 
333    if (anim)
334      elm_interface_scrollable_region_bring_in
335            (obj, x, y, w, h);
336    else
337      elm_interface_scrollable_content_region_show
338            (obj, x, y, w, h);
339 }
340 
341 static void
_drawer_close(Evas_Object * obj,Evas_Coord w,Evas_Coord h,Eina_Bool anim)342 _drawer_close(Evas_Object *obj, Evas_Coord w, Evas_Coord h, Eina_Bool anim)
343 {
344    ELM_PANEL_DATA_GET(obj, sd);
345    int x = 0, y = 0, cx, cy;
346    Eina_Bool horizontal = EINA_FALSE;
347 
348    switch (sd->orient)
349      {
350       case ELM_PANEL_ORIENT_TOP:
351          y = h * sd->content_size_ratio;
352          break;
353 
354       case ELM_PANEL_ORIENT_LEFT:
355          if (!efl_ui_mirrored_get(obj))
356            x = w * sd->content_size_ratio;
357          horizontal = EINA_TRUE;
358          break;
359 
360       case ELM_PANEL_ORIENT_BOTTOM:
361          break;
362 
363       case ELM_PANEL_ORIENT_RIGHT:
364          if (efl_ui_mirrored_get(obj))
365            x = w * sd->content_size_ratio;
366          horizontal = EINA_TRUE;
367          break;
368      }
369 
370    elm_interface_scrollable_content_pos_get(obj, &cx, &cy);
371 
372    if ((x == cx) && (y == cy))
373      {
374         if (!sd->freeze)
375           {
376              if (horizontal)
377                elm_interface_scrollable_movement_block_set
378                   (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
379              else
380                elm_interface_scrollable_movement_block_set
381                   (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
382              sd->freeze = EINA_TRUE;
383              elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
384           }
385 
386         return;
387      }
388 
389    if (anim)
390      {
391         if (sd->freeze)
392           {
393              elm_interface_scrollable_movement_block_set
394                    (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
395              sd->freeze = EINA_FALSE;
396              elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
397           }
398         elm_interface_scrollable_region_bring_in(obj, x, y, w, h);
399      }
400    else
401      {
402         elm_interface_scrollable_content_region_show(obj, x, y, w, h);
403         if (!sd->freeze)
404           {
405              if (horizontal)
406                elm_interface_scrollable_movement_block_set
407                      (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
408              else
409                elm_interface_scrollable_movement_block_set
410                      (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
411              sd->freeze = EINA_TRUE;
412              elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
413           }
414      }
415 }
416 
417 static void
_panel_toggle(void * data EINA_UNUSED,Evas_Object * obj,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)418 _panel_toggle(void *data EINA_UNUSED,
419               Evas_Object *obj,
420               const char *emission EINA_UNUSED,
421               const char *source EINA_UNUSED)
422 {
423    ELM_PANEL_DATA_GET(obj, sd);
424    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
425    int w, h;
426 
427    if (sd->scrollable)
428      {
429         if (elm_widget_disabled_get(obj)) return;
430 
431         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
432         if (sd->hidden)
433           {
434              sd->hidden = EINA_FALSE;
435              _drawer_open(obj, w, h, EINA_TRUE);
436           }
437         else
438           {
439              sd->hidden = EINA_TRUE;
440              _drawer_close(obj, w, h, EINA_TRUE);
441           }
442      }
443    else
444      {
445         if (sd->hidden)
446           {
447              elm_layout_signal_emit(obj, "elm,action,show", "elm");
448              sd->hidden = EINA_FALSE;
449              evas_object_repeat_events_set(obj, EINA_FALSE);
450           }
451         else
452           {
453              elm_layout_signal_emit(obj, "elm,action,hide", "elm");
454              sd->hidden = EINA_TRUE;
455              evas_object_repeat_events_set(obj, EINA_TRUE);
456           }
457 
458         //if the panel is hidden, make this thing unfocusable
459         edje_object_message_signal_process(wd->resize_obj);
460      }
461 
462    efl_ui_focus_layer_enable_set(obj, !sd->hidden);
463    efl_event_callback_legacy_call(obj, ELM_PANEL_EVENT_TOGGLED, NULL);
464 }
465 
466 static Eina_Bool
_state_sync(Evas_Object * obj)467 _state_sync(Evas_Object *obj)
468 {
469    ELM_PANEL_DATA_GET(obj, sd);
470    Evas_Coord pos, panel_size, w, h, threshold;
471    Eina_Bool horizontal = EINA_FALSE, reverse = EINA_FALSE;
472 
473    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
474 
475    if (!evas_object_visible_get(sd->bx)) return EINA_TRUE;
476 
477    switch (sd->orient)
478      {
479       case ELM_PANEL_ORIENT_BOTTOM:
480          reverse = EINA_TRUE;
481       case ELM_PANEL_ORIENT_TOP:
482          break;
483 
484       case ELM_PANEL_ORIENT_RIGHT:
485          reverse = EINA_TRUE;
486          EINA_FALLTHROUGH;
487       case ELM_PANEL_ORIENT_LEFT:
488          horizontal = EINA_TRUE;
489          break;
490      }
491 
492    if (horizontal)
493      {
494          if (w <= 0) return EINA_TRUE;
495 
496          panel_size = w * sd->content_size_ratio;
497          elm_interface_scrollable_content_pos_get(obj, &pos, NULL);
498          reverse ^= efl_ui_mirrored_get(obj);
499      }
500    else
501      {
502          if (h <= 0) return EINA_TRUE;
503 
504          panel_size = h * sd->content_size_ratio;
505          elm_interface_scrollable_content_pos_get(obj, NULL, &pos);
506      }
507    threshold = (sd->hidden) ? panel_size - (panel_size / 4) : (panel_size / 4);
508 
509    if (reverse)
510      {
511          if (pos > panel_size - threshold) sd->hidden = EINA_FALSE;
512          else sd->hidden = EINA_TRUE;
513      }
514    else
515      {
516          if (pos < threshold) sd->hidden = EINA_FALSE;
517          else sd->hidden = EINA_TRUE;
518      }
519 
520    return EINA_FALSE;
521 }
522 
523 static Eina_Bool
_timer_cb(void * data)524 _timer_cb(void *data)
525 {
526    ELM_PANEL_DATA_GET(data, sd);
527    Evas_Object *obj = data;
528    Evas_Coord w, h;
529 
530    sd->timer = NULL;
531 
532    if (sd->freeze)
533      {
534         elm_interface_scrollable_movement_block_set
535               (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
536         sd->freeze = EINA_FALSE;
537         elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
538         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
539         _handler_open(obj, w, h);
540      }
541 
542    return ECORE_CALLBACK_CANCEL;
543 }
544 
545 static void
_event_mouse_up(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)546 _event_mouse_up(void *data,
547                 Evas *e EINA_UNUSED,
548                 Evas_Object *obj EINA_UNUSED,
549                 void *event_info)
550 {
551    ELM_PANEL_DATA_GET(data, sd);
552    Evas_Event_Mouse_Up *ev = event_info;
553    Evas_Coord x, y, up_x, up_y, minw = 0, minh = 0;
554    evas_object_geometry_get(data, &x, &y, NULL, NULL);
555 
556    up_x = ev->canvas.x - x;
557    up_y = ev->canvas.y - y;
558 
559    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
560 
561    if ((!sd->hidden) && (up_x == sd->down_x) && (up_y == sd->down_y))
562      elm_panel_hidden_set(data, EINA_TRUE);
563 }
564 
565 static void
_on_mouse_down(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)566 _on_mouse_down(void *data,
567                Evas *e EINA_UNUSED,
568                Evas_Object *obj,
569                void *event_info)
570 {
571    Elm_Panel_Data *sd = data;
572    Evas_Event_Mouse_Down *ev = event_info;
573    Evas_Coord finger_size = elm_config_finger_size_get();
574    Evas_Coord x, y, w, h;
575    evas_object_geometry_get(obj, &x, &y, &w, &h);
576    Eina_Bool is_mirrored = efl_ui_mirrored_get(obj);
577 
578    sd->down_x = ev->canvas.x - x;
579    sd->down_y = ev->canvas.y - y;
580 
581    // if freeze state & mouse down on the edge
582    // then set timer for un-freeze
583    switch (sd->orient)
584      {
585       case ELM_PANEL_ORIENT_TOP:
586          if ((sd->freeze) && (sd->down_y >= 0) && (sd->down_y < finger_size))
587            {
588               ecore_timer_del(sd->timer);
589               sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
590            }
591          break;
592       case ELM_PANEL_ORIENT_BOTTOM:
593          if ((sd->freeze) && (sd->down_y <= h) && (sd->down_y > (h - finger_size)))
594            {
595               ecore_timer_del(sd->timer);
596               sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
597            }
598          break;
599       case ELM_PANEL_ORIENT_LEFT:
600          if ((!is_mirrored && (sd->freeze) && (sd->down_x >= 0) && (sd->down_x < finger_size)) ||
601               ((is_mirrored && (sd->freeze) && (sd->down_x <= w) && (sd->down_x > (w - finger_size)))))
602            {
603               ecore_timer_del(sd->timer);
604               sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
605            }
606          break;
607       case ELM_PANEL_ORIENT_RIGHT:
608          if ((is_mirrored && (sd->freeze) && (sd->down_x >= 0) && (sd->down_x < finger_size)) ||
609               (!is_mirrored && (sd->freeze) && (sd->down_x <= w) && (sd->down_x > (w - finger_size))))
610            {
611               ecore_timer_del(sd->timer);
612               sd->timer = ecore_timer_add(0.2, _timer_cb, obj);
613            }
614          break;
615      }
616 }
617 
618 static void
_on_mouse_move(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)619 _on_mouse_move(void *data,
620                Evas *e EINA_UNUSED,
621                Evas_Object *obj,
622                void *event_info)
623 {
624    Elm_Panel_Data *sd = data;
625    Evas_Event_Mouse_Move *ev = event_info;
626    Evas_Coord x, y, w, h, cur_x, cur_y, finger_size;
627    evas_object_geometry_get(obj, &x, &y, &w, &h);
628    finger_size = elm_config_finger_size_get();
629    Eina_Bool is_mirrored = efl_ui_mirrored_get(obj);
630 
631    cur_x = ev->cur.canvas.x - x;
632    cur_y = ev->cur.canvas.y - y;
633 
634    // if mouse down on the edge (it means sd->timer is not null)
635    //    and move more than finger size
636    // then un-freeze
637    switch (sd->orient)
638      {
639       case ELM_PANEL_ORIENT_TOP:
640          if (sd->timer && ((cur_y - sd->down_y) > finger_size))
641            {
642               elm_interface_scrollable_movement_block_set
643                  (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
644               sd->freeze = EINA_FALSE;
645               elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
646            }
647          break;
648       case ELM_PANEL_ORIENT_BOTTOM:
649          if (sd->timer && ((sd->down_y - cur_y) > finger_size))
650            {
651               elm_interface_scrollable_movement_block_set
652                  (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
653               sd->freeze = EINA_FALSE;
654               elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
655            }
656          break;
657       case ELM_PANEL_ORIENT_LEFT:
658          if ((!is_mirrored && (sd->timer) && ((cur_x - sd->down_x) > finger_size)) ||
659               ((is_mirrored) && (sd->timer) && ((sd->down_x - cur_x) > finger_size)))
660            {
661               elm_interface_scrollable_movement_block_set
662                  (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
663               sd->freeze = EINA_FALSE;
664               elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
665            }
666          break;
667       case ELM_PANEL_ORIENT_RIGHT:
668          if ((is_mirrored && (sd->timer) && ((cur_x - sd->down_x) > finger_size)) ||
669               (!is_mirrored && (sd->timer) && ((sd->down_x - cur_x) > finger_size)))
670            {
671               elm_interface_scrollable_movement_block_set
672                  (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
673               sd->freeze = EINA_FALSE;
674               elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
675            }
676          break;
677      }
678 
679    if (!sd->freeze && sd->hidden)
680      ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
681 }
682 
683 static void
_on_mouse_up(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)684 _on_mouse_up(void *data,
685              Evas *e EINA_UNUSED,
686              Evas_Object *obj,
687              void *event_info)
688 {
689    Elm_Panel_Data *sd = data;
690    Evas_Event_Mouse_Up *ev = event_info;
691    Evas_Coord w, h;
692    Eina_Bool hidden;
693 
694    hidden = sd->hidden;
695    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
696 
697    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
698 
699    if (_state_sync(obj)) return;
700 
701    if (sd->hidden) _drawer_close(obj, w, h, EINA_TRUE);
702    else _drawer_open(obj, w, h, EINA_TRUE);
703 
704    if (sd->hidden != hidden)
705      efl_event_callback_legacy_call(obj, ELM_PANEL_EVENT_TOGGLED, NULL);
706 
707    if (!sd->freeze && sd->hidden)
708      ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
709 }
710 
711 static Eina_Bool
_key_action_toggle(Evas_Object * obj,const char * params EINA_UNUSED)712 _key_action_toggle(Evas_Object *obj, const char *params EINA_UNUSED)
713 {
714    _panel_toggle(NULL, obj, NULL, NULL);
715    return EINA_TRUE;
716 }
717 
718 // _panel_elm_widget_widget_event
ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(panel,Elm_Panel_Data)719 ELM_WIDGET_KEY_DOWN_DEFAULT_IMPLEMENT(panel, Elm_Panel_Data)
720 
721 EOLIAN static Eina_Bool
722 _elm_panel_efl_ui_widget_widget_input_event_handler(Eo *obj, Elm_Panel_Data *pd, const Efl_Event *eo_event, Evas_Object *src)
723 {
724    if (src != obj) return EINA_FALSE;
725    return _panel_efl_ui_widget_widget_input_event_handler(obj, pd, eo_event, src);
726 }
727 
728 static Eina_Bool
_elm_panel_content_set(Eo * obj,Elm_Panel_Data * sd,const char * part,Evas_Object * content)729 _elm_panel_content_set(Eo *obj, Elm_Panel_Data *sd, const char *part, Evas_Object *content)
730 {
731    if (part)
732      {
733         // "elm.swallow.event" part is used for internal needs and should not be changed.
734         if (!strcmp(part, "elm.swallow.event"))
735           {
736              ERR("elm.swallow.event is being used for panel internally. Don't touch this part!");
737              return EINA_FALSE;
738           }
739         if (strcmp(part, "elm.swallow.content"))
740           {
741              Eina_Bool int_ret = EINA_TRUE;
742              int_ret = efl_content_set(efl_part(efl_super(obj, MY_CLASS), part), content);
743              return int_ret;
744           }
745      }
746 
747    if (sd->content == content) return EINA_TRUE;
748    if (sd->content)
749      evas_object_box_remove_all(sd->bx, EINA_TRUE);
750    sd->content = content;
751    if (content)
752      {
753         evas_object_box_append(sd->bx, sd->content);
754         evas_object_show(sd->content);
755         if (sd->scrollable)
756           elm_widget_sub_object_add(sd->scr_ly, sd->content);
757         else
758           elm_widget_sub_object_add(obj, sd->content);
759      }
760 
761    if (efl_finalized_get(obj))
762      elm_layout_sizing_eval(obj);
763 
764    return EINA_TRUE;
765 }
766 
767 static Evas_Object*
_elm_panel_content_get(Eo * obj,Elm_Panel_Data * sd,const char * part)768 _elm_panel_content_get(Eo *obj, Elm_Panel_Data *sd, const char *part)
769 {
770    if (part)
771      {
772         // "elm.swallow.event" part is used for internal needs and should not be changed.
773         if (!strcmp(part, "elm.swallow.event"))
774           {
775              ERR("elm.swallow.event is being used for panel internally. Don't touch this part!");
776              return NULL;
777           }
778         if (strcmp(part, "elm.swallow.content"))
779           {
780              Evas_Object *ret = NULL;
781              ret = efl_content_get(efl_part(efl_super(obj, MY_CLASS), part));
782              return ret;
783           }
784      }
785 
786    return sd->content;
787 }
788 
789 static Evas_Object*
_elm_panel_content_unset(Eo * obj,Elm_Panel_Data * sd,const char * part)790 _elm_panel_content_unset(Eo *obj, Elm_Panel_Data *sd, const char *part)
791 {
792    Evas_Object *ret = NULL;
793 
794    if (part)
795      {
796         // "elm.swallow.event" part is used for internal needs and should not be changed.
797         if (!strcmp(part, "elm.swallow.event"))
798           {
799              ERR("elm.swallow.event is being used for panel internally. Don't touch this part!");
800              return NULL;
801           }
802         if (strcmp(part, "elm.swallow.content"))
803           {
804              ret = efl_content_unset(efl_part(efl_super(obj, MY_CLASS), part));
805              return ret;
806           }
807      }
808 
809    if (!sd->content) return NULL;
810    ret = sd->content;
811 
812    evas_object_box_remove_all(sd->bx, EINA_FALSE);
813    if (sd->scrollable)
814      _elm_widget_sub_object_redirect_to_top(sd->scr_ly, sd->content);
815    sd->content = NULL;
816 
817    return ret;
818 }
819 
820 EOLIAN static void
_elm_panel_efl_canvas_group_group_add(Eo * obj,Elm_Panel_Data * priv)821 _elm_panel_efl_canvas_group_group_add(Eo *obj, Elm_Panel_Data *priv)
822 {
823    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
824 
825    efl_canvas_group_add(efl_super(obj, MY_CLASS));
826    elm_widget_can_focus_set(obj, EINA_TRUE);
827 
828    priv->panel_edje = wd->resize_obj;
829 
830    efl_ui_widget_theme_apply(obj);
831 
832    priv->bx = evas_object_box_add(evas_object_evas_get(obj));
833    evas_object_box_layout_set(priv->bx, _box_layout_cb, priv, NULL);
834    evas_object_show(priv->bx);
835 
836    elm_layout_signal_callback_add
837      (obj, "elm,action,panel,toggle", "*", _panel_toggle, obj);
838 
839    _mirrored_set(obj, efl_ui_mirrored_get(obj));
840 
841    priv->event = evas_object_rectangle_add(evas_object_evas_get(obj));
842    evas_object_color_set(priv->event, 0, 0, 0, 0);
843    evas_object_pass_events_set(priv->event, EINA_TRUE);
844    elm_widget_sub_object_add(obj, priv->event);
845 
846    /* just to bootstrap and have theme hook to work */
847    if (!elm_layout_theme_set(obj, "panel", "top", elm_widget_style_get(obj)))
848      CRI("Failed to set layout!");
849    else
850      {
851         efl_content_set(efl_part(efl_super(obj, MY_CLASS), "elm.swallow.content"), priv->bx);
852         /* trigger box recalc on manual panel calc */
853         _efl_ui_layout_subobjs_calc_set(obj, EINA_TRUE);
854         efl_ui_layout_finger_size_multiplier_set(obj, 0, 0);
855 
856         if (edje_object_part_exists
857             (wd->resize_obj, "elm.swallow.event"))
858           {
859              Evas_Coord minw = 0, minh = 0;
860 
861              elm_coords_finger_size_adjust(1, &minw, 1, &minh);
862              evas_object_size_hint_min_set(priv->event, minw, minh);
863              efl_content_set(efl_part(efl_super(obj, MY_CLASS), "elm.swallow.event"), priv->event);
864           }
865      }
866 }
867 
868 EOLIAN static void
_elm_panel_efl_canvas_group_group_del(Eo * obj,Elm_Panel_Data * sd)869 _elm_panel_efl_canvas_group_group_del(Eo *obj, Elm_Panel_Data *sd)
870 {
871    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
872 
873    sd->delete_me = EINA_TRUE;
874 
875    ELM_SAFE_FREE(sd->timer, ecore_timer_del);
876 
877    /* let's make our panel object the *last* to be processed, since it
878     * may (smart) parent other sub objects here */
879    {
880       unsigned int resize_id = 0;
881       if (eina_array_find(wd->children, wd->resize_obj, &resize_id))
882         {
883            //exchange with last
884            eina_array_data_set(wd->children, resize_id, eina_array_data_get(wd->children, eina_array_count(wd->children) - 1));
885            eina_array_data_set(wd->children, eina_array_count(wd->children) - 1, wd->resize_obj);
886         }
887    }
888 
889    efl_canvas_group_del(efl_super(obj, MY_CLASS));
890 }
891 
892 EOLIAN static void
_elm_panel_efl_gfx_entity_position_set(Eo * obj,Elm_Panel_Data * sd,Eina_Position2D pos)893 _elm_panel_efl_gfx_entity_position_set(Eo *obj, Elm_Panel_Data *sd, Eina_Position2D pos)
894 {
895    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_MOVE, 0, pos.x, pos.y))
896      return;
897 
898    efl_gfx_entity_position_set(efl_super(obj, MY_CLASS), pos);
899    efl_gfx_entity_position_set(sd->hit_rect, pos);
900 }
901 
902 static void
_scrollable_layout_resize(Eo * obj,Elm_Panel_Data * sd,Evas_Coord w,Evas_Coord h)903 _scrollable_layout_resize(Eo *obj, Elm_Panel_Data *sd, Evas_Coord w, Evas_Coord h)
904 {
905    switch (sd->orient)
906      {
907       case ELM_PANEL_ORIENT_TOP:
908       case ELM_PANEL_ORIENT_BOTTOM:
909          // vertical
910          evas_object_resize(sd->scr_ly, w, (1 + sd->content_size_ratio) * h);
911          evas_object_size_hint_min_set(sd->scr_panel, w, (sd->content_size_ratio * h));
912          evas_object_size_hint_min_set(sd->scr_event, w, h);
913          break;
914       case ELM_PANEL_ORIENT_LEFT:
915       case ELM_PANEL_ORIENT_RIGHT:
916          // horizontal
917          evas_object_resize(sd->scr_ly, (1 + sd->content_size_ratio) * w, h);
918          evas_object_size_hint_min_set(sd->scr_panel, (sd->content_size_ratio * w), h);
919          evas_object_size_hint_min_set(sd->scr_event, w, h);
920          break;
921      }
922    if (efl_finalized_get(obj))
923      elm_layout_sizing_eval(obj);
924 }
925 
926 EOLIAN static void
_elm_panel_efl_gfx_entity_size_set(Eo * obj,Elm_Panel_Data * sd,Eina_Size2D sz)927 _elm_panel_efl_gfx_entity_size_set(Eo *obj, Elm_Panel_Data *sd, Eina_Size2D sz)
928 {
929    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_RESIZE, 0, sz.w, sz.h))
930      return;
931 
932    efl_gfx_entity_size_set(efl_super(obj, MY_CLASS), sz);
933 
934    if (!sd->scrollable) return;
935 
936    efl_gfx_entity_size_set(sd->hit_rect, sz);
937    _scrollable_layout_resize(obj, sd, sz.w, sz.h);
938 }
939 
940 EOLIAN static void
_elm_panel_efl_canvas_group_group_member_add(Eo * obj,Elm_Panel_Data * sd,Evas_Object * member)941 _elm_panel_efl_canvas_group_group_member_add(Eo *obj, Elm_Panel_Data *sd, Evas_Object *member)
942 {
943    efl_canvas_group_member_add(efl_super(obj, MY_CLASS), member);
944 
945    if (sd->hit_rect) evas_object_raise(sd->hit_rect);
946 }
947 
948 EOLIAN static void
_elm_panel_efl_ui_widget_on_access_update(Eo * obj,Elm_Panel_Data * _pd,Eina_Bool is_access)949 _elm_panel_efl_ui_widget_on_access_update(Eo *obj, Elm_Panel_Data *_pd, Eina_Bool is_access)
950 {
951    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
952    Elm_Panel_Data *sd = _pd;
953 
954    if (sd->scrollable)
955      {
956         _access_obj_process(obj, is_access);
957         return;
958      }
959 
960    if (is_access)
961      _elm_access_edje_object_part_object_register
962        (obj, wd->resize_obj, "btn_icon");
963    else
964      _elm_access_edje_object_part_object_unregister
965        (obj, wd->resize_obj, "btn_icon");
966 }
967 
968 EAPI Evas_Object *
elm_panel_add(Evas_Object * parent)969 elm_panel_add(Evas_Object *parent)
970 {
971    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
972    Evas_Object *obj = elm_legacy_add(MY_CLASS, parent);
973 
974    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
975    wd->highlight_root = EINA_TRUE;
976 
977    return obj;
978 }
979 
980 EOLIAN static Eo *
_elm_panel_efl_object_constructor(Eo * obj,Elm_Panel_Data * _pd EINA_UNUSED)981 _elm_panel_efl_object_constructor(Eo *obj, Elm_Panel_Data *_pd EINA_UNUSED)
982 {
983    obj = efl_constructor(efl_super(obj, MY_CLASS));
984    efl_canvas_object_type_set(obj, MY_CLASS_NAME_LEGACY);
985    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
986    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_PANEL);
987 
988    efl_ui_focus_layer_behaviour_set(obj, EINA_FALSE, EINA_FALSE);
989 
990    return obj;
991 }
992 
993 EOLIAN static void
_elm_panel_orient_set(Eo * obj,Elm_Panel_Data * sd,Elm_Panel_Orient orient)994 _elm_panel_orient_set(Eo *obj, Elm_Panel_Data *sd, Elm_Panel_Orient orient)
995 {
996    if (sd->orient == orient) return;
997    sd->orient = orient;
998 
999    if (sd->scrollable)
1000      {
1001         _scrollable_layout_theme_set(obj, sd);
1002 
1003         if (!sd->freeze)
1004           {
1005              switch (sd->orient)
1006                {
1007                   case ELM_PANEL_ORIENT_TOP:
1008                   case ELM_PANEL_ORIENT_BOTTOM:
1009                      elm_interface_scrollable_movement_block_set
1010                            (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
1011                      break;
1012                   case ELM_PANEL_ORIENT_LEFT:
1013                   case ELM_PANEL_ORIENT_RIGHT:
1014                      elm_interface_scrollable_movement_block_set
1015                            (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
1016                      break;
1017                }
1018 
1019              sd->freeze = EINA_TRUE;
1020              elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
1021           }
1022 
1023         elm_panel_scrollable_content_size_set(obj, sd->content_size_ratio);
1024      }
1025    else
1026      _orient_set_do(obj);
1027 
1028    if (efl_finalized_get(obj))
1029      elm_layout_sizing_eval(obj);
1030 }
1031 
1032 EOLIAN static Elm_Panel_Orient
_elm_panel_orient_get(const Eo * obj EINA_UNUSED,Elm_Panel_Data * sd)1033 _elm_panel_orient_get(const Eo *obj EINA_UNUSED, Elm_Panel_Data *sd)
1034 {
1035    return sd->orient;
1036 }
1037 
1038 EOLIAN static void
_elm_panel_hidden_set(Eo * obj,Elm_Panel_Data * sd,Eina_Bool hidden)1039 _elm_panel_hidden_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool hidden)
1040 {
1041    if (sd->hidden == !!hidden)
1042      {
1043         if (sd->scrollable && sd->hidden && !sd->freeze)
1044           {
1045              Evas_Coord w, h;
1046              evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1047              _drawer_close(obj, w, h, EINA_TRUE);
1048           }
1049         return;
1050      }
1051 
1052    _panel_toggle(NULL, obj, NULL, NULL);
1053 }
1054 
1055 EOLIAN static Eina_Bool
_elm_panel_hidden_get(const Eo * obj EINA_UNUSED,Elm_Panel_Data * sd)1056 _elm_panel_hidden_get(const Eo *obj EINA_UNUSED, Elm_Panel_Data *sd)
1057 {
1058    return sd->hidden;
1059 }
1060 
1061 EOLIAN static void
_elm_panel_toggle(Eo * obj,Elm_Panel_Data * _pd EINA_UNUSED)1062 _elm_panel_toggle(Eo *obj, Elm_Panel_Data *_pd EINA_UNUSED)
1063 {
1064    _panel_toggle(NULL, obj, NULL, NULL);
1065 }
1066 
1067 EOLIAN static Eina_Rect
_elm_panel_efl_ui_widget_interest_region_get(const Eo * obj,Elm_Panel_Data * sd)1068 _elm_panel_efl_ui_widget_interest_region_get(const Eo *obj, Elm_Panel_Data *sd)
1069 {
1070    Eina_Rect r = {};
1071 
1072    elm_interface_scrollable_content_pos_get(obj, &r.x, &r.y);
1073    evas_object_geometry_get(obj, NULL, NULL, &r.w, &r.h);
1074    switch (sd->orient)
1075      {
1076       case ELM_PANEL_ORIENT_TOP:
1077       case ELM_PANEL_ORIENT_BOTTOM:
1078          r.h *= sd->content_size_ratio;
1079          break;
1080       case ELM_PANEL_ORIENT_LEFT:
1081       case ELM_PANEL_ORIENT_RIGHT:
1082          r.w *= sd->content_size_ratio;
1083          break;
1084      }
1085    if (r.w < 1) r.w = 1;
1086    if (r.h < 1) r.h = 1;
1087 
1088    return r;
1089 }
1090 
1091 static void
_anim_stop_cb(Evas_Object * obj,void * data EINA_UNUSED)1092 _anim_stop_cb(Evas_Object *obj, void *data EINA_UNUSED)
1093 {
1094    ELM_PANEL_DATA_GET(obj, sd);
1095    Evas_Object *ao;
1096    Evas_Coord pos, w, h, panel_size = 0;
1097    Eina_Bool open = EINA_FALSE, horizontal = EINA_FALSE, reverse = EINA_FALSE;
1098 
1099    if (elm_widget_disabled_get(obj)) return;
1100 
1101    switch (sd->orient)
1102      {
1103       case ELM_PANEL_ORIENT_BOTTOM:
1104          reverse = EINA_TRUE;
1105       case ELM_PANEL_ORIENT_TOP:
1106          break;
1107 
1108       case ELM_PANEL_ORIENT_RIGHT:
1109          reverse = EINA_TRUE;
1110          EINA_FALLTHROUGH;
1111       case ELM_PANEL_ORIENT_LEFT:
1112          horizontal = EINA_TRUE;
1113          break;
1114      }
1115 
1116    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1117    if (horizontal)
1118      {
1119          if (w <= 0) return;
1120 
1121          panel_size = w * sd->content_size_ratio;
1122          elm_interface_scrollable_content_pos_get(obj, &pos, NULL);
1123          reverse ^= efl_ui_mirrored_get(obj);
1124      }
1125    else
1126      {
1127          if (h <= 0) return;
1128 
1129          panel_size = h * sd->content_size_ratio;
1130          elm_interface_scrollable_content_pos_get(obj, NULL, &pos);
1131      }
1132 
1133    if (pos == 0) open = !reverse;
1134    else if (pos == panel_size) open = reverse;
1135    else return;
1136 
1137    if (open)
1138      {
1139         elm_interface_scrollable_single_direction_set
1140               (obj, ELM_SCROLLER_SINGLE_DIRECTION_HARD);
1141 
1142         //focus & access
1143         elm_object_tree_focus_allow_set(obj, EINA_TRUE);
1144         if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
1145           {
1146              ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
1147              evas_object_show(ao);
1148              _elm_access_highlight_set(ao);
1149           }
1150         else
1151           elm_object_focus_set(obj, EINA_TRUE);
1152      }
1153    else
1154      {
1155         if (horizontal)
1156           elm_interface_scrollable_movement_block_set
1157                 (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
1158         else
1159           elm_interface_scrollable_movement_block_set
1160                 (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
1161         sd->freeze = EINA_TRUE;
1162         elm_layout_signal_emit(sd->scr_ly, "elm,state,content,hidden", "elm");
1163 
1164         elm_interface_scrollable_single_direction_set
1165               (obj, ELM_SCROLLER_SINGLE_DIRECTION_NONE);
1166 
1167         //focus & access
1168         elm_object_tree_focus_allow_set(obj, EINA_FALSE);
1169         if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
1170           {
1171              ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
1172              evas_object_hide(ao);
1173           }
1174      }
1175 }
1176 
1177 static void
_scroll_cb(Evas_Object * obj,void * data EINA_UNUSED)1178 _scroll_cb(Evas_Object *obj, void *data EINA_UNUSED)
1179 {
1180    ELM_PANEL_DATA_GET(obj, sd);
1181    Elm_Panel_Scroll_Info event;
1182    Evas_Coord x, y, w, h;
1183 
1184    if (elm_widget_disabled_get(obj)) return;
1185    // in the case of
1186    // freeze_set(FALSE) -> mouse_up -> freeze_set(TRUE) -> scroll
1187    if (sd->freeze)
1188      {
1189         elm_interface_scrollable_movement_block_set
1190               (obj, EFL_UI_LAYOUT_ORIENTATION_DEFAULT);
1191         sd->freeze = EINA_FALSE;
1192         elm_layout_signal_emit(sd->scr_ly, "elm,state,content,visible", "elm");
1193      }
1194 
1195    elm_interface_scrollable_content_pos_get(obj, &x, &y);
1196    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1197 
1198    switch (sd->orient)
1199      {
1200       case ELM_PANEL_ORIENT_TOP:
1201          event.rel_x = 1;
1202          event.rel_y = 1 - ((double) y / (double) ((sd->content_size_ratio) * h));
1203         break;
1204       case ELM_PANEL_ORIENT_BOTTOM:
1205          event.rel_x = 1;
1206          event.rel_y = (double) y / (double) ((sd->content_size_ratio) * h);
1207         break;
1208       case ELM_PANEL_ORIENT_LEFT:
1209         if (!efl_ui_mirrored_get(obj))
1210           {
1211              event.rel_x = 1 - ((double) x / (double) ((sd->content_size_ratio) * w));
1212              event.rel_y = 1;
1213           }
1214         else
1215           {
1216              event.rel_x = (double) x / (double) ((sd->content_size_ratio) * w);
1217              event.rel_y = 1;
1218            }
1219         break;
1220       case ELM_PANEL_ORIENT_RIGHT:
1221         if (efl_ui_mirrored_get(obj))
1222           {
1223              event.rel_x = 1 - ((double) x / (double) ((sd->content_size_ratio) * w));
1224              event.rel_y = 1;
1225           }
1226         else
1227           {
1228              event.rel_x = (double) x / (double) ((sd->content_size_ratio) * w);
1229              event.rel_y = 1;
1230           }
1231         break;
1232      }
1233    evas_object_smart_callback_call(obj, "scroll", &event);
1234 }
1235 
1236 EOLIAN static void
_elm_panel_efl_ui_widget_disabled_set(Eo * obj,Elm_Panel_Data * sd,Eina_Bool disabled)1237 _elm_panel_efl_ui_widget_disabled_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool disabled)
1238 {
1239    efl_ui_widget_disabled_set(efl_super(obj, MY_CLASS), disabled);
1240 
1241    if (sd->scrollable)
1242      {
1243         if (efl_ui_widget_disabled_get(obj) && sd->callback_added)
1244           {
1245              switch (sd->orient)
1246                {
1247                   case ELM_PANEL_ORIENT_BOTTOM:
1248                   case ELM_PANEL_ORIENT_TOP:
1249                      elm_interface_scrollable_movement_block_set
1250                         (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
1251                      break;
1252 
1253                   case ELM_PANEL_ORIENT_RIGHT:
1254                   case ELM_PANEL_ORIENT_LEFT:
1255                      elm_interface_scrollable_movement_block_set
1256                         (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
1257                      break;
1258                }
1259 
1260              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN,
1261                                             _on_mouse_down);
1262              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE,
1263                                             _on_mouse_move);
1264              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP,
1265                                             _on_mouse_up);
1266              evas_object_event_callback_del(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
1267                                             _event_mouse_up);
1268 
1269              sd->callback_added = EINA_FALSE;
1270           }
1271         else if (!efl_ui_widget_disabled_get(obj) && !sd->callback_added)
1272           {
1273              switch (sd->orient)
1274                {
1275                   case ELM_PANEL_ORIENT_BOTTOM:
1276                   case ELM_PANEL_ORIENT_TOP:
1277                      elm_interface_scrollable_movement_block_set
1278                         (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
1279                      break;
1280 
1281                   case ELM_PANEL_ORIENT_RIGHT:
1282                   case ELM_PANEL_ORIENT_LEFT:
1283                      elm_interface_scrollable_movement_block_set
1284                         (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
1285                      break;
1286                }
1287 
1288              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
1289                                             _on_mouse_down, sd);
1290              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
1291                                             _on_mouse_move, sd);
1292              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1293                                             _on_mouse_up, sd);
1294              evas_object_event_callback_add(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
1295                                             _event_mouse_up, obj);
1296 
1297              sd->callback_added = EINA_TRUE;
1298           }
1299      }
1300 }
1301 
1302 EOLIAN static double
_elm_panel_scrollable_content_size_get(const Eo * obj EINA_UNUSED,Elm_Panel_Data * sd)1303 _elm_panel_scrollable_content_size_get(const Eo *obj EINA_UNUSED, Elm_Panel_Data *sd)
1304 {
1305    return sd->content_size_ratio;
1306 }
1307 
1308 EOLIAN static void
_elm_panel_scrollable_content_size_set(Eo * obj,Elm_Panel_Data * sd,double ratio)1309 _elm_panel_scrollable_content_size_set(Eo *obj, Elm_Panel_Data *sd, double ratio)
1310 {
1311    if (ratio < 0) ratio = 0;
1312    else if (ratio > 1.0) ratio = 1.0;
1313 
1314    sd->content_size_ratio = ratio;
1315 
1316    if (sd->scrollable)
1317      {
1318         Evas_Coord w, h;
1319         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1320 
1321         _scrollable_layout_resize(obj, sd, w, h);
1322      }
1323 }
1324 
1325 EOLIAN static Eina_Bool
_elm_panel_scrollable_get(const Eo * obj EINA_UNUSED,Elm_Panel_Data * sd)1326 _elm_panel_scrollable_get(const Eo *obj EINA_UNUSED, Elm_Panel_Data *sd)
1327 {
1328    return sd->scrollable;
1329 }
1330 
1331 EOLIAN static void
_elm_panel_scrollable_set(Eo * obj,Elm_Panel_Data * sd,Eina_Bool scrollable)1332 _elm_panel_scrollable_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool scrollable)
1333 {
1334    scrollable = !!scrollable;
1335    if (sd->scrollable == scrollable) return;
1336    sd->scrollable = scrollable;
1337 
1338    if (scrollable)
1339      {
1340         efl_content_unset(efl_part(efl_super(obj, MY_CLASS), "elm.swallow.content"));
1341 
1342         //Hide previous resize object
1343         evas_object_hide(sd->panel_edje);
1344         elm_widget_resize_object_set(obj, NULL);
1345         elm_widget_sub_object_add(obj, sd->panel_edje);
1346 
1347         if (!sd->scr_edje)
1348           {
1349              const char *handler_size;
1350 
1351              sd->scr_edje = edje_object_add(evas_object_evas_get(obj));
1352              elm_widget_theme_object_set(obj, sd->scr_edje, "scroller", "panel",
1353                                          elm_widget_style_get(obj));
1354              evas_object_size_hint_weight_set
1355                 (sd->scr_edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1356              evas_object_size_hint_align_set
1357                 (sd->scr_edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
1358 
1359              handler_size = edje_object_data_get(sd->scr_edje, "handler_size");
1360              if (handler_size)
1361                sd->handler_size = (int) (elm_object_scale_get(obj)) * (atoi(handler_size));
1362           }
1363 
1364         elm_widget_resize_object_set(obj, sd->scr_edje);
1365 
1366         if (!sd->hit_rect)
1367           {
1368              sd->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
1369              evas_object_smart_member_add(sd->hit_rect, obj);
1370              elm_widget_sub_object_add(obj, sd->hit_rect);
1371              evas_object_color_set(sd->hit_rect, 0, 0, 0, 0);
1372              evas_object_show(sd->hit_rect);
1373              evas_object_repeat_events_set(sd->hit_rect, EINA_TRUE);
1374 
1375              elm_interface_scrollable_objects_set(obj, sd->scr_edje, sd->hit_rect);
1376              elm_interface_scrollable_animate_stop_cb_set(obj, _anim_stop_cb);
1377              elm_interface_scrollable_scroll_cb_set(obj, _scroll_cb);
1378           }
1379 
1380         if (!sd->scr_ly)
1381           {
1382              sd->scr_ly = elm_layout_add(obj);
1383              evas_object_smart_member_add(sd->scr_ly, obj);
1384              elm_widget_sub_object_add(obj, sd->scr_ly);
1385              _scrollable_layout_theme_set(obj, sd);
1386 
1387              sd->scr_panel = evas_object_rectangle_add(evas_object_evas_get(obj));
1388              evas_object_color_set(sd->scr_panel, 0, 0, 0, 0);
1389              elm_widget_sub_object_add(obj, sd->scr_panel);
1390              if (!elm_layout_content_set(sd->scr_ly, "elm.panel_area", sd->scr_panel))
1391                elm_layout_content_set(sd->scr_ly, "panel_area", sd->scr_panel);
1392 
1393              sd->scr_event = evas_object_rectangle_add(evas_object_evas_get(obj));
1394              evas_object_color_set(sd->scr_event, 0, 0, 0, 0);
1395              elm_widget_sub_object_add(obj, sd->scr_event);
1396              if (!elm_layout_content_set(sd->scr_ly, "elm.event_area", sd->scr_event))
1397                elm_layout_content_set(sd->scr_ly, "event_area", sd->scr_event);
1398           }
1399         else _scrollable_layout_theme_set(obj, sd);
1400 
1401         elm_interface_scrollable_content_set(obj, sd->scr_ly);
1402         sd->freeze = EINA_TRUE;
1403         elm_layout_content_set(sd->scr_ly, "elm.swallow.content", sd->bx);
1404         if (sd->content) elm_widget_sub_object_add(sd->scr_ly, sd->content);
1405 
1406         if (sd->hidden)
1407           {
1408              switch (sd->orient)
1409                {
1410                 case ELM_PANEL_ORIENT_TOP:
1411                 case ELM_PANEL_ORIENT_BOTTOM:
1412                    elm_interface_scrollable_movement_block_set
1413                       (obj, EFL_UI_LAYOUT_ORIENTATION_VERTICAL);
1414                    break;
1415                 case ELM_PANEL_ORIENT_LEFT:
1416                 case ELM_PANEL_ORIENT_RIGHT:
1417                    elm_interface_scrollable_movement_block_set
1418                       (obj, EFL_UI_LAYOUT_ORIENTATION_HORIZONTAL);
1419                    break;
1420                }
1421           }
1422 
1423         elm_interface_scrollable_single_direction_set
1424               (obj, ELM_SCROLLER_SINGLE_DIRECTION_NONE);
1425 
1426         if (!elm_widget_disabled_get(obj) && !sd->callback_added)
1427           {
1428              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
1429                                             _on_mouse_down, sd);
1430              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE,
1431                                             _on_mouse_move, sd);
1432              evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
1433                                             _on_mouse_up, sd);
1434              evas_object_event_callback_add(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
1435                                             _event_mouse_up, obj);
1436 
1437              sd->callback_added = EINA_TRUE;
1438           }
1439 
1440      }
1441    else
1442      {
1443         elm_interface_scrollable_content_set(obj, NULL);
1444 
1445         if (sd->callback_added)
1446           {
1447              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_DOWN, _on_mouse_down);
1448              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_MOVE, _on_mouse_move);
1449              evas_object_event_callback_del(obj, EVAS_CALLBACK_MOUSE_UP, _on_mouse_up);
1450              evas_object_event_callback_del(sd->scr_event, EVAS_CALLBACK_MOUSE_UP,
1451                                             _event_mouse_up);
1452 
1453              sd->callback_added = EINA_FALSE;
1454           }
1455 
1456         elm_widget_resize_object_set(obj, NULL);
1457         elm_widget_sub_object_add(obj, sd->scr_edje);
1458 
1459         elm_widget_resize_object_set(obj, sd->panel_edje);
1460 
1461         _orient_set_do(obj);
1462 
1463         if (sd->hidden)
1464           {
1465              elm_layout_signal_emit(obj, "elm,action,hide,no_animate", "elm");
1466              evas_object_repeat_events_set(obj, EINA_TRUE);
1467           }
1468         else
1469           {
1470              elm_layout_signal_emit(obj, "elm,action,show,no_animate", "elm");
1471              evas_object_repeat_events_set(obj, EINA_FALSE);
1472           }
1473 
1474         edje_object_message_signal_process(sd->panel_edje);
1475 
1476         evas_object_hide(sd->scr_ly);
1477         elm_layout_content_unset(sd->scr_ly, "elm.swallow.content");
1478         efl_content_set(efl_part(efl_super(obj, MY_CLASS), "elm.swallow.content"), sd->bx);
1479         if (sd->content) elm_widget_sub_object_add(obj, sd->content);
1480      }
1481 }
1482 
1483 EOLIAN static void
_elm_panel_efl_ui_i18n_mirrored_set(Eo * obj,Elm_Panel_Data * sd,Eina_Bool mirrored)1484 _elm_panel_efl_ui_i18n_mirrored_set(Eo *obj, Elm_Panel_Data *sd, Eina_Bool mirrored)
1485 {
1486    if (sd->scrollable)
1487      efl_ui_mirrored_set(efl_cast(obj, ELM_INTERFACE_SCROLLABLE_MIXIN), mirrored);
1488    else
1489      efl_ui_mirrored_set(efl_cast(obj, EFL_UI_WIDGET_CLASS), mirrored);
1490 }
1491 
1492 static void
_elm_panel_class_constructor(Efl_Class * klass)1493 _elm_panel_class_constructor(Efl_Class *klass)
1494 {
1495    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
1496 }
1497 
1498 EOLIAN const Efl_Access_Action_Data *
_elm_panel_efl_access_widget_action_elm_actions_get(const Eo * obj EINA_UNUSED,Elm_Panel_Data * pd EINA_UNUSED)1499 _elm_panel_efl_access_widget_action_elm_actions_get(const Eo *obj EINA_UNUSED, Elm_Panel_Data *pd EINA_UNUSED)
1500 {
1501    static Efl_Access_Action_Data atspi_actions[] = {
1502           { "toggle", "toggle", NULL, _key_action_toggle},
1503           { NULL, NULL, NULL, NULL }
1504    };
1505    return &atspi_actions[0];
1506 }
1507 
1508 /* Efl.Part begin */
1509 
1510 ELM_PART_OVERRIDE(elm_panel, ELM_PANEL, Elm_Panel_Data)
1511 ELM_PART_OVERRIDE_CONTENT_SET(elm_panel, ELM_PANEL, Elm_Panel_Data)
1512 ELM_PART_OVERRIDE_CONTENT_GET(elm_panel, ELM_PANEL, Elm_Panel_Data)
1513 ELM_PART_OVERRIDE_CONTENT_UNSET(elm_panel, ELM_PANEL, Elm_Panel_Data)
1514 #include "elm_panel_part.eo.c"
1515 
1516 /* Efl.Part end */
1517 
1518 /* Internal EO APIs and hidden overrides */
1519 
1520 #define ELM_PANEL_EXTRA_OPS \
1521    EFL_CANVAS_GROUP_CALC_OPS(elm_panel), \
1522    EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_panel)
1523 
1524 #include "elm_panel_eo.c"
1525