Initialize Tizen 2.3
[framework/uifw/elementary.git] / wearable / src / lib / elm_panel.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_panel.h"
4
5 #define THRESHOLD 10
6
7 EAPI const char ELM_PANEL_SMART_NAME[] = "elm_panel";
8
9 static const char ACCESS_OUTLINE_PART[] = "elm.swallow.content";
10
11 static const char SIG_SCROLL[] = "scroll";
12
13 static const Evas_Smart_Cb_Description _smart_callbacks[] =
14 {
15    {SIG_SCROLL, ""}
16 };
17
18 static const Evas_Smart_Interface *_smart_interfaces[] =
19 {
20    (Evas_Smart_Interface *)&ELM_SCROLLABLE_IFACE, NULL
21 };
22
23 EVAS_SMART_SUBCLASS_IFACE_NEW
24   (ELM_PANEL_SMART_NAME, _elm_panel, Elm_Panel_Smart_Class,
25   Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks,
26   _smart_interfaces);
27
28 static void
29 _mirrored_set(Evas_Object *obj,
30               Eina_Bool rtl)
31 {
32    ELM_PANEL_DATA_GET(obj, sd);
33
34    elm_widget_mirrored_set(sd->bx, rtl);
35    elm_panel_orient_set(obj, elm_panel_orient_get(obj));
36 }
37
38 static void
39 _hidden_content_region_set(Evas_Object *obj, Evas_Coord w, Evas_Coord h,
40                            Eina_Bool anim)
41 {
42    ELM_PANEL_DATA_GET(obj, sd);
43
44    if (sd->hidden)
45      {
46         //Move the content to the outside of the panel in order to be hidden.
47         if (sd->orient == ELM_PANEL_ORIENT_TOP ||
48             sd->orient == ELM_PANEL_ORIENT_LEFT)
49           {
50              if (anim) sd->s_iface->region_bring_in(obj, sd->panel_w, 0, w, h);
51              else
52                {
53                   sd->s_iface->content_region_show(obj, sd->panel_w, 0, w, h);
54                   if (!sd->hold)
55                     {
56                        sd->s_iface->hold_set(obj, EINA_TRUE);
57                        sd->hold = EINA_TRUE;
58                        elm_layout_signal_emit(sd->ly, "elm,state,content,hidden", "elm");
59                        elm_object_signal_emit(obj, "elm,state,hold", "elm");
60                        sd->scrolled = EINA_FALSE;
61                     }
62                }
63           }
64         else
65           {
66              //FIXME: Set position properly in case of panel visible.
67              if (anim) sd->s_iface->region_bring_in(obj, 0, 0, w, h);
68              else
69                {
70                   sd->s_iface->content_region_show(obj, 0, 0, w, h);
71                   if (!sd->hold)
72                     {
73                        sd->s_iface->hold_set(obj, EINA_TRUE);
74                        sd->hold = EINA_TRUE;
75                        elm_layout_signal_emit(sd->ly, "elm,state,content,hidden", "elm");
76                        elm_object_signal_emit(obj, "elm,state,hold", "elm");
77                        sd->scrolled = EINA_FALSE;
78                     }
79                }
80           }
81      }
82    else
83      {
84         if (sd->orient == ELM_PANEL_ORIENT_TOP ||
85             sd->orient == ELM_PANEL_ORIENT_LEFT)
86           {
87              if (anim) sd->s_iface->region_bring_in(obj, 0, 0, w, h);
88              else
89                {
90                   sd->s_iface->content_region_show(obj, 0, 0, w, h);
91                   if (sd->hold)
92                     {
93                        sd->s_iface->hold_set(obj, EINA_FALSE);
94                        sd->hold = EINA_FALSE;
95                        elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
96                        elm_object_signal_emit(obj, "elm,state,unhold", "elm");
97                     }
98                }
99           }
100         else
101           {
102              if (anim) sd->s_iface->region_bring_in(obj, sd->panel_w, 0, w, h);
103              else
104                {
105                   sd->s_iface->content_region_show(obj, sd->panel_w, 0, w, h);
106                   if (sd->hold)
107                     {
108                        sd->s_iface->hold_set(obj, EINA_FALSE);
109                        sd->hold = EINA_FALSE;
110                        elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
111                        elm_object_signal_emit(obj, "elm,state,unhold", "elm");
112                     }
113                }
114           }
115      }
116 }
117
118 static void
119 _elm_panel_smart_sizing_eval(Evas_Object *obj)
120 {
121    Evas_Coord mw = -1, mh = -1;
122
123    ELM_PANEL_DATA_GET(obj, sd);
124
125    if (sd->on_deletion) return;
126
127    evas_object_smart_calculate(sd->bx);
128    edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &mw, &mh);
129    evas_object_size_hint_min_set(obj, mw, mh);
130    evas_object_size_hint_max_set(obj, -1, -1);
131 }
132
133 static char *
134 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
135 {
136    ELM_PANEL_DATA_GET(data, sd);
137
138    if (!sd->hidden) return strdup(E_("state: opened"));
139    else return strdup(E_("state: closed"));
140
141    return NULL;
142 }
143
144 static void
145 _orient_set_do_internal(Evas_Object *obj)
146 {
147    ELM_PANEL_DATA_GET(obj, sd);
148
149    if (!sd->scrollable) return;
150
151    switch (sd->orient)
152      {
153       case ELM_PANEL_ORIENT_TOP:
154         elm_layout_theme_set(sd->ly, "panel", "top/internal",
155                              elm_widget_style_get(obj));
156         break;
157       case ELM_PANEL_ORIENT_BOTTOM:
158         elm_layout_theme_set(sd->ly, "panel", "bottom/internal",
159                              elm_widget_style_get(obj));
160         break;
161       case ELM_PANEL_ORIENT_LEFT:
162         if (!elm_widget_mirrored_get(obj))
163           {
164              elm_layout_theme_set(sd->ly, "panel", "left/internal",
165                                   elm_widget_style_get(obj));
166           }
167         else
168           {
169              elm_layout_theme_set(sd->ly, "panel", "right/internal",
170                                   elm_widget_style_get(obj));
171           }
172         break;
173       case ELM_PANEL_ORIENT_RIGHT:
174         if (!elm_widget_mirrored_get(obj))
175           {
176              elm_layout_theme_set(sd->ly, "panel", "right/internal",
177                                   elm_widget_style_get(obj));
178           }
179         else
180           {
181              elm_layout_theme_set(sd->ly, "panel", "left/internal",
182                                  elm_widget_style_get(obj));
183           }
184         break;
185      }
186    const char *panel_w = edje_object_data_get(elm_layout_edje_get(sd->ly),
187                                               "content_width");
188    const char *panel_h = edje_object_data_get(elm_layout_edje_get(sd->ly),
189                                               "content_height");
190    sd->panel_w = (int) (elm_object_scale_get(obj) * (double) atoi(panel_w));
191    sd->panel_h = (int) (elm_object_scale_get(obj) * (double) atoi(panel_h));
192 }
193
194 static Evas_Object *
195 _access_object_get(const Evas_Object *obj, const char *part)
196 {
197    Evas_Object *po, *ao;
198    ELM_PANEL_DATA_GET(obj, sd);
199
200    po = (Evas_Object *)edje_object_part_object_get
201       (elm_layout_edje_get(sd->ly), part);
202    ao = evas_object_data_get(po, "_part_access_obj");
203
204    return ao;
205 }
206
207 static void
208 _access_activate_cb(void *data,
209                     Evas_Object *part_obj __UNUSED__,
210                     Elm_Object_Item *item __UNUSED__)
211 {
212    elm_panel_hidden_set(data, EINA_TRUE);
213 }
214
215 static void
216 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
217 {
218    Evas_Object *ao;
219    ELM_PANEL_DATA_GET(obj, sd);
220
221    if (is_access)
222      {
223         ao = _elm_access_edje_object_part_object_register
224            (obj, elm_layout_edje_get(sd->ly), ACCESS_OUTLINE_PART);
225         _elm_access_text_set(_elm_access_object_get(ao),
226                              ELM_ACCESS_TYPE, E_("A drawer is open, double tap to close it"));
227         _elm_access_activate_callback_set
228            (_elm_access_object_get(ao), _access_activate_cb, obj);
229      }
230    else
231      {
232         _elm_access_edje_object_part_object_unregister
233            (obj, elm_layout_edje_get(sd->ly), ACCESS_OUTLINE_PART);
234      }
235 }
236
237 static void
238 _orient_set_do(Evas_Object *obj)
239 {
240    Evas_Coord handler_w = 0, handler_h = 0;
241
242    ELM_PANEL_DATA_GET(obj, sd);
243    ELM_WIDGET_DATA_GET(obj, wsd);
244
245    switch (sd->orient)
246      {
247       case ELM_PANEL_ORIENT_TOP:
248         elm_layout_theme_set(obj, "panel", "top", elm_widget_style_get(obj));
249         break;
250       case ELM_PANEL_ORIENT_BOTTOM:
251         elm_layout_theme_set
252           (obj, "panel", "bottom", elm_widget_style_get(obj));
253         break;
254       case ELM_PANEL_ORIENT_LEFT:
255         if (!elm_widget_mirrored_get(obj))
256           {
257              elm_layout_theme_set
258                 (obj, "panel", "left", elm_widget_style_get(obj));
259           }
260         else
261           {
262              elm_layout_theme_set
263                 (obj, "panel", "right", elm_widget_style_get(obj));
264           }
265         break;
266       case ELM_PANEL_ORIENT_RIGHT:
267         if (!elm_widget_mirrored_get(obj))
268           {
269              elm_layout_theme_set
270                 (obj, "panel", "right", elm_widget_style_get(obj));
271           }
272         else
273           {
274              elm_layout_theme_set
275                 (obj, "panel", "left", elm_widget_style_get(obj));
276           }
277         break;
278      }
279    edje_object_part_geometry_get(wsd->resize_obj, "handler", NULL, NULL, &handler_w, &handler_h);
280    sd->handler_w = (int) (elm_object_scale_get(obj) * (double) (int)(handler_w));
281    sd->handler_h = (int) (elm_object_scale_get(obj) * (double) (int)(handler_h));
282
283    _orient_set_do_internal(obj);
284
285    /* drawer access*/
286    if (sd->scrollable)
287      {
288         if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
289         return;
290      }
291    /* drawer access*/
292
293    /* access */
294    if (_elm_config->access_mode == ELM_ACCESS_MODE_ON)
295      {
296         Evas_Object *ao;
297         ao = _elm_access_edje_object_part_object_register
298                (obj, ELM_WIDGET_DATA(sd)->resize_obj, "btn_icon");
299         _elm_access_text_set(_elm_access_object_get(ao),
300                              ELM_ACCESS_TYPE, E_("panel button"));
301         _elm_access_callback_set
302           (_elm_access_object_get(ao), ELM_ACCESS_STATE, _access_state_cb, obj);
303      }
304 }
305
306 static Eina_Bool
307 _elm_panel_smart_theme(Evas_Object *obj)
308 {
309    const char *str;
310
311    ELM_PANEL_DATA_GET(obj, sd);
312
313    if (!ELM_WIDGET_CLASS(_elm_panel_parent_sc)->theme(obj))
314      return EINA_FALSE;
315
316    _mirrored_set(obj, elm_widget_mirrored_get(obj));
317
318    str = edje_object_data_get
319        (ELM_WIDGET_DATA(sd)->resize_obj, "focus_highlight");
320    if ((str) && (!strcmp(str, "on")))
321      elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
322    else
323      elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
324
325    _orient_set_do(obj);
326
327    elm_layout_sizing_eval(obj);
328
329    return EINA_TRUE;
330 }
331
332 static Eina_Bool
333 _elm_panel_smart_focus_next(const Evas_Object *obj,
334                             Elm_Focus_Direction dir,
335                             Evas_Object **next)
336 {
337    Evas_Object *cur;
338    Eina_List *items = NULL;
339    Eina_Bool ret = EINA_FALSE;
340
341    ELM_PANEL_DATA_GET(obj, sd);
342
343    if (sd->scrollable)
344      {
345         if (sd->hidden)
346           return EINA_FALSE;
347
348         if (_elm_config->access_mode)
349           {
350              Evas_Object *ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
351              if (ao) items = eina_list_append(items, ao);
352           }
353
354         items = eina_list_append(items, sd->ly);
355
356         if (_elm_config->access_mode)
357           {
358              ret = elm_widget_focus_list_next_get
359                 (obj, items, eina_list_data_get, dir, next);
360              eina_list_free(items);
361
362              return ret;
363           }
364         else
365           return elm_widget_focus_next_get(sd->ly, dir, next);
366      }
367
368    if (!sd->content)
369      return EINA_FALSE;
370
371    cur = sd->content;
372
373    /* Try to Focus cycle in subitem */
374    if (!sd->hidden)
375      return elm_widget_focus_next_get(cur, dir, next);
376
377    /* access */
378    if (_elm_config->access_mode != ELM_ACCESS_MODE_OFF)
379      {
380         Evas_Object *ao, *po;
381         po = (Evas_Object *)edje_object_part_object_get
382                (ELM_WIDGET_DATA(sd)->resize_obj, "btn_icon");
383         ao = evas_object_data_get(po, "_part_access_obj");
384         _elm_access_highlight_set(ao, EINA_FALSE);
385      }
386
387    /* Return */
388    *next = (Evas_Object *)obj;
389    return !elm_widget_focus_get(obj);
390 }
391
392 static void
393 _box_layout_cb(Evas_Object *o,
394                Evas_Object_Box_Data *priv,
395                void *data __UNUSED__)
396 {
397    _els_box_layout(o, priv, EINA_TRUE, EINA_FALSE, EINA_FALSE);
398 }
399
400 static void
401 _panel_toggle(void *data __UNUSED__,
402               Evas_Object *obj,
403               const char *emission __UNUSED__,
404               const char *source __UNUSED__)
405 {
406    int w, h;
407    ELM_PANEL_DATA_GET(obj, sd);
408
409    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
410
411    sd->hidden = !sd->hidden;
412
413    if (sd->hidden)
414      {
415         if (sd->scrollable)
416           elm_object_signal_emit(obj, "elm,state,inactive", "elm");
417         else
418           {
419              elm_layout_signal_emit(obj, "elm,action,hide", "elm");
420
421              if (elm_widget_focus_get(sd->content))
422                {
423                   elm_widget_focused_object_clear(obj);
424                   elm_widget_focus_steal(obj);
425                }
426           }
427      }
428    else
429      {
430         if (sd->scrollable)
431           {
432              if (sd->hold)
433                {
434                   sd->s_iface->hold_set(obj, EINA_FALSE);
435                   sd->hold = EINA_FALSE;
436                   elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
437                   elm_object_signal_emit(obj, "elm,state,unhold", "elm");
438                }
439
440              elm_object_signal_emit(obj, "elm,state,active", "elm");
441           }
442         else
443           elm_layout_signal_emit(obj, "elm,action,show", "elm");
444      }
445
446    _hidden_content_region_set(obj, w, h, EINA_TRUE);
447
448    edje_object_message_signal_process(ELM_WIDGET_DATA(sd)->resize_obj);
449 }
450
451 static Eina_Bool
452 _elm_panel_smart_event(Evas_Object *obj,
453                        Evas_Object *src,
454                        Evas_Callback_Type type,
455                        void *event_info)
456 {
457    // TIZEN ONLY (2013.11.27): when panel is scrollable, ignore smart event
458    ELM_PANEL_DATA_GET(obj, sd);
459    if (sd->scrollable) return EINA_FALSE;
460    // TIZEN ONLY
461
462    Evas_Event_Key_Down *ev = event_info;
463
464    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
465    if ((src != obj) || (type != EVAS_CALLBACK_KEY_DOWN)) return EINA_FALSE;
466    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
467
468    if ((strcmp(ev->keyname, "Return")) &&
469        (strcmp(ev->keyname, "KP_Enter")))
470      return EINA_FALSE;
471
472    _panel_toggle(NULL, obj, NULL, NULL);
473
474    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
475    return EINA_TRUE;
476 }
477
478 static Eina_Bool
479 _elm_panel_smart_content_set(Evas_Object *obj,
480                              const char *part,
481                              Evas_Object *content)
482 {
483    int w, h;
484
485    ELM_PANEL_DATA_GET(obj, sd);
486
487    if (part && strcmp(part, "default"))
488      return ELM_CONTAINER_CLASS(_elm_panel_parent_sc)->content_set
489               (obj, part, content);
490
491    if (sd->content == content) return EINA_TRUE;
492
493    if (!sd->scrollable && sd->content)
494      evas_object_box_remove_all(sd->bx, EINA_TRUE);
495
496    sd->content = content;
497
498    if (content)
499      {
500         if (sd->scrollable)
501           {
502              elm_layout_content_set(sd->ly, "elm.swallow.content", sd->content);
503              sd->s_iface->content_set(obj, sd->bx);
504              evas_object_geometry_get(obj, NULL, NULL, &w, &h);
505              _hidden_content_region_set(obj, w, h, EINA_FALSE);
506           }
507         else
508           {
509              evas_object_box_append(sd->bx, sd->content);
510              evas_object_show(sd->content);
511           }
512      }
513
514    elm_layout_sizing_eval(obj);
515
516    return EINA_TRUE;
517 }
518
519 static Evas_Object *
520 _elm_panel_smart_content_get(const Evas_Object *obj,
521                              const char *part)
522 {
523    ELM_PANEL_DATA_GET(obj, sd);
524
525    if (part && strcmp(part, "default"))
526      return ELM_CONTAINER_CLASS(_elm_panel_parent_sc)->content_get(obj, part);
527
528    return sd->content;
529 }
530
531 static Evas_Object *
532 _elm_panel_smart_content_unset(Evas_Object *obj,
533                                const char *part)
534 {
535    Evas_Object *content;
536
537    ELM_PANEL_DATA_GET(obj, sd);
538
539    if (part && strcmp(part, "default"))
540      return ELM_CONTAINER_CLASS
541               (_elm_panel_parent_sc)->content_unset(obj, part);
542
543    if (!sd->content) return NULL;
544    content = sd->content;
545
546    sd->content = NULL;
547
548    if (sd->scrollable) elm_layout_content_unset(sd->ly, "elm.swallow.content");
549    else evas_object_box_remove_all(sd->bx, EINA_FALSE);
550
551    return content;
552 }
553
554 static void
555 _hidden_state_change(Evas_Object *obj, Eina_Bool handler_bring_in)
556 {
557    Evas_Object *ao;
558    int x, w, h;
559    ELM_PANEL_DATA_GET(obj, sd);
560
561    if (!sd->scrollable) return;
562    if (sd->hold) return;
563
564    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
565    sd->s_iface->content_pos_get(obj, &x, NULL);
566
567    if (sd->orient == ELM_PANEL_ORIENT_TOP ||
568        sd->orient == ELM_PANEL_ORIENT_LEFT)
569      {
570         //1. handler open
571         if (x == (sd->panel_w - sd->handler_w))
572           {
573              if (!handler_bring_in) //_anim_stop_cb function
574                {
575                   sd->scroll_dir = 0;
576                   return;
577                }
578              else if (sd->scroll_dir == 0) //_on_mouse_up function -> handler close
579                {
580                   sd->s_iface->region_bring_in(obj, sd->panel_w, 0, w, h);
581                   return;
582                }
583           }
584         //2. drawer open
585         else if (x == 0)
586           {
587              if (sd->hidden)
588                {
589                   elm_object_signal_emit(obj, "elm,state,active", "elm");
590                   sd->hidden = EINA_FALSE;
591                }
592              sd->scroll_dir = 0;
593
594              // drawer focus & access
595              elm_object_tree_focus_allow_set(obj, EINA_TRUE);
596              if (_elm_config->access_mode)
597                {
598                   ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
599                   evas_object_show(ao);
600                }
601              elm_object_focus_set(obj, EINA_TRUE);
602
603              return;
604           }
605         //3. drawer close
606         else if (x == sd->panel_w)
607           {
608              sd->s_iface->hold_set(obj, EINA_TRUE);
609              sd->hold = EINA_TRUE;
610              elm_layout_signal_emit(sd->ly, "elm,state,content,hidden", "elm");
611              elm_object_signal_emit(obj, "elm,state,hold", "elm");
612              sd->scrolled = EINA_FALSE;
613
614              if (!sd->hidden)
615                {
616                   elm_object_signal_emit(obj, "elm,state,inactive", "elm");
617                   sd->hidden = EINA_TRUE;
618                }
619              sd->scroll_dir = 0;
620
621              // drawer focus & access
622              elm_object_tree_focus_allow_set(obj, EINA_FALSE);
623              if (_elm_config->access_mode)
624                {
625                   ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
626                   evas_object_hide(ao);
627                }
628
629              return;
630           }
631      }
632    else
633      {
634         //1. handler open
635         if (x == sd->handler_w)
636           {
637              if (!handler_bring_in) //_anim_stop_cb function
638                {
639                   sd->scroll_dir = 0;
640                   return;
641                }
642              else if (sd->scroll_dir == 0) //_on_mouse_up function -> handler close
643                {
644                   sd->s_iface->region_bring_in(obj, 0, 0, w, h);
645                   return;
646                }
647           }
648         //2. drawer open
649         else if (x == sd->panel_w)
650           {
651              if (sd->hidden)
652                {
653                   elm_object_signal_emit(obj, "elm,state,active", "elm");
654                   sd->hidden = EINA_FALSE;
655                }
656              sd->scroll_dir = 0;
657
658              // drawer focus & access
659              elm_object_tree_focus_allow_set(obj, EINA_TRUE);
660              if (_elm_config->access_mode)
661                {
662                   ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
663                   evas_object_show(ao);
664                }
665              elm_object_focus_set(obj, EINA_TRUE);
666
667              return;
668           }
669         //3. drawer close
670         else if (x == 0)
671           {
672              sd->s_iface->hold_set(obj, EINA_TRUE);
673              sd->hold = EINA_TRUE;
674              elm_layout_signal_emit(sd->ly, "elm,state,content,hidden", "elm");
675              elm_object_signal_emit(obj, "elm,state,hold", "elm");
676              sd->scrolled = EINA_FALSE;
677
678              if (!sd->hidden)
679                {
680                   elm_object_signal_emit(obj, "elm,state,inactive", "elm");
681                   sd->hidden = EINA_TRUE;
682                }
683              sd->scroll_dir = 0;
684
685              // drawer focus & access
686              elm_object_tree_focus_allow_set(obj, EINA_FALSE);
687              if (_elm_config->access_mode)
688                {
689                   ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
690                   evas_object_hide(ao);
691                }
692
693              return;
694           }
695      }
696
697    if (sd->scroll_dir == 1)
698      sd->s_iface->region_bring_in(obj, 0, 0, w, h);
699    else if (sd->scroll_dir == 2)
700      sd->s_iface->region_bring_in(obj, sd->panel_w, 0, w, h);
701 }
702
703 static void
704 _on_mouse_up(void *data __UNUSED__,
705              Evas *e __UNUSED__,
706              Evas_Object *obj,
707              void *event_info __UNUSED__)
708 {
709    _hidden_state_change(obj, EINA_TRUE);
710 }
711
712 static void
713 _on_spacer_mouse_down(void *data,
714                       Evas *e __UNUSED__,
715                       Evas_Object *obj __UNUSED__,
716                       void *event_info)
717 {
718    ELM_PANEL_DATA_GET(data, sd);
719    Evas_Event_Mouse_Down *ev = event_info;
720
721    sd->down_x = ev->output.x;
722    sd->down_y = ev->output.y;
723 }
724
725 static void
726 _on_spacer_mouse_up(void *data,
727                     Evas *e __UNUSED__,
728                     Evas_Object *obj __UNUSED__,
729                     void *event_info)
730 {
731    ELM_PANEL_DATA_GET(data, sd);
732    Evas_Event_Mouse_Up *ev = event_info;
733    Evas_Coord up_x, up_y, minw = 0, minh = 0;
734
735    up_x = ev->output.x;
736    up_y = ev->output.y;
737
738    elm_coords_finger_size_adjust(1, &minw, 1, &minh);
739
740    if ((abs(up_x - sd->down_x) < minw) && (abs(up_y - sd->down_y) < minh))
741      elm_panel_hidden_set(data, EINA_TRUE);
742
743    sd->down_x = 0;
744    sd->down_y = 0;
745 }
746
747 static void
748 _scroll_left_cb(Evas_Object *obj, void *data __UNUSED__)
749 {
750    ELM_PANEL_DATA_GET(obj, sd);
751    int x;
752
753    sd->s_iface->content_pos_get(obj, &x, NULL);
754
755    if (!(sd->scroll_dir == 2 && ((sd->content_pos - x) < THRESHOLD)))
756      sd->scroll_dir = 1;
757
758    sd->content_pos = x;
759 }
760
761 static void
762 _scroll_right_cb(Evas_Object *obj, void *data __UNUSED__)
763 {
764    ELM_PANEL_DATA_GET(obj, sd);
765    int x;
766
767    sd->s_iface->content_pos_get(obj, &x, NULL);
768
769    if (!(sd->scroll_dir == 1 && ((x - sd->content_pos) < THRESHOLD)))
770      sd->scroll_dir = 2;
771
772    sd->content_pos = x;
773 }
774
775 static void
776 _scroll_cb(Evas_Object *obj, void *data __UNUSED__)
777 {
778    Evas_Coord x, y;
779    Elm_Panel_Scroll_Info event;
780
781    ELM_PANEL_DATA_GET(obj, sd);
782
783    // if drag really fast and mouse up, scroll happens after the mouse up.
784    // scroller is set to hold on mouse up, so have to unhold here
785    if (sd->hold)
786      {
787         sd->s_iface->hold_set(obj, EINA_FALSE);
788         sd->hold = EINA_FALSE;
789         elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
790         elm_object_signal_emit(obj, "elm,state,unhold", "elm");
791      }
792    // signal emit at the first scrolling
793    if (!sd->scrolled)
794      {
795         sd->scrolled = EINA_TRUE;
796         elm_layout_signal_emit(sd->ly, "elm,state,scroll,start", "elm");
797      }
798
799    sd->s_iface->content_pos_get(obj, &x, &y);
800
801    if (sd->orient == ELM_PANEL_ORIENT_TOP)
802      {
803         event.rel_x = 1;
804         event.rel_y = 1;
805 //        event.rel_y = 1 - ((double) y / (double) sd->panel_h);
806      }
807    else if (sd->orient == ELM_PANEL_ORIENT_LEFT)
808      {
809         event.rel_x = 1 - ((double) x / (double) sd->panel_w);
810         event.rel_y = 1;
811      }
812    else if (sd->orient == ELM_PANEL_ORIENT_RIGHT)
813      {
814         event.rel_x = (double) x / (double) sd->panel_w;
815         event.rel_y = 1;
816      }
817    else
818      {
819         event.rel_x = 1;
820         event.rel_y = 1;
821 //        event.rel_y = 1 - ((double) y / (double) sd->panel_h);
822      }
823    evas_object_smart_callback_call(obj, SIG_SCROLL, (void *) &event);
824 }
825
826 static void
827 _active_cb(void *data __UNUSED__,
828            Evas_Object *obj,
829            const char *emission __UNUSED__,
830            const char *source __UNUSED__)
831 {
832    ELM_PANEL_DATA_GET(obj, sd);
833
834    if (!sd->scrollable) return;
835    if (!sd->hold) return;
836
837    sd->s_iface->hold_set(obj, EINA_FALSE);
838    sd->hold = EINA_FALSE;
839    elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
840    elm_object_signal_emit(obj, "elm,state,unhold", "elm");
841 }
842
843 static void
844 _handler_open_cb(void *data __UNUSED__,
845            Evas_Object *obj,
846            const char *emission __UNUSED__,
847            const char *source __UNUSED__)
848 {
849    int w, h, x;
850    ELM_PANEL_DATA_GET(obj, sd);
851
852    if (!sd->scrollable) return;
853
854    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
855    evas_pointer_output_xy_get(evas_object_evas_get(obj), &x, NULL);
856
857    if (sd->orient == ELM_PANEL_ORIENT_TOP ||
858        sd->orient == ELM_PANEL_ORIENT_LEFT)
859      {
860         if ((x > 0) && (x < sd->handler_w))
861           sd->s_iface->region_bring_in
862              (obj, (sd->panel_w - sd->handler_w), 0, w, h);
863      }
864    else
865      {
866         if ((x > (sd->panel_w - sd->handler_w)) && (x < sd->panel_w))
867           sd->s_iface->region_bring_in
868              (obj, sd->handler_w, 0, w, h);
869      }
870 }
871
872 static void
873 _anim_start_cb(Evas_Object *obj, void *data __UNUSED__)
874 {
875    ELM_PANEL_DATA_GET(obj, sd);
876    sd->animating = EINA_TRUE;
877 }
878
879 static void
880 _anim_stop_cb(Evas_Object *obj, void *data __UNUSED__)
881 {
882    ELM_PANEL_DATA_GET(obj, sd);
883    sd->animating = EINA_FALSE;
884    _hidden_state_change(obj, EINA_FALSE);
885 }
886
887 static void
888 _elm_panel_smart_add(Evas_Object *obj)
889 {
890    EVAS_SMART_DATA_ALLOC(obj, Elm_Panel_Smart_Data);
891
892    ELM_WIDGET_CLASS(_elm_panel_parent_sc)->base.add(obj);
893 }
894
895 static void
896 _elm_panel_smart_del(Evas_Object *obj)
897 {
898    Evas_Object *child;
899    Eina_List *l;
900
901    ELM_PANEL_DATA_GET(obj, sd);
902
903    sd->on_deletion = EINA_TRUE;
904
905    /* let's make our box object the *last* to be processed, since it
906     * may (smart) parent other sub objects here */
907    EINA_LIST_FOREACH(ELM_WIDGET_DATA(sd)->subobjs, l, child)
908      {
909         if (child == sd->bx)
910           {
911              ELM_WIDGET_DATA(sd)->subobjs =
912                eina_list_demote_list(ELM_WIDGET_DATA(sd)->subobjs, l);
913              break;
914           }
915      }
916
917    ELM_WIDGET_CLASS(_elm_panel_parent_sc)->base.del(obj);
918 }
919
920 static void
921 _elm_panel_smart_access(Evas_Object *obj, Eina_Bool is_access)
922 {
923    ELM_PANEL_CHECK(obj);
924    ELM_PANEL_DATA_GET(obj, sd);
925
926    /* drawer access*/
927    if (sd->scrollable)
928      {
929         _access_obj_process(obj, is_access);
930         return;
931      }
932    /* drawer access*/
933
934    if (is_access)
935      _elm_access_edje_object_part_object_register
936        (obj, ELM_WIDGET_DATA(sd)->resize_obj, "btn_icon");
937    else
938      _elm_access_edje_object_part_object_unregister
939        (obj, ELM_WIDGET_DATA(sd)->resize_obj, "btn_icon");
940 }
941
942 static void
943 _elm_panel_smart_resize(Evas_Object *obj,
944                         Evas_Coord w,
945                         Evas_Coord h)
946 {
947    Evas_Coord handler_w = 0, handler_h = 0;
948
949    ELM_PANEL_DATA_GET(obj, sd);
950    ELM_WIDGET_DATA_GET(obj, wsd);
951
952    ELM_WIDGET_CLASS(_elm_panel_parent_sc)->base.resize(obj, w, h);
953
954    evas_object_resize(sd->hit_rect, w, h);
955    if ((sd->content) && (!sd->animating))
956      _hidden_content_region_set(obj, w, h, EINA_FALSE);
957    if (sd->spacer)
958      {
959         if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
960           {
961              evas_object_size_hint_min_set(sd->spacer, 1860, h);
962              evas_object_resize(sd->bx, 1860, 0);
963           }
964         else
965           {
966              evas_object_size_hint_min_set(sd->spacer, 1300, h);
967              evas_object_resize(sd->bx, 1300, 0);
968           }
969         edje_object_part_geometry_get(wsd->resize_obj, "handler", NULL, NULL, &handler_w, &handler_h);
970         sd->handler_w = (int) (elm_object_scale_get(obj) * (double) (int)(handler_w));
971         sd->handler_h = (int) (elm_object_scale_get(obj) * (double) (int)(handler_h));
972      }
973 }
974
975 static Eina_Bool
976 _elm_panel_smart_disable(Evas_Object *obj)
977 {
978    ELM_PANEL_DATA_GET(obj, sd);
979    if (sd->scrollable)
980      {
981         if (elm_widget_disabled_get(obj))
982           {
983              evas_object_pass_events_set(sd->hit_rect, EINA_TRUE);
984              elm_layout_signal_emit(obj, "elm,state,disabled", "elm");
985           }
986         else
987           {
988              evas_object_pass_events_set(sd->hit_rect, EINA_FALSE);
989              elm_layout_signal_emit(obj, "elm,state,enabled", "elm");
990           }
991      }
992    return EINA_TRUE;
993 }
994
995 static void
996 _elm_panel_smart_set_user(Elm_Panel_Smart_Class *sc)
997 {
998    ELM_WIDGET_CLASS(sc)->base.add = _elm_panel_smart_add;
999    ELM_WIDGET_CLASS(sc)->base.del = _elm_panel_smart_del;
1000
1001    ELM_WIDGET_CLASS(sc)->base.resize = _elm_panel_smart_resize;
1002
1003    ELM_WIDGET_CLASS(sc)->focus_next = _elm_panel_smart_focus_next;
1004    ELM_WIDGET_CLASS(sc)->theme = _elm_panel_smart_theme;
1005    ELM_WIDGET_CLASS(sc)->event = _elm_panel_smart_event;
1006    ELM_WIDGET_CLASS(sc)->access = _elm_panel_smart_access;
1007    ELM_WIDGET_CLASS(sc)->disable = _elm_panel_smart_disable;
1008
1009    ELM_CONTAINER_CLASS(sc)->content_set = _elm_panel_smart_content_set;
1010    ELM_CONTAINER_CLASS(sc)->content_get = _elm_panel_smart_content_get;
1011    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_panel_smart_content_unset;
1012
1013    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_panel_smart_sizing_eval;
1014 }
1015
1016 EAPI const Elm_Panel_Smart_Class *
1017 elm_panel_smart_class_get(void)
1018 {
1019    static Elm_Panel_Smart_Class _sc =
1020      ELM_PANEL_SMART_CLASS_INIT_NAME_VERSION(ELM_PANEL_SMART_NAME);
1021    static const Elm_Panel_Smart_Class *class = NULL;
1022
1023    if (class) return class;
1024
1025    _elm_panel_smart_set(&_sc);
1026    class = &_sc;
1027
1028    return class;
1029 }
1030
1031 EAPI Evas_Object *
1032 elm_panel_add(Evas_Object *parent)
1033 {
1034    Evas_Object *obj;
1035
1036    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1037
1038    obj = elm_widget_add(_elm_panel_smart_class_new(), parent);
1039    if (!obj) return NULL;
1040
1041    if (!elm_widget_sub_object_add(parent, obj))
1042      ERR("could not add %p as sub object of %p", obj, parent);
1043
1044    ELM_PANEL_DATA_GET(obj, sd);
1045
1046    elm_widget_can_focus_set(obj, EINA_TRUE);
1047
1048    _orient_set_do(obj);
1049
1050    /* box */
1051    sd->bx = evas_object_box_add(evas_object_evas_get(obj));
1052    evas_object_size_hint_align_set(sd->bx, 0.5, 0.5);
1053    evas_object_size_hint_weight_set(sd->bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1054    evas_object_box_layout_set(sd->bx, _box_layout_cb, sd, NULL);
1055    elm_layout_content_set(obj, "elm.swallow.content", sd->bx);
1056    evas_object_show(sd->bx);
1057
1058    elm_layout_signal_callback_add
1059      (obj, "elm,action,panel,toggle", "*", _panel_toggle, obj);
1060    elm_layout_signal_callback_add(obj, "elm,state,event,active", "elm", _active_cb,
1061                                   NULL);
1062    elm_layout_signal_callback_add(obj, "elm,state,handler,open", "elm", _handler_open_cb,
1063                                   NULL);
1064    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, _on_mouse_up,
1065                                   NULL);
1066
1067    elm_layout_sizing_eval(obj);
1068
1069    /* scrollable interface */
1070    sd->s_iface = evas_object_smart_interface_get
1071      (obj, ELM_SCROLLABLE_IFACE_NAME);
1072
1073    /* hit rect */
1074    sd->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
1075    evas_object_smart_member_add(sd->hit_rect, obj);
1076    elm_widget_sub_object_add(obj, sd->hit_rect);
1077    evas_object_color_set(sd->hit_rect, 0, 0, 0, 0);
1078    evas_object_pass_events_set(sd->hit_rect, EINA_TRUE);
1079    evas_object_show(sd->hit_rect);
1080
1081    sd->s_iface->objects_set
1082       (obj, ELM_WIDGET_DATA(sd)->resize_obj, sd->hit_rect);
1083
1084    sd->s_iface->single_direction_set(obj, ELM_SCROLLER_SINGLE_DIRECTION_HARD);
1085    sd->s_iface->scroll_left_cb_set(obj, _scroll_left_cb);
1086    sd->s_iface->scroll_right_cb_set(obj, _scroll_right_cb);
1087    sd->s_iface->scroll_cb_set(obj, _scroll_cb);
1088    sd->s_iface->animate_start_cb_set(obj, _anim_start_cb);
1089    sd->s_iface->animate_stop_cb_set(obj, _anim_stop_cb);
1090
1091    sd->s_iface->hold_set(obj, EINA_TRUE);
1092    sd->hold = EINA_TRUE;
1093
1094    //Tizen Only: This should be removed when eo is applied.
1095    ELM_WIDGET_DATA_GET(obj, wsd);
1096    wsd->on_create = EINA_FALSE;
1097    wsd->highlight_root = EINA_TRUE;
1098
1099    return obj;
1100 }
1101
1102 EAPI void
1103 elm_panel_orient_set(Evas_Object *obj,
1104                      Elm_Panel_Orient orient)
1105 {
1106    ELM_PANEL_CHECK(obj);
1107    ELM_PANEL_DATA_GET(obj, sd);
1108
1109    if (sd->orient == orient) return;
1110    sd->orient = orient;
1111
1112    _orient_set_do(obj);
1113
1114    elm_layout_sizing_eval(obj);
1115 }
1116
1117 EAPI Elm_Panel_Orient
1118 elm_panel_orient_get(const Evas_Object *obj)
1119 {
1120    ELM_PANEL_CHECK(obj) ELM_PANEL_ORIENT_LEFT;
1121    ELM_PANEL_DATA_GET(obj, sd);
1122
1123    return sd->orient;
1124 }
1125
1126 EAPI void
1127 elm_panel_hidden_set(Evas_Object *obj,
1128                      Eina_Bool hidden)
1129 {
1130    ELM_PANEL_CHECK(obj);
1131    ELM_PANEL_DATA_GET(obj, sd);
1132
1133    if (sd->hidden == hidden)
1134      {
1135         if (sd->hidden && !sd->hold)
1136           {
1137              int w, h;
1138              evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1139              _hidden_content_region_set(obj, w, h, EINA_TRUE);
1140           }
1141
1142         return;
1143      }
1144
1145
1146    _panel_toggle(NULL, obj, NULL, NULL);
1147 }
1148
1149 EAPI Eina_Bool
1150 elm_panel_hidden_get(const Evas_Object *obj)
1151 {
1152    ELM_PANEL_CHECK(obj) EINA_FALSE;
1153    ELM_PANEL_DATA_GET(obj, sd);
1154
1155    return sd->hidden;
1156 }
1157
1158 EAPI void
1159 elm_panel_toggle(Evas_Object *obj)
1160 {
1161    ELM_PANEL_CHECK(obj);
1162
1163    _panel_toggle(NULL, obj, NULL, NULL);
1164 }
1165
1166 EAPI void
1167 elm_panel_scrollable_set(Evas_Object *obj, Eina_Bool scrollable)
1168 {
1169    ELM_PANEL_CHECK(obj);
1170    ELM_PANEL_DATA_GET(obj, sd);
1171    ELM_WIDGET_DATA_GET(obj, wsd);
1172
1173    Evas_Coord h;
1174
1175    Evas_Object *content;
1176
1177    scrollable = !!scrollable;
1178
1179    if (sd->scrollable == scrollable) return;
1180    sd->scrollable = scrollable;
1181
1182    //TODO: scrollable set
1183    if (scrollable)
1184      {
1185         /* internal layout */
1186         sd->ly = elm_layout_add(obj);
1187         evas_object_smart_member_add(sd->ly, obj);
1188         elm_widget_sub_object_add(obj, sd->ly);
1189         _orient_set_do_internal(obj);
1190         evas_object_show(sd->ly);
1191
1192         content = sd->content;
1193         evas_object_box_remove_all(sd->bx, EINA_FALSE);
1194         evas_object_box_append(sd->bx, sd->ly);
1195         elm_layout_content_unset(obj, "elm.swallow.content");
1196         sd->content = NULL;
1197         if (content)
1198           elm_layout_content_set(obj, "elm.swallow.content", content);
1199
1200         sd->spacer = evas_object_rectangle_add(evas_object_evas_get(obj));
1201         evas_object_color_set(sd->spacer, 0, 0, 0, 0);
1202         evas_object_event_callback_add(sd->spacer, EVAS_CALLBACK_MOUSE_DOWN,
1203                                        _on_spacer_mouse_down, obj);
1204         evas_object_event_callback_add(sd->spacer, EVAS_CALLBACK_MOUSE_UP,
1205                                        _on_spacer_mouse_up, obj);
1206
1207         evas_object_geometry_get(obj, NULL, NULL, NULL, &h);
1208         if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1209           evas_object_size_hint_min_set(sd->spacer, 1860, h);
1210         else
1211           evas_object_size_hint_min_set(sd->spacer, 1300, h);
1212
1213         elm_layout_content_set(sd->ly, "elm.swallow.spacer", sd->spacer);
1214
1215         if (sd->hidden)
1216           elm_layout_signal_emit(sd->ly, "elm,state,content,hidden", "elm");
1217         else
1218           elm_layout_signal_emit(sd->ly, "elm,state,content,visible", "elm");
1219
1220         evas_object_pass_events_set(sd->hit_rect, EINA_FALSE);
1221      }
1222    else
1223      {
1224         elm_layout_content_unset(sd->ly, "elm.swallow.content");
1225         evas_object_box_append(sd->bx, sd->content);
1226         elm_layout_content_set(obj, "elm.swallow.content", sd->bx);
1227         evas_object_pass_events_set(sd->hit_rect, EINA_TRUE);
1228         evas_object_del(sd->spacer);
1229         evas_object_del(sd->ly);
1230         sd->spacer = NULL;
1231         sd->ly = NULL;
1232      }
1233 }
1234
1235 EAPI Eina_Bool
1236 elm_panel_scrollable_get(const Evas_Object *obj)
1237 {
1238    ELM_PANEL_CHECK(obj) EINA_FALSE;
1239    ELM_PANEL_DATA_GET(obj, sd);
1240    return sd->scrollable;
1241 }