tizen 2.3 release
[framework/uifw/elementary.git] / src / lib / elc_ctxpopup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_ctxpopup.h"
4
5 #define TTS_STR_MENU_POPUP dgettext(PACKAGE, "IDS_SCR_OPT_MENU_POP_UP_TTS")
6 #define TTS_STR_MENU_CLOSE dgettext(PACKAGE, "IDS_ST_BODY_DOUBLE_TAP_TO_CLOSE_THE_MENU_T_TTS")
7
8 EAPI const char ELM_CTXPOPUP_SMART_NAME[] = "elm_ctxpopup";
9
10 static const char ACCESS_OUTLINE_PART[] = "access.outline";
11
12 static const char SIG_DISMISSED[] = "dismissed";
13 static const char SIG_LANG_CHANGED[] = "language,changed";
14 static const char SIG_ACCESS_CHANGED[] = "access,changed";
15
16 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
17    {SIG_DISMISSED, ""},
18    {SIG_LANG_CHANGED, ""},
19    {SIG_ACCESS_CHANGED, ""},
20    {NULL, NULL}
21 };
22
23 static void _on_move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__);
24 static void _item_sizing_eval(Elm_Ctxpopup_Item *item);
25
26
27 EVAS_SMART_SUBCLASS_NEW
28   (ELM_CTXPOPUP_SMART_NAME, _elm_ctxpopup, Elm_Ctxpopup_Smart_Class,
29    Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
30
31 static Eina_Bool
32 _elm_ctxpopup_smart_translate(Evas_Object *obj)
33 {
34    ELM_CTXPOPUP_DATA_GET(obj, sd);
35    Elm_Ctxpopup_Item *it;
36    Eina_List *l;
37
38    if (sd->auto_hide)
39      evas_object_hide(obj);
40
41    EINA_LIST_FOREACH(sd->items, l, it)
42      elm_widget_item_translate(it);
43
44    return EINA_TRUE;
45 }
46
47 static Evas_Object *
48 _access_object_get(const Evas_Object *obj, const char* part)
49 {
50    Evas_Object *po, *ao;
51    ELM_CTXPOPUP_DATA_GET(obj, sd);
52
53    po = (Evas_Object *)edje_object_part_object_get(ELM_WIDGET_DATA(sd)->resize_obj, part);
54    ao = evas_object_data_get(po, "_part_access_obj");
55
56    return ao;
57 }
58
59 // FIXME: There are applications which do not use elm_win as top widget.
60 // This is workaround! Those could not use focus!
61 static Eina_Bool _focus_enabled(Evas_Object *obj)
62 {
63    if (!elm_widget_focus_get(obj)) return EINA_FALSE;
64
65    const Evas_Object *win = elm_widget_top_get(obj);
66    const char *type = evas_object_type_get(win);
67
68    if (type && !strcmp(type, "elm_win"))
69      {
70         return elm_win_focus_highlight_enabled_get(win);
71      }
72    return EINA_FALSE;
73 }
74
75 static Eina_Bool
76 _elm_ctxpopup_smart_focus_next(const Evas_Object *obj,
77                                Elm_Focus_Direction dir,
78                                Evas_Object **next)
79 {
80    Eina_List *items = NULL;
81    Evas_Object *ao;
82
83    ELM_CTXPOPUP_DATA_GET(obj, sd);
84
85    if (!sd)
86      return EINA_FALSE;
87
88    if (_elm_config->access_mode)
89      {
90         Eina_Bool ret;
91
92         ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
93         if (ao) items = eina_list_append(items, ao);
94
95         /* scroller exists when ctxpopup has an item */
96         if (sd->scr)
97            items = eina_list_append(items, sd->scr);
98         else
99            items = eina_list_append(items, sd->box);
100
101         _elm_access_auto_highlight_set(EINA_TRUE);
102         ret = elm_widget_focus_list_next_get
103                  (obj, items, eina_list_data_get, dir, next);
104         _elm_access_auto_highlight_set(EINA_FALSE);
105         return ret;
106      }
107    else
108      {
109         elm_widget_focus_next_get(sd->box, dir, next);
110         if (!*next) *next = (Evas_Object *)obj;
111         return EINA_TRUE;
112      }
113 }
114
115 static Eina_Bool
116 _elm_ctxpopup_smart_focus_direction_manager_is(const Evas_Object *obj __UNUSED__)
117 {
118    return EINA_TRUE;
119 }
120
121 static Eina_Bool
122 _elm_ctxpopup_smart_focus_direction(const Evas_Object *obj,
123                                     const Evas_Object *base,
124                                     double degree,
125                                     Evas_Object **direction,
126                                     double *weight)
127 {
128    Eina_Bool ret;
129    Eina_List *l = NULL;
130    void *(*list_data_get)(const Eina_List *list);
131
132    ELM_CTXPOPUP_DATA_GET(obj, sd);
133
134    if (!sd)
135      return EINA_FALSE;
136
137    list_data_get = eina_list_data_get;
138
139    l = eina_list_append(l, sd->box);
140    ret = elm_widget_focus_list_direction_get
141       (obj, base, l, list_data_get, degree, direction, weight);
142    eina_list_free(l);
143
144    return ret;
145 }
146
147 static void
148 _x_pos_adjust(Evas_Coord_Point *pos,
149               Evas_Coord_Point *base_size,
150               Evas_Coord_Rectangle *hover_area)
151 {
152    pos->x -= (base_size->x / 2);
153
154    if (pos->x < hover_area->x)
155      pos->x = hover_area->x;
156    else if ((pos->x + base_size->x) > (hover_area->x + hover_area->w))
157      pos->x = (hover_area->x + hover_area->w) - base_size->x;
158
159    if (base_size->x > hover_area->w)
160      base_size->x -= (base_size->x - hover_area->w);
161
162    if (pos->x < hover_area->x)
163      pos->x = hover_area->x;
164 }
165
166 static void
167 _y_pos_adjust(Evas_Coord_Point *pos,
168               Evas_Coord_Point *base_size,
169               Evas_Coord_Rectangle *hover_area)
170 {
171    pos->y -= (base_size->y / 2);
172
173    if (pos->y < hover_area->y)
174      pos->y = hover_area->y;
175    else if ((pos->y + base_size->y) > (hover_area->y + hover_area->h))
176      pos->y = hover_area->y + hover_area->h - base_size->y;
177
178    if (base_size->y > hover_area->h)
179      base_size->y -= (base_size->y - hover_area->h);
180
181    if (pos->y < hover_area->y)
182      pos->y = hover_area->y;
183 }
184
185 static void
186 _item_select_cb(void *data,
187                 Evas_Object *obj __UNUSED__,
188                 void *event_info __UNUSED__)
189 {
190    Elm_Ctxpopup_Item *item = data;
191
192    if (!item) return;
193    if (elm_widget_item_disabled_get(item))
194      {
195         if (_elm_config->access_mode)
196           elm_access_say(E_("Disabled"));
197         return;
198      }
199
200    if (item->func)
201      item->func((void*)item->base.data, WIDGET(item), data);
202 }
203
204 static char *
205 _access_info_cb(void *data, Evas_Object *obj __UNUSED__)
206 {
207    Elm_Ctxpopup_Item *it = (Elm_Ctxpopup_Item *)data;
208    const char *txt = NULL;
209    Evas_Object *icon = NULL;
210
211    if (!it) return NULL;
212
213    txt = it->label;
214    icon = it->icon;
215
216    if (txt) return strdup(txt);
217    if (icon) return strdup(E_("icon"));
218    return NULL;
219 }
220
221 static char *
222 _access_state_cb(void *data, Evas_Object *obj __UNUSED__)
223 {
224    Elm_Ctxpopup_Item *it = (Elm_Ctxpopup_Item *)data;
225    if (!it) return NULL;
226
227    if (it->base.disabled)
228      return strdup(E_("Disabled"));
229
230    return NULL;
231 }
232
233 static void
234 _access_focusable_button_register(Evas_Object *obj, Elm_Ctxpopup_Item *it)
235 {
236    Elm_Access_Info *ai;
237
238    ai = _elm_access_object_get(obj);
239
240    _elm_access_callback_set(ai, ELM_ACCESS_INFO, _access_info_cb, it);
241    _elm_access_callback_set(ai, ELM_ACCESS_STATE, _access_state_cb, it);
242    _elm_access_callback_set(ai, ELM_ACCESS_TYPE, NULL, NULL);
243
244    ((Elm_Widget_Item *)it)->access_obj = obj;
245 }
246
247 static void
248 _mouse_down_cb(Elm_Ctxpopup_Item *it,
249                Evas *evas __UNUSED__,
250                Evas_Object *obj __UNUSED__,
251                Evas_Event_Mouse_Down *ev)
252 {
253    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
254
255    if (ev->button != 1) return;
256
257    //If counter is not zero, it means all other multi down is not released.
258    if (sd->multi_down != 0) return;
259    sd->mouse_down = EINA_TRUE;
260 //******************** TIZEN Only
261    sd->pressed = EINA_TRUE;
262 //****************************
263 }
264
265 //******************** TIZEN Only
266 static void
267 _mouse_move_cb(Elm_Ctxpopup_Item *it,
268                Evas *evas __UNUSED__,
269                Evas_Object *obj,
270                void *event_info)
271 {
272    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
273    Evas_Event_Mouse_Move *ev = event_info;
274
275    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
276      {
277         if (sd->pressed)
278           {
279              edje_object_signal_emit(obj,"elm,action,unpressed", "elm");
280              sd->pressed = EINA_FALSE;
281           }
282      }
283    else
284      {
285         Evas_Coord x, y, w, h;
286         evas_object_geometry_get(obj, &x, &y, &w, &h);
287         if ((sd->pressed) && (ELM_RECTS_POINT_OUT(x, y, w, h, ev->cur.canvas.x, ev->cur.canvas.y)))
288           {
289              edje_object_signal_emit(obj,"elm,action,unpressed", "elm");
290              sd->pressed = EINA_FALSE;
291           }
292      }
293 }
294 //****************************
295
296 static void
297 _mouse_up_cb(Elm_Ctxpopup_Item *it,
298              Evas *evas __UNUSED__,
299              Evas_Object *obj __UNUSED__,
300              Evas_Event_Mouse_Up *ev)
301 {
302    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
303
304    if (ev->button != 1) return;
305
306    if (!sd->mouse_down) return;
307    sd->mouse_down = EINA_FALSE;
308 //******************** TIZEN Only
309    sd->pressed = EINA_FALSE;
310 //****************************
311 }
312
313 static void
314 _multi_down_cb(void *data,
315                     Evas *evas __UNUSED__,
316                     Evas_Object *obj __UNUSED__,
317                     void *event_info __UNUSED__)
318 {
319    Elm_Ctxpopup_Item *it = data;
320    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
321
322    //Emitting signal to inform edje about multi down event.
323    edje_object_signal_emit(VIEW(it), "elm,action,multi,down", "elm");
324    sd->multi_down++;
325 }
326
327 static void
328 _multi_up_cb(void *data,
329                     Evas *evas __UNUSED__,
330                     Evas_Object *obj __UNUSED__,
331                     void *event_info __UNUSED__)
332 {
333    Elm_Ctxpopup_Item *it = data;
334    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
335
336    sd->multi_down--;
337    if(sd->multi_down == 0)
338      {
339         //Emitting signal to inform edje about last multi up event.
340         edje_object_signal_emit(VIEW(it), "elm,action,multi,up", "elm");
341      }
342 }
343
344 static void
345 _item_new(Elm_Ctxpopup_Item *item,
346           char *group_name)
347 {
348    ELM_CTXPOPUP_DATA_GET(WIDGET(item), sd);
349    if (!sd) return;
350
351    VIEW(item) = edje_object_add(evas_object_evas_get(sd->box));
352    edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
353    _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", group_name,
354                          elm_widget_style_get(WIDGET(item)));
355    evas_object_size_hint_align_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
356    evas_object_show(VIEW(item));
357
358    evas_object_event_callback_add
359      (VIEW(item), EVAS_CALLBACK_MOUSE_DOWN, (Evas_Object_Event_Cb)_mouse_down_cb,
360      item);
361 //******************** TIZEN Only
362    evas_object_event_callback_add
363      (VIEW(item), EVAS_CALLBACK_MOUSE_MOVE, (Evas_Object_Event_Cb)_mouse_move_cb,
364      item);
365 //****************************
366    evas_object_event_callback_add
367      (VIEW(item), EVAS_CALLBACK_MOUSE_UP, (Evas_Object_Event_Cb)_mouse_up_cb, item);
368
369    /*Registering Multi down/up events to ignore mouse down/up events untill all
370      multi down/up events are released.*/
371    evas_object_event_callback_add
372      (VIEW(item), EVAS_CALLBACK_MULTI_DOWN, (Evas_Object_Event_Cb)_multi_down_cb,
373      item);
374    evas_object_event_callback_add
375      (VIEW(item), EVAS_CALLBACK_MULTI_UP, (Evas_Object_Event_Cb)_multi_up_cb,
376      item);
377 }
378
379 static void
380 _item_icon_set(Elm_Ctxpopup_Item *item,
381                Evas_Object *icon)
382 {
383    if (item->icon)
384      evas_object_del(item->icon);
385
386    item->icon = icon;
387    if (!icon) return;
388
389    edje_object_part_swallow(VIEW(item), "elm.swallow.icon", item->icon);
390 }
391
392 static void
393 _item_label_set(Elm_Ctxpopup_Item *item,
394                 const char *label)
395 {
396    if (!eina_stringshare_replace(&item->label, label))
397      return;
398
399    ELM_CTXPOPUP_DATA_GET(WIDGET(item), sd);
400
401    edje_object_part_text_set(VIEW(item), "elm.text", label);
402    if (sd->visible) _item_sizing_eval(item);
403 }
404
405 static Evas_Object *
406 _item_in_focusable_button(Elm_Ctxpopup_Item *item)
407 {
408    Evas_Object *bt;
409
410    bt = elm_button_add(WIDGET(item));
411    elm_object_style_set(bt, "focus");
412    evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
413    elm_object_part_content_set(bt, "elm.swallow.content", VIEW(item));
414    evas_object_smart_callback_add(bt, "clicked", _item_select_cb, item);
415    evas_object_show(bt);
416
417    return bt;
418 }
419
420 static Eina_Bool
421 _item_del_pre_hook(Elm_Object_Item *it)
422 {
423    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
424    Evas_Object *btn;
425
426    ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
427    if (!sd) return EINA_FALSE;
428
429    btn = ctxpopup_it->btn;
430    elm_box_unpack(sd->box, btn);
431    evas_object_smart_callback_del_full(btn, "clicked", _item_select_cb, ctxpopup_it);
432    evas_object_del(btn);
433
434    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
435
436    if (ctxpopup_it->icon)
437      evas_object_del(ctxpopup_it->icon);
438    if (VIEW(ctxpopup_it))
439      evas_object_del(VIEW(ctxpopup_it));
440
441    eina_stringshare_del(ctxpopup_it->label);
442    sd->items = eina_list_remove(sd->items, ctxpopup_it);
443
444    if (eina_list_count(sd->items) < 1)
445      {
446         evas_object_hide(WIDGET(ctxpopup_it));
447         return EINA_TRUE;
448      }
449    if (sd->visible) elm_layout_sizing_eval(WIDGET(ctxpopup_it));
450
451 #ifndef ELM_FEATURE_WEARABLE
452    if (ctxpopup_it == sd->top_drawn_item) sd->top_drawn_item = NULL;
453 #endif
454    return EINA_TRUE;
455 }
456
457 static void
458 _items_remove(Elm_Ctxpopup_Smart_Data *sd)
459 {
460    Eina_List *l, *l_next;
461    Elm_Ctxpopup_Item *item;
462
463    if (!sd->items) return;
464
465    EINA_LIST_FOREACH_SAFE(sd->items, l, l_next, item)
466      elm_widget_item_del(item);
467
468    sd->items = NULL;
469 }
470
471 static void
472 _item_sizing_eval(Elm_Ctxpopup_Item *item)
473 {
474    Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
475
476    if (!item) return;
477
478    edje_object_signal_emit(VIEW(item), "elm,state,text,default", "elm");
479    edje_object_message_signal_process(VIEW(item));
480    edje_object_size_min_restricted_calc(VIEW(item), &min_w, &min_h, min_w,
481                                         min_h);
482    evas_object_size_hint_min_set(VIEW(item), min_w, min_h);
483    evas_object_size_hint_max_set(VIEW(item), max_w, max_h);
484 }
485
486 static Elm_Ctxpopup_Direction
487 _base_geometry_calc(Evas_Object *obj,
488                     Evas_Coord_Rectangle *rect)
489 {
490    Elm_Ctxpopup_Direction dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
491    Evas_Coord_Rectangle hover_area;
492    Evas_Coord_Point pos = {0, 0};
493    Evas_Coord_Point arrow_size;
494    Evas_Coord_Point base_size;
495    Evas_Coord_Point max_size;
496    Evas_Coord_Point min_size;
497    Evas_Coord_Point temp;
498    int idx;
499    const char *str;
500
501    ELM_CTXPOPUP_DATA_GET(obj, sd);
502
503    if (!rect) return ELM_CTXPOPUP_DIRECTION_DOWN;
504
505    edje_object_part_geometry_get
506      (sd->arrow, "ctxpopup_arrow", NULL, NULL, &arrow_size.x, &arrow_size.y);
507    evas_object_resize(sd->arrow, arrow_size.x, arrow_size.y);
508
509    //Initialize Area Rectangle.
510    evas_object_geometry_get
511      (sd->parent, &hover_area.x, &hover_area.y, &hover_area.w,
512      &hover_area.h);
513
514    evas_object_geometry_get(obj, &pos.x, &pos.y, NULL, NULL);
515
516    //recalc the edje
517    edje_object_size_min_calc
518      (ELM_WIDGET_DATA(sd)->resize_obj, &base_size.x, &base_size.y);
519    evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
520
521    //Limit to Max Size
522    evas_object_size_hint_max_get(obj, &max_size.x, &max_size.y);
523    if ((max_size.x == -1) || (max_size.y == -1))
524      {
525         str = edje_object_data_get(sd->layout, "visible_maxw");
526         if (str)
527           max_size.x = atoi(str) * elm_widget_scale_get(obj) * elm_config_scale_get();
528         str = edje_object_data_get(sd->layout, "visible_maxh");
529         if (str)
530           max_size.y = atoi(str) * elm_widget_scale_get(obj) * elm_config_scale_get();
531      }
532
533    if ((max_size.y > 0) && (base_size.y > max_size.y))
534      base_size.y = max_size.y;
535
536    if ((max_size.x > 0) && (base_size.x > max_size.x))
537      base_size.x = max_size.x;
538
539    //Limit to Min Size
540    evas_object_size_hint_min_get(obj, &min_size.x, &min_size.y);
541    if ((min_size.x == 0) || (min_size.y == 0))
542      edje_object_size_min_get(sd->layout, &min_size.x, &min_size.y);
543
544    if ((min_size.y > 0) && (base_size.y < min_size.y))
545      base_size.y = min_size.y;
546
547    if ((min_size.x > 0) && (base_size.x < min_size.x))
548      base_size.x = min_size.x;
549
550    //Check the Which direction is available.
551    //If find a avaialble direction, it adjusts position and size.
552    for (idx = 0; idx < 4; idx++)
553      {
554         switch (sd->dir_priority[idx])
555           {
556            case ELM_CTXPOPUP_DIRECTION_UNKNOWN:
557
558            case ELM_CTXPOPUP_DIRECTION_UP:
559              temp.y = (pos.y - base_size.y);
560              if ((temp.y - arrow_size.y) < hover_area.y)
561                continue;
562
563              _x_pos_adjust(&pos, &base_size, &hover_area);
564              pos.y -= base_size.y;
565              dir = ELM_CTXPOPUP_DIRECTION_UP;
566              break;
567
568            case ELM_CTXPOPUP_DIRECTION_LEFT:
569              temp.x = (pos.x - base_size.x);
570              if ((temp.x - arrow_size.x) < hover_area.x)
571                continue;
572
573              _y_pos_adjust(&pos, &base_size, &hover_area);
574              pos.x -= base_size.x;
575              dir = ELM_CTXPOPUP_DIRECTION_LEFT;
576              break;
577
578            case ELM_CTXPOPUP_DIRECTION_RIGHT:
579              temp.x = (pos.x + base_size.x);
580              if ((temp.x + arrow_size.x) >
581                  (hover_area.x + hover_area.w))
582                continue;
583
584              _y_pos_adjust(&pos, &base_size, &hover_area);
585              dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
586              break;
587
588            case ELM_CTXPOPUP_DIRECTION_DOWN:
589              temp.y = (pos.y + base_size.y);
590              if ((temp.y + arrow_size.y) >
591                  (hover_area.y + hover_area.h))
592                continue;
593
594              _x_pos_adjust(&pos, &base_size, &hover_area);
595              dir = ELM_CTXPOPUP_DIRECTION_DOWN;
596              break;
597
598            default:
599              continue;
600           }
601         break;
602      }
603
604    //In this case, all directions are invalid because of lack of space.
605    if (idx == 4)
606      {
607         Evas_Coord length[2];
608
609         if (!sd->horizontal)
610           {
611              length[0] = pos.y - hover_area.y;
612              length[1] = (hover_area.y + hover_area.h) - pos.y;
613
614              // ELM_CTXPOPUP_DIRECTION_UP
615              if (length[0] > length[1])
616                {
617                   _x_pos_adjust(&pos, &base_size, &hover_area);
618                   pos.y -= base_size.y;
619                   dir = ELM_CTXPOPUP_DIRECTION_UP;
620                   if (pos.y < (hover_area.y + arrow_size.y))
621                     {
622                        base_size.y -= ((hover_area.y + arrow_size.y) - pos.y);
623                        pos.y = hover_area.y + arrow_size.y;
624                     }
625                }
626              //ELM_CTXPOPUP_DIRECTION_DOWN
627              else
628                {
629                   _x_pos_adjust(&pos, &base_size, &hover_area);
630                   dir = ELM_CTXPOPUP_DIRECTION_DOWN;
631                   if ((pos.y + arrow_size.y + base_size.y) >
632                       (hover_area.y + hover_area.h))
633                     base_size.y -=
634                       ((pos.y + arrow_size.y + base_size.y) -
635                        (hover_area.y + hover_area.h));
636                }
637           }
638         else
639           {
640              length[0] = pos.x - hover_area.x;
641              length[1] = (hover_area.x + hover_area.w) - pos.x;
642
643              //ELM_CTXPOPUP_DIRECTION_LEFT
644              if (length[0] > length[1])
645                {
646                   _y_pos_adjust(&pos, &base_size, &hover_area);
647                   pos.x -= base_size.x;
648                   dir = ELM_CTXPOPUP_DIRECTION_LEFT;
649                   if (pos.x < (hover_area.x + arrow_size.x))
650                     {
651                        base_size.x -= ((hover_area.x + arrow_size.x) - pos.x);
652                        pos.x = hover_area.x + arrow_size.x;
653                     }
654                }
655              //ELM_CTXPOPUP_DIRECTION_RIGHT
656              else
657                {
658                   _y_pos_adjust(&pos, &base_size, &hover_area);
659                   dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
660                   if (pos.x + (arrow_size.x + base_size.x) >
661                       hover_area.x + hover_area.w)
662                     base_size.x -=
663                       ((pos.x + arrow_size.x + base_size.x) -
664                        (hover_area.x + hover_area.w));
665                }
666           }
667      }
668
669    //Final position and size.
670    rect->x = pos.x;
671    rect->y = pos.y;
672    rect->w = base_size.x;
673    rect->h = base_size.y;
674
675    return dir;
676 }
677
678 static void
679 _arrow_update(Evas_Object *obj,
680               Elm_Ctxpopup_Direction dir,
681               Evas_Coord_Rectangle base_size)
682 {
683    Evas_Coord_Rectangle arrow_size;
684    Evas_Coord x, y;
685    double drag;
686    Evas_Coord_Rectangle shadow_left_top, shadow_right_bottom, arrow_padding;
687
688    ELM_CTXPOPUP_DATA_GET(obj, sd);
689
690    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
691    evas_object_geometry_get
692      (sd->arrow, NULL, NULL, &arrow_size.w, &arrow_size.h);
693
694    /* tizen only : since ctxpopup of tizen has shadow, start and end padding of arrow, it should be put together when updating arrow
695     * so there are some differences between open source and tizen */
696    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_left_top_padding", NULL, NULL, &shadow_left_top.w, &shadow_left_top.h);
697    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_right_bottom_padding", NULL, NULL, &shadow_right_bottom.w, &shadow_right_bottom.h);
698    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "ctxpopup_frame_left_top", NULL, NULL, &arrow_padding.w, &arrow_padding.h);
699
700    /* arrow is not being kept as sub-object on purpose, here. the
701     * design of the widget does not help with the contrary */
702
703    switch (dir)
704      {
705       case ELM_CTXPOPUP_DIRECTION_RIGHT:
706         edje_object_signal_emit(sd->arrow, "elm,state,left", "elm");
707         edje_object_part_swallow
708            (ELM_WIDGET_DATA(sd)->resize_obj,
709             (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
710              "elm.swallow.arrow_left"), sd->arrow);
711
712         if (base_size.h > 0)
713           {
714              if (y <= ((arrow_size.h * 0.5) + base_size.y + shadow_left_top.h + arrow_padding.h))
715                y = 0;
716              else if (y >= (base_size.y + base_size.h - ((arrow_size.h * 0.5) + shadow_right_bottom.h + arrow_padding.h)))
717                y = base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2));
718              else
719                y = y - base_size.y - ((arrow_size.h * 0.5) + shadow_left_top.h + arrow_padding.h);
720              drag = (double)(y) / (double)(base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2)));
721              edje_object_part_drag_value_set
722                 (ELM_WIDGET_DATA(sd)->resize_obj,
723                  (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
724                   "elm.swallow.arrow_left"), 1, drag);
725           }
726         break;
727
728       case ELM_CTXPOPUP_DIRECTION_LEFT:
729         edje_object_signal_emit(sd->arrow, "elm,state,right", "elm");
730         edje_object_part_swallow
731            (ELM_WIDGET_DATA(sd)->resize_obj,
732             (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
733              "elm.swallow.arrow_right"), sd->arrow);
734
735         if (base_size.h > 0)
736           {
737              if (y <= ((arrow_size.h * 0.5) + base_size.y + shadow_left_top.h + arrow_padding.h))
738                y = 0;
739              else if (y >= (base_size.y + base_size.h - ((arrow_size.h * 0.5) + shadow_right_bottom.h + arrow_padding.h)))
740                y = base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2));
741              else
742                y = y - base_size.y - ((arrow_size.h * 0.5) + shadow_left_top.h + arrow_padding.h);
743              drag = (double)(y) / (double)(base_size.h - (arrow_size.h + shadow_right_bottom.h + shadow_left_top.h + (arrow_padding.h * 2)));
744              edje_object_part_drag_value_set
745                 (ELM_WIDGET_DATA(sd)->resize_obj,
746                  (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
747                   "elm.swallow.arrow_right"), 0, drag);
748           }
749         break;
750
751       case ELM_CTXPOPUP_DIRECTION_DOWN:
752         edje_object_signal_emit(sd->arrow, "elm,state,top", "elm");
753         edje_object_part_swallow
754           (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_up",
755           sd->arrow);
756
757         if (base_size.w > 0)
758           {
759              if (x <= ((arrow_size.w * 0.5) + base_size.x + shadow_left_top.w + arrow_padding.w))
760                x = 0;
761              else if (x >= (base_size.x + base_size.w - ((arrow_size.w * 0.5) + shadow_right_bottom.w + arrow_padding.w)))
762                x = base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2));
763              else
764                x = x - base_size.x - ((arrow_size.w * 0.5) + shadow_left_top.w + arrow_padding.w);
765              drag = (double)(x) / (double)(base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2)));
766              edje_object_part_drag_value_set
767                (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_up",
768                drag, 1);
769           }
770         break;
771
772       case ELM_CTXPOPUP_DIRECTION_UP:
773         edje_object_signal_emit(sd->arrow, "elm,state,bottom", "elm");
774         edje_object_part_swallow
775           (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_down",
776           sd->arrow);
777
778         if (base_size.w > 0)
779           {
780              if (x <= ((arrow_size.w * 0.5) + base_size.x + shadow_left_top.w + arrow_padding.w))
781                x = 0;
782              else if (x >= (base_size.x + base_size.w - ((arrow_size.w * 0.5) + shadow_right_bottom.w + arrow_padding.w)))
783                x = base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2));
784              else
785                x = x - base_size.x - ((arrow_size.w * 0.5) + shadow_left_top.w + arrow_padding.w);
786              drag = (double)(x) / (double)(base_size.w - (arrow_size.w + shadow_right_bottom.w + shadow_left_top.w + (arrow_padding.w * 2)));
787              edje_object_part_drag_value_set
788                (ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.arrow_down",
789                drag, 0);
790           }
791         break;
792
793       default:
794         break;
795      }
796
797    //should be here for getting accurate geometry value
798    evas_object_smart_calculate(ELM_WIDGET_DATA(sd)->resize_obj);
799 }
800
801 static void
802 _show_signals_emit(Evas_Object *obj,
803                    Elm_Ctxpopup_Direction dir)
804 {
805    ELM_CTXPOPUP_DATA_GET(obj, sd);
806
807    if (!sd->visible) return;
808
809    switch (dir)
810      {
811       case ELM_CTXPOPUP_DIRECTION_UP:
812         edje_object_signal_emit(sd->layout, "elm,state,show,up", "elm");
813         break;
814
815       case ELM_CTXPOPUP_DIRECTION_LEFT:
816         edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,show,right" :
817                "elm,state,show,left"), "elm");
818         break;
819
820       case ELM_CTXPOPUP_DIRECTION_RIGHT:
821         edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,show,left" :
822                "elm,state,show,right"), "elm");
823         break;
824
825       case ELM_CTXPOPUP_DIRECTION_DOWN:
826         edje_object_signal_emit(sd->layout, "elm,state,show,down", "elm");
827         break;
828
829       default:
830         break;
831      }
832
833    edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
834 }
835
836 static void
837 _hide_signals_emit(Evas_Object *obj,
838                    Elm_Ctxpopup_Direction dir)
839 {
840    ELM_CTXPOPUP_DATA_GET(obj, sd);
841
842    if (!sd->visible) return;
843
844    switch (dir)
845      {
846       case ELM_CTXPOPUP_DIRECTION_UP:
847         edje_object_signal_emit(sd->layout, "elm,state,hide,up", "elm");
848         break;
849
850       case ELM_CTXPOPUP_DIRECTION_LEFT:
851         edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,hide,right" :
852                "elm,state,hide,left"), "elm");
853         break;
854
855       case ELM_CTXPOPUP_DIRECTION_RIGHT:
856         edje_object_signal_emit(sd->layout, (elm_widget_mirrored_get(obj) ? "elm,state,hide,left" :
857                "elm,state,hide,right"), "elm");
858         break;
859
860       case ELM_CTXPOPUP_DIRECTION_DOWN:
861         edje_object_signal_emit(sd->layout, "elm,state,hide,down", "elm");
862         break;
863
864       default:
865         break;
866      }
867
868    edje_object_signal_emit(sd->bg, "elm,state,hide", "elm");
869 }
870
871 static void
872 _base_shift_by_arrow(Evas_Object *obj,
873                      Evas_Object *arrow,
874                      Elm_Ctxpopup_Direction dir,
875                      Evas_Coord_Rectangle *rect)
876 {
877    ELM_CTXPOPUP_DATA_GET(obj, sd);
878
879    Evas_Coord arrow_w, arrow_h, diff_w, diff_h;
880    Evas_Coord_Rectangle shadow_left_top, shadow_right_bottom;
881
882    evas_object_geometry_get(arrow, NULL, NULL, &arrow_w, &arrow_h);
883    /* tizen only: since ctxpopup of tizen has shadow parts, start and end padding of arrow, it should be put together when shifting ctxpopup by arrow
884     * so there are some differences between opensource and tizen*/
885    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_left_top_padding", NULL, NULL, &shadow_left_top.w, &shadow_left_top.h);
886    edje_object_part_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, "frame_shadow_right_bottom_padding", NULL, NULL, &shadow_right_bottom.w, &shadow_right_bottom.h);
887    //
888
889    switch (dir)
890      {
891       case ELM_CTXPOPUP_DIRECTION_RIGHT:
892         diff_w = arrow_w - shadow_right_bottom.w;
893         rect->x += diff_w;
894         break;
895
896       case ELM_CTXPOPUP_DIRECTION_LEFT:
897         diff_w = arrow_w - shadow_left_top.w;
898         rect->x -= diff_w;
899         break;
900
901       case ELM_CTXPOPUP_DIRECTION_DOWN:
902         diff_h = arrow_h - shadow_left_top.h;
903         rect->y += diff_h;
904         break;
905
906       case ELM_CTXPOPUP_DIRECTION_UP:
907         diff_h = arrow_h - shadow_right_bottom.h;
908         rect->y -= diff_h;
909         break;
910
911       default:
912          break;
913      }
914 }
915
916 static Eina_Bool
917 _elm_ctxpopup_smart_sub_object_add(Evas_Object *obj,
918                                    Evas_Object *sobj)
919 {
920    Elm_Widget_Smart_Class *parent_parent;
921
922    parent_parent = (Elm_Widget_Smart_Class *)((Evas_Smart_Class *)
923                                               _elm_ctxpopup_parent_sc)->parent;
924
925    /* skipping layout's code, which registers size hint changing
926     * callback on sub objects. a hack to make ctxpopup live, as it is,
927     * on the new classing schema. this widget needs a total
928     * rewrite. */
929    if (!parent_parent->sub_object_add(obj, sobj))
930      return EINA_FALSE;
931
932    return EINA_TRUE;
933 }
934
935 static void
936 _elm_ctxpopup_smart_sizing_eval(Evas_Object *obj)
937 {
938    Eina_List *elist;
939    Elm_Ctxpopup_Item *item;
940    Evas_Coord_Rectangle rect = { 0, 0, 1, 1 };
941    Evas_Coord_Point box_size = { 0, 0 };
942    Evas_Coord_Point _box_size = { 0, 0 };
943    Evas_Coord maxw = 0;
944    Evas_Coord x, y, w, h;
945    const char *str;
946
947    ELM_CTXPOPUP_DATA_GET(obj, sd);
948
949    if (!sd->parent || !(sd->items || sd->content)) return;
950
951    //Box, Scroller
952    EINA_LIST_FOREACH(sd->items, elist, item)
953      {
954         _item_sizing_eval(item);
955         evas_object_size_hint_min_get(VIEW(item), &_box_size.x, &_box_size.y);
956 #ifndef ELM_FEATURE_WEARABLE
957    //Kiran only
958    if (!sd->color_calculated)
959      {
960         int item_r, item_g, item_b, item_a = 0;
961         int bg_r, bg_g, bg_b, bg_a = 0;
962         int item_banded_a ,bg_banded_a = 0;
963         const char *item_bg_color = NULL;
964         const char *list_bg_color = NULL;
965         int i = 0;
966         item_bg_color = edje_object_data_get(VIEW(item), "bg_color");
967         list_bg_color = edje_object_data_get(sd->bg, "personalized_color");
968         if (item_bg_color != NULL && list_bg_color != NULL )
969           {
970              edje_color_class_get (item_bg_color, &item_r, &item_g, &item_b, &item_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
971              edje_color_class_get (list_bg_color, &bg_r, &bg_g, &bg_b, &bg_a, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
972              for (i = 0; i < MAX_ITEMS_PER_VIEWPORT; i++)
973                 {
974                    item_banded_a = 255 - i*10;
975                    bg_banded_a = 255 - item_banded_a;
976                    sd->item_color[i][0] = ((item_r * item_banded_a) >> 8) + ((bg_r * bg_banded_a) >> 8);
977                    sd->item_color[i][1] = ((item_g * item_banded_a) >> 8) + ((bg_g * bg_banded_a) >> 8);
978                    sd->item_color[i][2] = ((item_b * item_banded_a) >> 8) + ((bg_b * bg_banded_a) >> 8);
979                 }
980              sd->color_calculated = EINA_TRUE;
981           }
982      }
983 #endif
984         str = edje_object_data_get(VIEW(item), "item_max_size");
985         if (str)
986           {
987              maxw = atoi(str);
988              maxw = maxw * elm_widget_scale_get(obj) * elm_config_scale_get();
989
990              if (_box_size.x > maxw)
991                {
992                   edje_object_signal_emit(VIEW(item), "elm,state,text,ellipsis", "elm");
993                   edje_object_message_signal_process(VIEW(item));
994                }
995           }
996
997         if (!sd->horizontal)
998           {
999              if (_box_size.x > box_size.x)
1000                box_size.x = _box_size.x;
1001              if (_box_size.y != -1)
1002                box_size.y += _box_size.y;
1003           }
1004         else
1005           {
1006              if (_box_size.x != -1)
1007                box_size.x += _box_size.x;
1008              if (_box_size.y > box_size.y)
1009                box_size.y = _box_size.y;
1010           }
1011      }
1012
1013 //   if (!sd->arrow) return;  /* simple way to flag "under deletion" */
1014
1015    if ((!sd->content) && (sd->scr))
1016      {
1017         evas_object_size_hint_min_set(sd->box, box_size.x, box_size.y);
1018         elm_scroller_content_min_limit(sd->scr, EINA_TRUE, EINA_TRUE);
1019         evas_object_size_hint_min_set(sd->scr, box_size.x, box_size.y);
1020      }
1021
1022    //Base
1023    sd->dir = _base_geometry_calc(obj, &rect);
1024
1025    _arrow_update(obj, sd->dir, rect);
1026    _base_shift_by_arrow(obj, sd->arrow, sd->dir, &rect);
1027
1028    //resize scroller according to final size
1029    if ((!sd->content) && (sd->scr))
1030      {
1031         elm_scroller_content_min_limit(sd->scr, EINA_FALSE, EINA_FALSE);
1032         evas_object_smart_calculate(sd->scr);
1033      }
1034
1035    evas_object_size_hint_min_set(ELM_WIDGET_DATA(sd)->resize_obj, rect.w, rect.h);
1036    evas_object_resize(ELM_WIDGET_DATA(sd)->resize_obj, rect.w, rect.h);
1037
1038    evas_object_resize(sd->layout, rect.w, rect.h);
1039    evas_object_move(sd->layout, rect.x, rect.y);
1040
1041    evas_object_geometry_get(sd->parent, &x, &y, &w, &h);
1042    evas_object_move(sd->bg, x, y);
1043    evas_object_resize(sd->bg, w, h);
1044 }
1045
1046 static void
1047 _on_parent_del(void *data,
1048                Evas *e __UNUSED__,
1049                Evas_Object *obj __UNUSED__,
1050                void *event_info __UNUSED__)
1051 {
1052    evas_object_del(data);
1053 }
1054
1055 static void
1056 _on_parent_move(void *data,
1057                 Evas *e __UNUSED__,
1058                 Evas_Object *obj __UNUSED__,
1059                 void *event_info __UNUSED__)
1060 {
1061    ELM_CTXPOPUP_DATA_GET(data, sd);
1062
1063
1064    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1065
1066    if (sd->visible)
1067      elm_layout_sizing_eval(data);
1068 }
1069
1070 static void
1071 _on_parent_resize(void *data,
1072                   Evas *e __UNUSED__,
1073                   Evas_Object *obj __UNUSED__,
1074                   void *event_info __UNUSED__)
1075 {
1076    ELM_CTXPOPUP_DATA_GET(data, sd);
1077    ELM_WIDGET_DATA_GET(data, wsd);
1078
1079    if (sd->auto_hide)
1080      {
1081         _hide_signals_emit(data, sd->dir);
1082
1083         sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1084
1085         evas_object_hide(data);
1086         evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
1087      }
1088    else
1089      {
1090         if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1091          elm_widget_theme_object_set
1092            (data, sd->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(data));
1093         else
1094          elm_widget_theme_object_set
1095            (data, sd->layout, "ctxpopup", "layout", elm_widget_style_get(data));
1096
1097         if (sd->visible)
1098           elm_layout_sizing_eval(data);
1099
1100         _show_signals_emit(data, sd->dir);
1101      }
1102 }
1103
1104 static void
1105 _parent_detach(Evas_Object *obj)
1106 {
1107    ELM_CTXPOPUP_DATA_GET(obj, sd);
1108
1109    if (!sd->parent) return;
1110
1111    evas_object_event_callback_del_full
1112      (sd->parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
1113    evas_object_event_callback_del_full
1114      (sd->parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
1115    evas_object_event_callback_del_full
1116      (sd->parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
1117 }
1118
1119 static void
1120 _on_content_resized(void *data,
1121                     Evas *e __UNUSED__,
1122                     Evas_Object *obj __UNUSED__,
1123                     void *event_info __UNUSED__)
1124 {
1125    elm_layout_sizing_eval(data);
1126 }
1127
1128 static void
1129 _access_outline_activate_cb(void *data,
1130                         Evas_Object *part_obj __UNUSED__,
1131                         Elm_Object_Item *item __UNUSED__)
1132 {
1133    evas_object_hide(data);
1134    evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
1135 }
1136
1137 static void
1138 _access_obj_process(Evas_Object *obj, Eina_Bool is_access)
1139 {
1140    Evas_Object *ao;
1141    ELM_CTXPOPUP_DATA_GET(obj, sd);
1142
1143    if (is_access)
1144      {
1145         ao = _access_object_get(obj, ACCESS_OUTLINE_PART);
1146         if (!ao)
1147           {
1148              ao = _elm_access_edje_object_part_object_register
1149                 (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_OUTLINE_PART);
1150
1151              const char *style = elm_widget_style_get(obj);
1152              if (!strcmp(style, "more/default"))
1153                {
1154                   elm_access_info_set(ao, ELM_ACCESS_TYPE, TTS_STR_MENU_POPUP);
1155                   elm_access_info_set(ao, ELM_ACCESS_CONTEXT_INFO, TTS_STR_MENU_CLOSE);
1156                }
1157              else
1158                {
1159                   elm_access_info_set(ao, ELM_ACCESS_TYPE, E_("Contextual popup"));
1160                   elm_access_info_set(ao, ELM_ACCESS_CONTEXT_INFO, E_("Double tap to close popup"));
1161                }
1162              _elm_access_activate_callback_set
1163                 (_elm_access_object_get(ao), _access_outline_activate_cb, obj);
1164           }
1165      }
1166    else
1167      {
1168         _elm_access_edje_object_part_object_unregister
1169                (obj, ELM_WIDGET_DATA(sd)->resize_obj, ACCESS_OUTLINE_PART);
1170      }
1171 }
1172
1173 static void
1174 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
1175 {
1176    ELM_CTXPOPUP_DATA_GET(obj, sd);
1177
1178    edje_object_mirrored_set(sd->layout, rtl);
1179    edje_object_mirrored_set(sd->arrow, rtl);
1180    edje_object_mirrored_set(ELM_WIDGET_DATA(sd)->resize_obj, rtl);
1181 }
1182
1183 static Eina_Bool
1184 _elm_ctxpopup_smart_event(Evas_Object *obj,
1185                           Evas_Object *src __UNUSED__,
1186                           Evas_Callback_Type type,
1187                           void *event_info)
1188 {
1189    Evas_Event_Key_Down *ev = event_info;
1190
1191    ELM_CTXPOPUP_DATA_GET(obj, sd);
1192
1193    // TIZEN ONLY(20131221) : When access mode, focused ui is disabled.
1194    if (_elm_config->access_mode) return EINA_FALSE;
1195
1196    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
1197    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
1198    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
1199    if (!_focus_enabled(obj)) return EINA_FALSE;
1200
1201    //FIXME: for this key event, _elm_ctxpopup_smart_focus_next should be done first
1202    if ((!strcmp(ev->keyname, "Tab")) ||
1203        (!strcmp(ev->keyname, "ISO_Left_Tab")))
1204      {
1205         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1206         return EINA_TRUE;
1207      }
1208    /////
1209    if (((!strcmp(ev->keyname, "Left")) ||
1210         (!strcmp(ev->keyname, "KP_Left")) ||
1211         (!strcmp(ev->keyname, "Right")) ||
1212         (!strcmp(ev->keyname, "KP_Right")) ||
1213         (!strcmp(ev->keyname, "Up")) ||
1214         (!strcmp(ev->keyname, "KP_Up")) ||
1215         (!strcmp(ev->keyname, "Down")) ||
1216         (!strcmp(ev->keyname, "KP_Down"))) && (!ev->string))
1217      {
1218         double degree = 0.0;
1219
1220         if ((!strcmp(ev->keyname, "Left")) ||
1221             (!strcmp(ev->keyname, "KP_Left")))
1222           degree = 270.0;
1223         else if ((!strcmp(ev->keyname, "Right")) ||
1224                  (!strcmp(ev->keyname, "KP_Right")))
1225           degree = 90.0;
1226         else if ((!strcmp(ev->keyname, "Up")) ||
1227                  (!strcmp(ev->keyname, "KP_Up")))
1228           degree = 0.0;
1229         else if ((!strcmp(ev->keyname, "Down")) ||
1230                  (!strcmp(ev->keyname, "KP_Down")))
1231           degree = 180.0;
1232
1233         elm_widget_focus_direction_go(sd->box, degree);
1234         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1235         return EINA_TRUE;
1236      }
1237    else if (((!strcmp(ev->keyname, "Home")) ||
1238              (!strcmp(ev->keyname, "KP_Home")) ||
1239              (!strcmp(ev->keyname, "Prior")) ||
1240              (!strcmp(ev->keyname, "KP_Prior"))) && (!ev->string))
1241      {
1242         Elm_Ctxpopup_Item *it = eina_list_data_get(sd->items);
1243         Evas_Object *btn = it->btn;
1244         elm_object_focus_set(btn, EINA_TRUE);
1245         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1246         return EINA_TRUE;
1247      }
1248    else if (((!strcmp(ev->keyname, "End")) ||
1249              (!strcmp(ev->keyname, "KP_End")) ||
1250              (!strcmp(ev->keyname, "Next")) ||
1251              (!strcmp(ev->keyname, "KP_Next"))) && (!ev->string))
1252      {
1253         Elm_Ctxpopup_Item *it = eina_list_data_get(eina_list_last(sd->items));
1254         Evas_Object *btn = it->btn;
1255         elm_object_focus_set(btn, EINA_TRUE);
1256         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1257         return EINA_TRUE;
1258      }
1259
1260    // TIZEN ONLY : 20130530 : ctxpopup will be dismissed by user
1261    //if (strcmp(ev->keyname, "Escape")) return EINA_FALSE;
1262    return EINA_FALSE;
1263
1264 /*
1265    _hide_signals_emit(obj, sd->dir);
1266
1267    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
1268    return EINA_TRUE;
1269 */
1270 }
1271
1272 //FIXME: lost the content size when theme hook is called.
1273 static Eina_Bool
1274 _elm_ctxpopup_smart_theme(Evas_Object *obj)
1275 {
1276    Eina_List *elist;
1277    Elm_Ctxpopup_Item *item;
1278    int idx = 0;
1279    Eina_Bool rtl;
1280
1281    ELM_CTXPOPUP_DATA_GET(obj, sd);
1282    ELM_WIDGET_DATA_GET(obj, wsd);
1283
1284    if (!ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->theme(obj))
1285      return EINA_FALSE;
1286
1287    rtl = elm_widget_mirrored_get(obj);
1288
1289    elm_widget_theme_object_set
1290      (obj, sd->bg, "ctxpopup", "bg", elm_widget_style_get(obj));
1291
1292    elm_widget_theme_object_set
1293      (obj, sd->arrow, "ctxpopup", "arrow", elm_widget_style_get(obj));
1294
1295    if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1296      elm_widget_theme_object_set
1297        (obj, sd->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(obj));
1298    else
1299      elm_widget_theme_object_set
1300        (obj, sd->layout, "ctxpopup", "layout", elm_widget_style_get(obj));
1301
1302    _mirrored_set(obj, rtl);
1303
1304    //Items
1305    EINA_LIST_FOREACH(sd->items, elist, item)
1306      {
1307         edje_object_mirrored_set(VIEW(item), rtl);
1308
1309         if (item->label && item->icon)
1310           _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1311                                 "icon_text_style_item",
1312                                 elm_widget_style_get(obj));
1313         else if (item->label)
1314           {
1315              if(!sd->horizontal)
1316                _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1317                                      "text_style_item",
1318                                      elm_widget_style_get(obj));
1319              else
1320                _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1321                                      "text_style_item_horizontal",
1322                                      elm_widget_style_get(obj));
1323           }
1324         else if (item->icon)
1325           _elm_theme_object_set
1326              (obj, VIEW(item), "ctxpopup", "icon_style_item",
1327               elm_widget_style_get(obj));
1328         if (item->label)
1329           edje_object_part_text_set(VIEW(item), "elm.text", item->label);
1330
1331         if (elm_widget_item_disabled_get(item))
1332           edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
1333
1334        /*
1335         *  For separator, if the first item has visible separator,
1336         *  then it should be aligned with edge of the base part.
1337         *  In some cases, it gives improper display. Ex) rounded corner
1338         *  So the first item separator should be invisible.
1339         */
1340         if ((idx++) == 0)
1341           edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
1342         else
1343           edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
1344
1345         // reset state of text to be default
1346         edje_object_signal_emit(VIEW(item), "elm,state,text,default", "elm");
1347         edje_object_message_signal_process(VIEW(item));
1348      }
1349
1350    if (evas_object_visible_get(sd->bg))
1351      edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
1352
1353    if (sd->scr)
1354      {
1355         elm_object_style_set(sd->scr, "list_effect");
1356
1357         if (sd->horizontal)
1358           elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
1359         else
1360           elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
1361      }
1362
1363    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1364
1365    if (sd->visible)
1366      _elm_ctxpopup_smart_sizing_eval(obj);
1367
1368    /* access */
1369   if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
1370
1371    return EINA_TRUE;
1372 }
1373
1374 /* kind of a big and tricky override here: an internal box will hold
1375  * the actual content. content aliases won't be of much help here */
1376 static Eina_Bool
1377 _elm_ctxpopup_smart_content_set(Evas_Object *obj,
1378                                 const char *part,
1379                                 Evas_Object *content)
1380 {
1381    Evas_Coord min_w = -1, min_h = -1;
1382
1383    ELM_CTXPOPUP_DATA_GET(obj, sd);
1384
1385    if ((part) && (strcmp(part, "default")))
1386      return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_set
1387               (obj, part, content);
1388
1389    if (!content) return EINA_FALSE;
1390
1391    if (content == sd->content) return EINA_TRUE;
1392
1393    if (sd->items) elm_ctxpopup_clear(obj);
1394    if (sd->content) evas_object_del(sd->content);
1395
1396    evas_object_event_callback_add
1397       (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1398    edje_object_part_swallow(ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content", sd->box);
1399
1400    evas_object_size_hint_weight_set
1401      (content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1402    evas_object_size_hint_fill_set
1403      (content, EVAS_HINT_FILL, EVAS_HINT_FILL);
1404
1405    /* since it's going to be a box content, not a layout's... */
1406    evas_object_show(content);
1407
1408    evas_object_size_hint_min_get(content, &min_w, &min_h);
1409    evas_object_size_hint_min_set(sd->box, min_w, min_h);
1410    elm_box_pack_end(sd->box, content);
1411
1412    sd->content = content;
1413    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1414
1415    if (sd->visible) elm_layout_sizing_eval(obj);
1416
1417    return EINA_TRUE;
1418 }
1419
1420 static Evas_Object *
1421 _elm_ctxpopup_smart_content_get(const Evas_Object *obj,
1422                                 const char *part)
1423 {
1424    ELM_CTXPOPUP_DATA_GET(obj, sd);
1425
1426    if ((part) && (strcmp(part, "default")))
1427      return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_get
1428               (obj, part);
1429
1430    return sd->content;
1431 }
1432
1433 static Evas_Object *
1434 _elm_ctxpopup_smart_content_unset(Evas_Object *obj,
1435                                   const char *part)
1436 {
1437    Evas_Object *content;
1438
1439    ELM_CTXPOPUP_DATA_GET(obj, sd);
1440
1441    if ((part) && (strcmp(part, "default")))
1442      return ELM_CONTAINER_CLASS(_elm_ctxpopup_parent_sc)->content_unset
1443               (obj, part);
1444
1445    content = sd->content;
1446    if (!content) return NULL;
1447
1448    elm_box_unpack(sd->box, sd->content);
1449
1450    sd->content = NULL;
1451    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1452
1453    if (sd->visible) elm_layout_sizing_eval(obj);
1454
1455    return content;
1456 }
1457
1458 static void
1459 _item_text_set_hook(Elm_Object_Item *it,
1460                     const char *part,
1461                     const char *label)
1462 {
1463    Elm_Ctxpopup_Item *ctxpopup_it;
1464
1465    if ((part) && (strcmp(part, "default"))) return;
1466
1467    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1468
1469    _item_label_set(ctxpopup_it, label);
1470 }
1471
1472 static const char *
1473 _item_text_get_hook(const Elm_Object_Item *it,
1474                     const char *part)
1475 {
1476    Elm_Ctxpopup_Item *ctxpopup_it;
1477
1478    if (part && strcmp(part, "default")) return NULL;
1479
1480    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1481    return ctxpopup_it->label;
1482 }
1483
1484 static void
1485 _item_content_set_hook(Elm_Object_Item *it,
1486                        const char *part,
1487                        Evas_Object *content)
1488 {
1489    Elm_Ctxpopup_Item *ctxpopup_it;
1490
1491    if ((part) && (strcmp(part, "icon"))) return;
1492
1493    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1494
1495    ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
1496
1497    _item_icon_set(ctxpopup_it, content);
1498    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1499
1500    if (sd->visible)
1501      _elm_ctxpopup_smart_sizing_eval(WIDGET(ctxpopup_it));
1502 }
1503
1504 static Evas_Object *
1505 _item_content_get_hook(const Elm_Object_Item *it,
1506                        const char *part)
1507 {
1508    Elm_Ctxpopup_Item *ctxpopup_it;
1509
1510    if (part && strcmp(part, "icon")) return NULL;
1511
1512    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1513    return ctxpopup_it->icon;
1514 }
1515
1516 static void
1517 _item_disable_hook(Elm_Object_Item *it)
1518 {
1519    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1520
1521    ELM_CTXPOPUP_DATA_GET(WIDGET(it), sd);
1522    if (!sd) return;
1523
1524    if (elm_widget_item_disabled_get(it))
1525      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,disabled", "elm");
1526    else
1527      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,enabled", "elm");
1528 }
1529
1530 static void
1531 _item_signal_emit_hook(Elm_Object_Item *it,
1532                        const char *emission,
1533                        const char *source)
1534 {
1535    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1536
1537    edje_object_signal_emit(VIEW(ctxpopup_it), emission, source);
1538 }
1539
1540 static void
1541 _item_style_set_hook(Elm_Object_Item *it,
1542                      const char *style)
1543 {
1544    Elm_Ctxpopup_Item *item = (Elm_Ctxpopup_Item *)it;
1545    ELM_CTXPOPUP_DATA_GET(WIDGET(item), sd);
1546
1547    if (item->icon && item->label)
1548       _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", "icon_text_style_item", style);
1549    else if (item->label)
1550      {
1551         if (sd->horizontal)
1552           _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", "text_style_item_horizontal", style);
1553         else
1554           _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", "text_style_item", style);
1555      }
1556    else
1557      _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", "icon_style_item", style);
1558
1559    if (sd->visible) elm_layout_sizing_eval(WIDGET(item));
1560 }
1561
1562 static void
1563 _bg_clicked_cb(void *data,
1564                Evas_Object *obj __UNUSED__,
1565                const char *emission __UNUSED__,
1566                const char *source __UNUSED__)
1567 {
1568    ELM_CTXPOPUP_DATA_GET(data, sd);
1569
1570    _hide_signals_emit(data, sd->dir);
1571 }
1572
1573 static void
1574 _on_show(void *data __UNUSED__,
1575          Evas *e __UNUSED__,
1576          Evas_Object *obj,
1577          void *event_info __UNUSED__)
1578 {
1579    Eina_List *elist;
1580    Elm_Ctxpopup_Item *item;
1581    int idx = 0;
1582
1583    ELM_CTXPOPUP_DATA_GET(obj, sd);
1584    ELM_WIDGET_DATA_GET(obj, wsd);
1585
1586    if ((!sd->items) && (!sd->content)) return;
1587
1588    sd->visible = EINA_TRUE;
1589
1590    edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
1591    elm_layout_signal_emit(obj, "elm,state,show", "elm");
1592
1593    if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1594      elm_widget_theme_object_set
1595        (obj, sd->layout, "ctxpopup", "layout/landscape", elm_widget_style_get(obj));
1596    else
1597      elm_widget_theme_object_set
1598        (obj, sd->layout, "ctxpopup", "layout", elm_widget_style_get(obj));
1599
1600    EINA_LIST_FOREACH(sd->items, elist, item)
1601      {
1602         if (item->label && !item->icon)
1603           {
1604              if(!sd->horizontal)
1605                _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1606                                      "text_style_item",
1607                                      elm_widget_style_get(obj));
1608              else
1609                _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
1610                                      "text_style_item_horizontal",
1611                                      elm_widget_style_get(obj));
1612           }
1613
1614         if (idx++ == 0)
1615           edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
1616         else
1617           edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
1618      }
1619
1620    elm_layout_sizing_eval(obj);
1621
1622    elm_object_focus_set(obj, EINA_TRUE);
1623    _show_signals_emit(obj, sd->dir);
1624 }
1625
1626 static void
1627 _on_hide(void *data __UNUSED__,
1628          Evas *e __UNUSED__,
1629          Evas_Object *obj,
1630          void *event_info __UNUSED__)
1631 {
1632    ELM_CTXPOPUP_DATA_GET(obj, sd);
1633
1634    if (!sd->visible) return;
1635
1636    sd->visible = EINA_FALSE;
1637 }
1638
1639 static void
1640 _on_move(void *data __UNUSED__,
1641          Evas *e __UNUSED__,
1642          Evas_Object *obj,
1643          void *event_info __UNUSED__)
1644 {
1645    ELM_CTXPOPUP_DATA_GET(obj, sd);
1646
1647    if (sd->visible) _elm_ctxpopup_smart_sizing_eval(obj);
1648 }
1649
1650 static void
1651 _hide_finished_cb(void *data,
1652                   Evas_Object *obj __UNUSED__,
1653                   const char *emission __UNUSED__,
1654                   const char *source __UNUSED__)
1655 {
1656    evas_object_hide(data);
1657    evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
1658 }
1659
1660 static void
1661 _list_del(Elm_Ctxpopup_Smart_Data *sd)
1662 {
1663    if (!sd->scr) return;
1664
1665    edje_object_part_unswallow(ELM_WIDGET_DATA(sd)->resize_obj, sd->scr);
1666    evas_object_del(sd->scr);
1667    sd->scr = NULL;
1668    evas_object_del(sd->box);
1669    sd->box = NULL;
1670 }
1671
1672 static void
1673 scroll_up_down_cb(void *data, Evas_Object *obj, void *event_info)
1674 {
1675 #ifndef ELM_FEATURE_WEARABLE
1676    ELM_CTXPOPUP_DATA_GET(data, sd);
1677    if (!sd) return;
1678    Evas_Coord x, y, w, h;
1679    Evas_Coord x2, y2, w2, h2;
1680    const char *color = NULL;
1681    int i = 0;
1682    Eina_List *elist;
1683    Elm_Ctxpopup_Item *item , *top_drawn_item = NULL;
1684
1685    evas_object_geometry_get(ELM_WIDGET_DATA(sd)->resize_obj, &x2, &y2, &w2, &h2);
1686    EINA_LIST_FOREACH(sd->items, elist, item) {
1687      evas_object_geometry_get(VIEW(item), &x, &y, &w, &h);
1688      if ( y <= y2 && ELM_RECTS_INTERSECT(x,y,w,h,x2,y2,w2,h2))
1689        top_drawn_item = item;
1690      if( top_drawn_item && ( top_drawn_item != sd->top_drawn_item  )) {
1691        if( i < MAX_ITEMS_PER_VIEWPORT ) {
1692           color = edje_object_data_get(VIEW(item), "bg_color");
1693           edje_object_color_class_set(VIEW(item), color, sd->item_color[i][0], sd->item_color[i][1], sd->item_color[i][2], 255, 255, 255, 255, 255, 255, 255, 255, 255);
1694           i++;
1695        }
1696      }
1697    }
1698    sd->top_drawn_item = top_drawn_item;
1699 #endif
1700 }
1701
1702 static void
1703 _list_new(Evas_Object *obj)
1704 {
1705    ELM_CTXPOPUP_DATA_GET(obj, sd);
1706    if (!sd) return;
1707
1708    //scroller
1709    sd->scr = elm_scroller_add(obj);
1710    elm_object_style_set(sd->scr, "list_effect");
1711    evas_object_size_hint_align_set(sd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
1712 #ifndef ELM_FEATURE_WEARABLE
1713    evas_object_smart_callback_add(sd->scr, "scroll,up", scroll_up_down_cb, obj);
1714    evas_object_smart_callback_add(sd->scr, "scroll,down", scroll_up_down_cb, obj);
1715 #endif
1716    if (sd->horizontal)
1717      elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
1718    else
1719      elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
1720
1721    edje_object_part_swallow(ELM_WIDGET_DATA(sd)->resize_obj, "elm.swallow.content", sd->scr);
1722
1723    elm_object_content_set(sd->scr, sd->box);
1724    elm_ctxpopup_horizontal_set(obj, sd->horizontal);
1725 }
1726
1727 static Eina_Bool
1728 _elm_ctxpopup_smart_disable(Evas_Object *obj)
1729 {
1730    Eina_List *l;
1731    Elm_Object_Item *it;
1732
1733    ELM_CTXPOPUP_DATA_GET(obj, sd);
1734
1735    if (!ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->disable(obj))
1736      return EINA_FALSE;
1737
1738    EINA_LIST_FOREACH(sd->items, l, it)
1739      elm_object_item_disabled_set(it, elm_widget_disabled_get(obj));
1740
1741    return EINA_TRUE;
1742 }
1743
1744 static void
1745 _elm_ctxpopup_smart_add(Evas_Object *obj)
1746 {
1747    EVAS_SMART_DATA_ALLOC(obj, Elm_Ctxpopup_Smart_Data);
1748
1749    ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->base.add(obj);
1750
1751 }
1752
1753 static void
1754 _elm_ctxpopup_smart_del(Evas_Object *obj)
1755 {
1756    ELM_CTXPOPUP_DATA_GET(obj, sd);
1757
1758    evas_object_event_callback_del_full
1759      (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1760    _parent_detach(obj);
1761
1762    if (sd->items)
1763      {
1764         _items_remove(sd);
1765         _list_del(sd);
1766      }
1767    else
1768      {
1769         evas_object_del(sd->box);
1770         sd->box = NULL;
1771      }
1772
1773    evas_object_del(sd->arrow);
1774    sd->arrow = NULL; /* stops _sizing_eval() from going on on deletion */
1775
1776    evas_object_del(sd->bg);
1777    sd->bg = NULL;
1778
1779    evas_object_del(sd->layout);
1780    sd->layout = NULL;
1781
1782    ELM_WIDGET_CLASS(_elm_ctxpopup_parent_sc)->base.del(obj);
1783 }
1784
1785 static void
1786 _elm_ctxpopup_smart_parent_set(Evas_Object *obj,
1787                                Evas_Object *parent)
1788 {
1789    //default parent is to be hover parent
1790    elm_ctxpopup_hover_parent_set(obj, parent);
1791 }
1792
1793 static void
1794 _elm_ctxpopup_smart_access(Evas_Object *obj, Eina_Bool is_access)
1795 {
1796    ELM_CTXPOPUP_CHECK(obj);
1797
1798    _access_obj_process(obj, is_access);
1799
1800    evas_object_smart_callback_call(obj, SIG_ACCESS_CHANGED, NULL);
1801 }
1802
1803 static Evas_Object *
1804 _elm_ctxpopup_smart_access_object_get(Evas_Object *obj, char *part)
1805 {
1806    ELM_CTXPOPUP_CHECK(obj) NULL;
1807
1808    return _access_object_get(obj, part);
1809 }
1810
1811 static void
1812 _elm_ctxpopup_smart_set_user(Elm_Ctxpopup_Smart_Class *sc)
1813 {
1814    ELM_WIDGET_CLASS(sc)->base.add = _elm_ctxpopup_smart_add;
1815    ELM_WIDGET_CLASS(sc)->base.del = _elm_ctxpopup_smart_del;
1816
1817    ELM_WIDGET_CLASS(sc)->parent_set = _elm_ctxpopup_smart_parent_set;
1818    ELM_WIDGET_CLASS(sc)->disable = _elm_ctxpopup_smart_disable;
1819    ELM_WIDGET_CLASS(sc)->event = _elm_ctxpopup_smart_event;
1820    ELM_WIDGET_CLASS(sc)->theme = _elm_ctxpopup_smart_theme;
1821    ELM_WIDGET_CLASS(sc)->translate = _elm_ctxpopup_smart_translate;
1822    ELM_WIDGET_CLASS(sc)->sub_object_add = _elm_ctxpopup_smart_sub_object_add;
1823    ELM_WIDGET_CLASS(sc)->focus_next = _elm_ctxpopup_smart_focus_next;
1824    ELM_WIDGET_CLASS(sc)->focus_direction_manager_is =
1825       _elm_ctxpopup_smart_focus_direction_manager_is;
1826    ELM_WIDGET_CLASS(sc)->focus_direction = _elm_ctxpopup_smart_focus_direction;
1827
1828    ELM_CONTAINER_CLASS(sc)->content_get = _elm_ctxpopup_smart_content_get;
1829    ELM_CONTAINER_CLASS(sc)->content_set = _elm_ctxpopup_smart_content_set;
1830    ELM_CONTAINER_CLASS(sc)->content_unset = _elm_ctxpopup_smart_content_unset;
1831
1832    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_ctxpopup_smart_sizing_eval;
1833
1834    ELM_WIDGET_CLASS(sc)->access = _elm_ctxpopup_smart_access;
1835    ELM_WIDGET_CLASS(sc)->access_object_get = _elm_ctxpopup_smart_access_object_get;
1836 }
1837
1838 EAPI const Elm_Ctxpopup_Smart_Class *
1839 elm_ctxpopup_smart_class_get(void)
1840 {
1841    static Elm_Ctxpopup_Smart_Class _sc =
1842      ELM_CTXPOPUP_SMART_CLASS_INIT_NAME_VERSION(ELM_CTXPOPUP_SMART_NAME);
1843    static const Elm_Ctxpopup_Smart_Class *class = NULL;
1844    Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
1845
1846    if (class)
1847      return class;
1848
1849    _elm_ctxpopup_smart_set(&_sc);
1850    esc->callbacks = _smart_callbacks;
1851    class = &_sc;
1852
1853    return class;
1854 }
1855
1856 EAPI Evas_Object *
1857 elm_ctxpopup_add(Evas_Object *parent)
1858 {
1859    Evas_Object *obj;
1860
1861    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1862
1863    obj = elm_widget_add(_elm_ctxpopup_smart_class_new(), parent);
1864    if (!obj) return NULL;
1865
1866    if (!elm_widget_sub_object_add(parent, obj))
1867      ERR("could not add %p as sub object of %p", obj, parent);
1868
1869    elm_layout_theme_set(obj, "ctxpopup", "base", elm_widget_style_get(obj));
1870    elm_layout_signal_callback_add
1871      (obj, "elm,action,hide,finished", "", _hide_finished_cb, obj);
1872
1873    ELM_CTXPOPUP_DATA_GET(obj, sd);
1874
1875    //Background
1876    sd->bg = edje_object_add(evas_object_evas_get(obj));
1877    elm_widget_theme_object_set(obj, sd->bg, "ctxpopup", "bg", "default");
1878    edje_object_signal_callback_add
1879      (sd->bg, "elm,action,click", "", _bg_clicked_cb, obj);
1880    evas_object_smart_member_add(sd->bg, obj);
1881    evas_object_stack_below(sd->bg, ELM_WIDGET_DATA(sd)->resize_obj);
1882 #ifndef ELM_FEATURE_WEARABLE
1883    sd->color_calculated = EINA_FALSE;
1884    sd->top_drawn_item = NULL;
1885 #endif
1886    //Arrow
1887    sd->arrow = edje_object_add(evas_object_evas_get(obj));
1888    elm_widget_theme_object_set
1889      (obj, sd->arrow, "ctxpopup", "arrow", "default");
1890
1891    sd->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1892    sd->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1893    sd->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1894    sd->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1895    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1896
1897    sd->auto_hide = EINA_TRUE;
1898    sd->mouse_down = EINA_FALSE;
1899    sd->multi_down = 0;
1900
1901    sd->box = elm_box_add(obj);
1902    evas_object_size_hint_weight_set
1903      (sd->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1904
1905    ELM_WIDGET_DATA_GET(obj, wsd);
1906
1907    sd->layout = edje_object_add(evas_object_evas_get(obj));
1908    if (wsd->orient_mode == 90 || wsd->orient_mode == 270)
1909      elm_widget_theme_object_set(obj, sd->layout, "ctxpopup", "layout/landscape", "default");
1910    else
1911      elm_widget_theme_object_set(obj, sd->layout, "ctxpopup", "layout", "default");
1912    evas_object_smart_member_add(sd->layout, obj);
1913
1914    edje_object_signal_callback_add
1915      (sd->layout, "elm,action,hide,finished", "", _hide_finished_cb, obj);
1916    edje_object_part_swallow(sd->layout, "swallow", ELM_WIDGET_DATA(sd)->resize_obj);
1917    evas_object_size_hint_weight_set
1918      (sd->layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1919
1920    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show, NULL);
1921    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide, NULL);
1922    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _on_move, NULL);
1923
1924    _mirrored_set(obj, elm_widget_mirrored_get(obj));
1925
1926    elm_widget_can_focus_set(obj, EINA_TRUE);
1927    elm_ctxpopup_hover_parent_set(obj, parent);
1928    /* access */
1929    if (_elm_config->access_mode) _access_obj_process(obj, EINA_TRUE);
1930
1931    /* access: parent could be any object such as elm_list which does
1932       not know elc_ctxpopup as its child object in the focus_next(); */
1933
1934    wsd->highlight_root = EINA_TRUE;
1935
1936    //Tizen Only: This should be removed when eo is applied.
1937    wsd->on_create = EINA_FALSE;
1938
1939    return obj;
1940 }
1941
1942 EAPI void
1943 elm_ctxpopup_hover_parent_set(Evas_Object *obj,
1944                               Evas_Object *parent)
1945 {
1946    Evas_Coord x, y, w, h;
1947
1948    ELM_CTXPOPUP_CHECK(obj);
1949    ELM_CTXPOPUP_DATA_GET(obj, sd);
1950
1951    if (!parent) return;
1952
1953    _parent_detach(obj);
1954
1955    evas_object_event_callback_add
1956      (parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
1957    evas_object_event_callback_add
1958      (parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
1959    evas_object_event_callback_add
1960      (parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
1961
1962    sd->parent = parent;
1963
1964    //Update Background
1965    evas_object_geometry_get(parent, &x, &y, &w, &h);
1966    evas_object_move(sd->bg, x, y);
1967    evas_object_resize(sd->bg, w, h);
1968
1969    if (sd->visible) elm_layout_sizing_eval(obj);
1970 }
1971
1972 EAPI Evas_Object *
1973 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1974 {
1975    ELM_CTXPOPUP_CHECK(obj) NULL;
1976    ELM_CTXPOPUP_DATA_GET(obj, sd);
1977
1978    return sd->parent;
1979 }
1980
1981 EAPI void
1982 elm_ctxpopup_clear(Evas_Object *obj)
1983 {
1984    ELM_CTXPOPUP_CHECK(obj);
1985    ELM_CTXPOPUP_DATA_GET(obj, sd);
1986
1987    _items_remove(sd);
1988
1989    elm_object_content_unset(sd->scr);
1990    edje_object_part_unswallow(ELM_WIDGET_DATA(sd)->resize_obj, sd->scr);
1991    evas_object_del(sd->scr);
1992    sd->scr = NULL;
1993    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1994 }
1995
1996 EAPI void
1997 elm_ctxpopup_horizontal_set(Evas_Object *obj,
1998                             Eina_Bool horizontal)
1999 {
2000    Eina_List *elist;
2001    Elm_Ctxpopup_Item *item;
2002    int idx = 0;
2003
2004    ELM_CTXPOPUP_CHECK(obj);
2005    ELM_CTXPOPUP_DATA_GET(obj, sd);
2006
2007    sd->horizontal = !!horizontal;
2008
2009    if (!sd->scr)
2010       return;
2011
2012   if (!horizontal)
2013      {
2014         elm_box_horizontal_set(sd->box, EINA_FALSE);
2015         elm_scroller_bounce_set(sd->scr, EINA_FALSE, EINA_TRUE);
2016         elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
2017      }
2018    else
2019      {
2020         elm_box_horizontal_set(sd->box, EINA_TRUE);
2021         elm_scroller_bounce_set(sd->scr, EINA_TRUE, EINA_FALSE);
2022         elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
2023      }
2024
2025    EINA_LIST_FOREACH(sd->items, elist, item)
2026      {
2027         if (item->label && !item->icon && !horizontal)
2028           _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "text_style_item",
2029                                 elm_widget_style_get(obj));
2030         else if (item->label && !item->icon && horizontal)
2031           _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
2032                                 "text_style_item_horizontal",
2033                                 elm_widget_style_get(obj));
2034
2035         if (idx++ == 0)
2036           edje_object_signal_emit(VIEW(item), "elm,state,default", "elm");
2037         else
2038           edje_object_signal_emit(VIEW(item), "elm,state,separator", "elm");
2039
2040         _item_disable_hook((Elm_Object_Item *)item);
2041      }
2042
2043    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
2044
2045    if (sd->visible) elm_layout_sizing_eval(obj);
2046 }
2047
2048 EAPI Eina_Bool
2049 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
2050 {
2051    ELM_CTXPOPUP_CHECK(obj) EINA_FALSE;
2052    ELM_CTXPOPUP_DATA_GET(obj, sd);
2053
2054    return sd->horizontal;
2055 }
2056
2057 EAPI Elm_Object_Item *
2058 elm_ctxpopup_item_append(Evas_Object *obj,
2059                          const char *label,
2060                          Evas_Object *icon,
2061                          Evas_Smart_Cb func,
2062                          const void *data)
2063 {
2064    Elm_Ctxpopup_Item *item, *it;
2065    Evas_Object *content, *focus_bt;
2066    int idx = 0;
2067    Eina_List *elist;
2068
2069    ELM_CTXPOPUP_CHECK(obj) NULL;
2070    ELM_CTXPOPUP_DATA_GET(obj, sd);
2071
2072    item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
2073    if (!item) return NULL;
2074
2075    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
2076    elm_widget_item_disable_hook_set(item, _item_disable_hook);
2077    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
2078    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
2079    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
2080    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
2081    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
2082    elm_widget_item_style_set_hook_set(item, _item_style_set_hook);
2083
2084    //The first item is appended.
2085    content = elm_object_content_unset(obj);
2086    if (content) evas_object_del(content);
2087
2088    if (!sd->items)
2089      _list_new(obj);
2090
2091    item->func = func;
2092    item->base.data = data;
2093
2094    if (icon && label)
2095      _item_new(item, "icon_text_style_item");
2096    else if (label)
2097      {
2098         if (!sd->horizontal)
2099           _item_new(item, "text_style_item");
2100         else
2101           _item_new(item, "text_style_item_horizontal");
2102      }
2103    else
2104      _item_new(item, "icon_style_item");
2105
2106    _item_icon_set(item, icon);
2107    _item_label_set(item, label);
2108    focus_bt = _item_in_focusable_button(item);
2109    elm_box_pack_end(sd->box, focus_bt);
2110    sd->items = eina_list_append(sd->items, item);
2111    item->btn = focus_bt;
2112
2113    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
2114 #ifndef ELM_FEATURE_WEARABLE
2115         const char *color = NULL;
2116         int i = 0;
2117         if (sd->color_calculated) {
2118           EINA_LIST_FOREACH(sd->items, elist, it) {
2119              if( i < MAX_ITEMS_PER_VIEWPORT ) {
2120                 color = edje_object_data_get(VIEW(it), "bg_color");
2121                 edje_object_color_class_set(VIEW(it), color, sd->item_color[i][0], sd->item_color[i][1], sd->item_color[i][2], 255, 255, 255, 255, 255, 255, 255, 255, 255);
2122                 i++;
2123              }
2124           }
2125         }
2126 #endif
2127    if (sd->visible)
2128      {
2129         EINA_LIST_FOREACH(sd->items, elist, it)
2130           {
2131              if (idx++ == 0)
2132                edje_object_signal_emit(VIEW(it), "elm,state,default", "elm");
2133              else
2134                edje_object_signal_emit(VIEW(it), "elm,state,separator", "elm");
2135           }
2136         _elm_ctxpopup_smart_sizing_eval(obj);
2137      }
2138
2139    if (_elm_config->access_mode) _access_focusable_button_register(focus_bt, item);
2140
2141    return (Elm_Object_Item *)item;
2142 }
2143
2144 EAPI void
2145 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
2146                                     Elm_Ctxpopup_Direction first,
2147                                     Elm_Ctxpopup_Direction second,
2148                                     Elm_Ctxpopup_Direction third,
2149                                     Elm_Ctxpopup_Direction fourth)
2150 {
2151    ELM_CTXPOPUP_CHECK(obj);
2152    ELM_CTXPOPUP_DATA_GET(obj, sd);
2153
2154    sd->dir_priority[0] = first;
2155    sd->dir_priority[1] = second;
2156    sd->dir_priority[2] = third;
2157    sd->dir_priority[3] = fourth;
2158
2159    if (sd->visible) elm_layout_sizing_eval(obj);
2160 }
2161
2162 EAPI void
2163 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
2164                                     Elm_Ctxpopup_Direction *first,
2165                                     Elm_Ctxpopup_Direction *second,
2166                                     Elm_Ctxpopup_Direction *third,
2167                                     Elm_Ctxpopup_Direction *fourth)
2168 {
2169    ELM_CTXPOPUP_CHECK(obj);
2170    ELM_CTXPOPUP_DATA_GET(obj, sd);
2171
2172    if (first) *first = sd->dir_priority[0];
2173    if (second) *second = sd->dir_priority[1];
2174    if (third) *third = sd->dir_priority[2];
2175    if (fourth) *fourth = sd->dir_priority[3];
2176 }
2177
2178 EAPI Elm_Ctxpopup_Direction
2179 elm_ctxpopup_direction_get(const Evas_Object *obj)
2180 {
2181    ELM_CTXPOPUP_CHECK(obj) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
2182    ELM_CTXPOPUP_DATA_GET(obj, sd);
2183
2184    return sd->dir;
2185 }
2186
2187 EAPI Eina_Bool
2188 elm_ctxpopup_direction_available_get(Evas_Object *obj, Elm_Ctxpopup_Direction direction)
2189 {
2190    ELM_CTXPOPUP_CHECK(obj) EINA_FALSE;
2191    ELM_CTXPOPUP_DATA_GET(obj, sd);
2192
2193    elm_layout_sizing_eval(obj);
2194
2195    if (sd->dir == direction) return EINA_TRUE;
2196    return EINA_FALSE;
2197 }
2198
2199 EAPI void
2200 elm_ctxpopup_dismiss(Evas_Object *obj)
2201 {
2202    ELM_CTXPOPUP_CHECK(obj);
2203    ELM_CTXPOPUP_DATA_GET(obj, sd);
2204
2205    _hide_signals_emit(obj, sd->dir);
2206 }
2207
2208 EAPI void
2209 elm_ctxpopup_auto_hide_disabled_set(Evas_Object *obj, Eina_Bool disabled)
2210 {
2211    ELM_CTXPOPUP_CHECK(obj);
2212    ELM_CTXPOPUP_DATA_GET(obj, sd);
2213
2214    disabled = !!disabled;
2215
2216    if (sd->auto_hide == !disabled) return;
2217    sd->auto_hide = !disabled;
2218 }