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