elementary/ctxpopup
[platform/upstream/elementary.git] / src / lib / elc_ctxpopup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Elm_Ctxpopup_Item Elm_Ctxpopup_Item;
6
7 struct _Elm_Ctxpopup_Item
8 {
9    ELM_WIDGET_ITEM;
10    const char *label;
11    Evas_Object *icon;
12    Evas_Smart_Cb func;
13 };
14
15 struct _Widget_Data
16 {
17    Evas_Object *parent;
18    Evas_Object *base;
19    Evas_Object *content;
20    Evas_Object *box;
21    Evas_Object *arrow;
22    Evas_Object *scr;
23    Evas_Object *bg;
24    Eina_List *items;
25    Elm_Ctxpopup_Direction dir;
26    Elm_Ctxpopup_Direction dir_priority[4];
27    Evas_Coord max_sc_w, max_sc_h;
28    Eina_Bool horizontal:1;
29    Eina_Bool visible:1;
30    Eina_Bool finished:1;
31 };
32
33 static const char *widtype = NULL;
34
35 static void _freeze_on(void *data, Evas_Object *obj, void *event_info);
36 static void _freeze_off(void *data, Evas_Object *obj, void *event_info);
37 static void _hold_on(void *data, Evas_Object *obj, void *event_info);
38 static void _hold_off(void *data, Evas_Object *obj, void *event_info);
39 static void _scroller_size_reset(Widget_Data *wd);
40 static void _on_focus_hook(void *data, Evas_Object *obj);
41 static Eina_Bool _event_hook(Evas_Object *obj,
42                              Evas_Object *src,
43                              Evas_Callback_Type type,
44                              void *event_info);
45 static void _parent_cut_off(Evas_Object *obj);
46 static void _parent_resize(void *data,
47                            Evas *e,
48                            Evas_Object *obj,
49                            void *event_info);
50 static void _parent_move(void *data,
51                          Evas *e,
52                          Evas_Object *obj,
53                          void *event_info);
54 static void _parent_del(void *data,
55                         Evas *e,
56                         Evas_Object *obj,
57                         void *event_info);
58 static void _item_sizing_eval(Elm_Ctxpopup_Item *item);
59 static void _adjust_pos_x(Evas_Coord_Point *pos,
60                           Evas_Coord_Point *base_size,
61                           Evas_Coord_Rectangle *hover_area);
62 static void _adjust_pos_y(Evas_Coord_Point *pos,
63                           Evas_Coord_Point *base_size,
64                           Evas_Coord_Rectangle *hover_area);
65 static Elm_Ctxpopup_Direction _calc_base_geometry(Evas_Object *obj,
66                                                   Evas_Coord_Rectangle *rect);
67 static void _update_arrow(Evas_Object *obj, Elm_Ctxpopup_Direction dir, Evas_Coord_Rectangle rect);
68 static void _sizing_eval(Evas_Object *obj);
69 static void _shift_base_by_arrow(Evas_Object *arrow,
70                                  Elm_Ctxpopup_Direction dir,
71                                  Evas_Coord_Rectangle *rect);
72 static void _del_pre_hook(Evas_Object *obj);
73 static void _del_hook(Evas_Object *obj);
74 static void _theme_hook(Evas_Object *obj);
75 static void _content_set_hook(Evas_Object *obj,
76                               const char *part,
77                               Evas_Object *content);
78 static Evas_Object * _content_unset_hook(Evas_Object *obj,
79                                          const char *part__);
80 static Evas_Object * _content_get_hook(const Evas_Object *obj,
81                                        const char *part);
82 static void _item_text_set_hook(Elm_Object_Item *it,
83                                const char *part,
84                                const char *label);
85 static const char * _item_text_get_hook(const Elm_Object_Item *it,
86                                         const char *part);
87 static void _item_content_set_hook(Elm_Object_Item *it,
88                                    const char *part,
89                                    Evas_Object *content);
90 static Evas_Object * _item_content_get_hook(const Elm_Object_Item *it,
91                                             const char *part);
92 static void _item_disable_set_hook(Elm_Object_Item *it);
93 static void _item_signal_emit_hook(Elm_Object_Item *it,
94                                    const char *emission,
95                                    const char *source);
96 static void _bg_clicked_cb(void *data, Evas_Object *obj,
97                            const char *emission,
98                            const char *source);
99 static void _ctxpopup_show(void *data,
100                            Evas *e,
101                            Evas_Object *obj,
102                            void *event_info);
103 static void _hide(Evas_Object *obj);
104 static void _ctxpopup_hide(void *data,
105                            Evas *e,
106                            Evas_Object *obj,
107                            void *event_info);
108 static void _content_resize(void *data,
109                             Evas *e,
110                             Evas_Object *obj,
111                             void *event_info);
112 static void _scroller_resize(void *data,
113                              Evas *e,
114                              Evas_Object *obj,
115                              void *event_info);
116 static void _ctxpopup_move(void *data,
117                            Evas *e,
118                            Evas_Object *obj,
119                            void *event_info);
120 static void _item_select_cb(void *data, Evas_Object *obj,
121                             const char *emission,
122                             const char *source);
123 static void _item_icon_set(Elm_Ctxpopup_Item *item, Evas_Object *icon);
124 static void _item_label_set(Elm_Ctxpopup_Item *item, const char *label);
125 static void _item_new(Elm_Ctxpopup_Item *item, char *group_name);
126 static void _content_del(void *data,
127                          Evas *e,
128                          Evas_Object *obj,
129                          void *event_info);
130 static void _list_del(Widget_Data *wd);
131 static void _list_new(Evas_Object *obj);
132 static void _remove_items(Widget_Data * wd);
133
134 static const char SIG_DISMISSED[] = "dismissed";
135
136 static const Evas_Smart_Cb_Description _signals[] = {
137    {SIG_DISMISSED, ""},
138    {NULL, NULL}
139 };
140
141 static void
142 _freeze_on(void *data __UNUSED__, Evas_Object *obj,
143            void *event_info __UNUSED__)
144 {
145    Widget_Data *wd = elm_widget_data_get(obj);
146
147    if ((!wd) || (!wd->scr)) return;
148    elm_object_scroll_freeze_push(wd->scr);
149 }
150
151 static void
152 _freeze_off(void *data __UNUSED__, Evas_Object *obj,
153             void *event_info __UNUSED__)
154 {
155    Widget_Data *wd = elm_widget_data_get(obj);
156
157    if ((!wd) || (!wd->scr)) return;
158    elm_object_scroll_freeze_pop(wd->scr);
159 }
160
161 static void
162 _hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
163 {
164    Widget_Data *wd = elm_widget_data_get(obj);
165
166    if ((!wd) || (!wd->scr)) return;
167    elm_object_scroll_hold_push(wd->scr);
168 }
169
170 static void
171 _hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
172 {
173    Widget_Data *wd = elm_widget_data_get(obj);
174
175    if ((!wd) || (!wd->scr)) return;
176    elm_object_scroll_hold_pop(wd->scr);
177 }
178
179 static void
180 _scroller_size_reset(Widget_Data *wd)
181 {
182    wd->finished = EINA_FALSE;
183    wd->max_sc_h = -1;
184    wd->max_sc_w = -1;
185 }
186
187 static void
188 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
189 {
190    Widget_Data *wd = elm_widget_data_get(obj);
191    if (!wd) return;
192
193    if (elm_widget_focus_get(obj))
194      {
195         //FIXME:
196      }
197    else
198      {
199         //FIXME:
200      }
201 }
202
203 static Eina_Bool
204 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
205 {
206    Evas_Event_Key_Down *ev;
207    Widget_Data *wd;
208
209    if (type != EVAS_CALLBACK_KEY_DOWN)
210      return EINA_FALSE;
211    wd = elm_widget_data_get(obj);
212    if (!wd) return EINA_FALSE;
213
214    ev = event_info;
215    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
216    if (strcmp(ev->keyname, "Escape")) return EINA_FALSE;
217
218    evas_object_hide(obj);
219    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
220    return EINA_TRUE;
221 }
222
223 static void
224 _parent_cut_off(Evas_Object *obj)
225 {
226    Widget_Data *wd = elm_widget_data_get(obj);
227
228    if (!wd) return;
229
230    evas_object_event_callback_del_full(wd->parent,
231                                        EVAS_CALLBACK_DEL,
232                                        _parent_del,
233                                        obj);
234    evas_object_event_callback_del_full(wd->parent,
235                                        EVAS_CALLBACK_MOVE,
236                                        _parent_move,
237                                        obj);
238    evas_object_event_callback_del_full(wd->parent,
239                                        EVAS_CALLBACK_RESIZE,
240                                        _parent_resize,
241                                        obj);
242
243    elm_widget_sub_object_del(wd->parent, obj);
244 }
245
246 static void
247 _parent_resize(void *data,
248                Evas *e __UNUSED__,
249                Evas_Object *obj __UNUSED__,
250                void *event_info __UNUSED__)
251 {
252    Widget_Data *wd = elm_widget_data_get(data);
253    if (!wd) return;
254
255    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
256
257    _hide(data);
258 }
259
260 static void
261 _parent_move(void *data,
262              Evas *e __UNUSED__,
263              Evas_Object *obj __UNUSED__,
264              void *event_info __UNUSED__)
265 {
266    Widget_Data *wd = elm_widget_data_get(data);
267
268    if (!wd) return;
269
270    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
271
272    if (wd->visible)
273      {
274         _scroller_size_reset(wd);
275         _sizing_eval(obj);
276      }
277 }
278
279 static void
280 _parent_del(void *data,
281             Evas *e __UNUSED__,
282             Evas_Object *obj __UNUSED__,
283             void *event_info __UNUSED__)
284 {
285    evas_object_del(data);
286 }
287
288 static void
289 _item_sizing_eval(Elm_Ctxpopup_Item *item)
290 {
291    Evas_Coord min_w = -1, min_h = -1, max_w = -1, max_h = -1;
292
293    if (!item) return;
294
295    edje_object_size_min_restricted_calc(VIEW(item), &min_w, &min_h, min_w,
296                                         min_h);
297    evas_object_size_hint_min_set(VIEW(item), min_w, min_h);
298    evas_object_size_hint_max_set(VIEW(item), max_w, max_h);
299 }
300
301 static void
302 _adjust_pos_x(Evas_Coord_Point *pos, Evas_Coord_Point *base_size,
303               Evas_Coord_Rectangle *hover_area)
304 {
305    pos->x -= (base_size->x / 2);
306
307    if (pos->x < hover_area->x)
308      pos->x = hover_area->x;
309    else if ((pos->x + base_size->x) > (hover_area->x + hover_area->w))
310      pos->x = (hover_area->x + hover_area->w) - base_size->x;
311
312    if (base_size->x > hover_area->w)
313      base_size->x -= (base_size->x - hover_area->w);
314
315    if (pos->x < hover_area->x)
316      pos->x = hover_area->x;
317 }
318
319 static void
320 _adjust_pos_y(Evas_Coord_Point *pos, Evas_Coord_Point *base_size,
321               Evas_Coord_Rectangle *hover_area)
322 {
323    pos->y -= (base_size->y / 2);
324
325    if (pos->y < hover_area->y)
326      pos->y = hover_area->y;
327    else if ((pos->y + base_size->y) > (hover_area->y + hover_area->h))
328      pos->y = hover_area->y + hover_area->h - base_size->y;
329
330    if (base_size->y > hover_area->h)
331      base_size->y -= (base_size->y - hover_area->h);
332
333    if (pos->y < hover_area->y)
334      pos->y = hover_area->y;
335 }
336
337 static Elm_Ctxpopup_Direction
338 _calc_base_geometry(Evas_Object *obj, Evas_Coord_Rectangle *rect)
339 {
340    Widget_Data *wd;
341    Evas_Coord_Point pos = {0, 0};
342    Evas_Coord_Point base_size;
343    Evas_Coord_Point max_size;
344    Evas_Coord_Point min_size;
345    Evas_Coord_Rectangle hover_area;
346    Evas_Coord_Point arrow_size;
347    Elm_Ctxpopup_Direction dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
348    Evas_Coord_Point temp;
349    int idx;
350
351    wd = elm_widget_data_get(obj);
352
353    if ((!wd) || (!rect))
354      return ELM_CTXPOPUP_DIRECTION_DOWN;
355
356    edje_object_part_geometry_get(wd->arrow, "ctxpopup_arrow", NULL, NULL,
357                                  &arrow_size.x, &arrow_size.y);
358    evas_object_resize(wd->arrow, arrow_size.x, arrow_size.y);
359
360    //Initialize Area Rectangle.
361    evas_object_geometry_get(wd->parent,
362                             &hover_area.x,
363                             &hover_area.y,
364                             &hover_area.w,
365                             &hover_area.h);
366
367    evas_object_geometry_get(obj, &pos.x, &pos.y, NULL, NULL);
368
369    //recalc the edje
370    edje_object_size_min_calc(wd->base, &base_size.x, &base_size.y);
371    evas_object_smart_calculate(wd->base);
372
373    //Limit to Max Size
374    evas_object_size_hint_max_get(obj, &max_size.x, &max_size.y);
375
376    if ((max_size.y > 0) && (base_size.y > max_size.y))
377      base_size.y = max_size.y;
378
379    if ((max_size.x > 0) && (base_size.x > max_size.x))
380      base_size.x = max_size.x;
381
382    //Limit to Min Size
383    evas_object_size_hint_min_get(obj, &min_size.x, &min_size.y);
384
385    if ((min_size.y > 0) && (base_size.y < min_size.y))
386      base_size.y = min_size.y;
387
388    if ((min_size.x > 0) && (base_size.x < min_size.x))
389      base_size.x = min_size.x;
390
391    //Check the Which direction is available.
392    //If find a avaialble direction, it adjusts position and size.
393    for (idx = 0; idx < 4; idx++)
394      {
395         switch (wd->dir_priority[idx])
396           {
397            case ELM_CTXPOPUP_DIRECTION_UNKNOWN:
398            case ELM_CTXPOPUP_DIRECTION_UP:
399               temp.y = (pos.y - base_size.y);
400               if ((temp.y - arrow_size.y) < hover_area.y)
401                 continue;
402               _adjust_pos_x(&pos, &base_size, &hover_area);
403               pos.y -= base_size.y;
404               dir = ELM_CTXPOPUP_DIRECTION_UP;
405               break;
406            case ELM_CTXPOPUP_DIRECTION_LEFT:
407               temp.x = (pos.x - base_size.x);
408               if ((temp.x - arrow_size.x) < hover_area.x)
409                 continue;
410               _adjust_pos_y(&pos, &base_size, &hover_area);
411               pos.x -= base_size.x;
412               dir = ELM_CTXPOPUP_DIRECTION_LEFT;
413               break;
414            case ELM_CTXPOPUP_DIRECTION_RIGHT:
415               temp.x = (pos.x + base_size.x);
416               if ((temp.x + arrow_size.x) >
417                   (hover_area.x + hover_area.w))
418                 continue;
419               _adjust_pos_y(&pos, &base_size, &hover_area);
420               dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
421               break;
422            case ELM_CTXPOPUP_DIRECTION_DOWN:
423               temp.y = (pos.y + base_size.y);
424               if ((temp.y + arrow_size.y) >
425                   (hover_area.y + hover_area.h))
426                 continue;
427               _adjust_pos_x(&pos, &base_size, &hover_area);
428               dir = ELM_CTXPOPUP_DIRECTION_DOWN;
429               break;
430            default:
431               break;
432           }
433         break;
434      }
435
436    //In this case, all directions are invalid because of lack of space.
437    if (idx == 4)
438      {
439         Evas_Coord length[2];
440
441         if(!wd->horizontal)
442           {
443              length[0] = pos.y - hover_area.y;
444              length[1] = (hover_area.y + hover_area.h) - pos.y;
445
446              // ELM_CTXPOPUP_DIRECTION_UP
447              if (length[0] > length[1])
448                {
449                   _adjust_pos_x(&pos, &base_size, &hover_area);
450                   pos.y -= base_size.y;
451                   dir = ELM_CTXPOPUP_DIRECTION_UP;
452                   if (pos.y < (hover_area.y + arrow_size.y))
453                     {
454                        base_size.y -= ((hover_area.y + arrow_size.y) - pos.y);
455                        pos.y = hover_area.y + arrow_size.y;
456                     }
457                }
458              //ELM_CTXPOPUP_DIRECTION_DOWN
459              else
460                {
461                   _adjust_pos_x(&pos, &base_size, &hover_area);
462                   dir = ELM_CTXPOPUP_DIRECTION_DOWN;
463                   if ((pos.y + arrow_size.y + base_size.y) >
464                       (hover_area.y + hover_area.h))
465                      base_size.y -=
466                         ((pos.y + arrow_size.y + base_size.y) -
467                          (hover_area.y + hover_area.h));
468                }
469           }
470         else
471           {
472              length[0] = pos.x - hover_area.x;
473              length[1] = (hover_area.x + hover_area.w) - pos.x;
474
475              //ELM_CTXPOPUP_DIRECTION_LEFT
476              if (length[0] > length[1])
477                {
478                   _adjust_pos_y(&pos, &base_size, &hover_area);
479                   pos.x -= base_size.x;
480                   dir = ELM_CTXPOPUP_DIRECTION_LEFT;
481                   if (pos.x < (hover_area.x + arrow_size.x))
482                     {
483                        base_size.x -= ((hover_area.x + arrow_size.x) - pos.x);
484                        pos.x = hover_area.x + arrow_size.x;
485                     }
486                }
487              //ELM_CTXPOPUP_DIRECTION_RIGHT
488              else
489                {
490                   _adjust_pos_y(&pos, &base_size, &hover_area);
491                   dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
492                   if (pos.x + (arrow_size.x + base_size.x) >
493                       hover_area.x + hover_area.w)
494                      base_size.x -=
495                         ((pos.x + arrow_size.x + base_size.x) -
496                          (hover_area.x + hover_area.w));
497                }
498           }
499      }
500
501    //Final position and size.
502    rect->x = pos.x;
503    rect->y = pos.y;
504    rect->w = base_size.x;
505    rect->h = base_size.y;
506
507    return dir;
508 }
509
510 static void
511 _update_arrow(Evas_Object *obj, Elm_Ctxpopup_Direction dir, Evas_Coord_Rectangle base_size)
512 {
513    Evas_Coord x, y;
514    Evas_Coord_Rectangle arrow_size;
515    Widget_Data *wd;
516    double drag;
517
518    wd = elm_widget_data_get(obj);
519    if (!wd) return;
520
521    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
522    evas_object_geometry_get(wd->arrow, NULL, NULL, &arrow_size.w,
523                             &arrow_size.h);
524
525    edje_object_part_unswallow(wd->base, wd->arrow);
526
527    switch (dir)
528      {
529       case ELM_CTXPOPUP_DIRECTION_RIGHT:
530          edje_object_signal_emit(wd->arrow, "elm,state,left", "elm");
531          edje_object_part_swallow(wd->base,
532                                   "elm.swallow.arrow_left",
533                                   wd->arrow);
534          if (base_size.h > 0)
535            {
536               if (y < ((arrow_size.h * 0.5) + base_size.y))
537                 y = 0;
538               else if (y > base_size.y + base_size.h - (arrow_size.h * 0.5))
539                 y = base_size.h - arrow_size.h;
540               else
541                 y = y - base_size.y - (arrow_size.h * 0.5);
542               drag = (double) (y) / (double) (base_size.h - arrow_size.h);
543               edje_object_part_drag_value_set(wd->base,
544                                               "elm.swallow.arrow_left",
545                                               1,
546                                               drag);
547            }
548          break;
549       case ELM_CTXPOPUP_DIRECTION_LEFT:
550          edje_object_signal_emit(wd->arrow, "elm,state,right", "elm");
551          edje_object_part_swallow(wd->base,
552                                   "elm.swallow.arrow_right",
553                                   wd->arrow);
554          if (base_size.h > 0)
555            {
556               if (y < ((arrow_size.h * 0.5) + base_size.y))
557                 y = 0;
558               else if (y > (base_size.y + base_size.h - (arrow_size.h * 0.5)))
559                 y = base_size.h - arrow_size.h;
560               else
561                 y = y - base_size.y - (arrow_size.h * 0.5);
562               drag = (double) (y) / (double) (base_size.h - arrow_size.h);
563               edje_object_part_drag_value_set(wd->base,
564                                               "elm.swallow.arrow_right",
565                                               0,
566                                               drag);
567            }
568          break;
569       case ELM_CTXPOPUP_DIRECTION_DOWN:
570          edje_object_signal_emit(wd->arrow, "elm,state,top", "elm");
571          edje_object_part_swallow(wd->base, "elm.swallow.arrow_up", wd->arrow);
572          if (base_size.w > 0)
573            {
574               if (x < ((arrow_size.w * 0.5) + base_size.x))
575                 x = 0;
576               else if (x > (base_size.x + base_size.w - (arrow_size.w * 0.5)))
577                 x = base_size.w - arrow_size.w;
578               else
579                 x = x - base_size.x - (arrow_size.w * 0.5);
580               drag = (double) (x) / (double) (base_size.w - arrow_size.w);
581               edje_object_part_drag_value_set(wd->base,
582                                               "elm.swallow.arrow_up",
583                                               drag,
584                                               1);
585            }
586          break;
587       case ELM_CTXPOPUP_DIRECTION_UP:
588          edje_object_signal_emit(wd->arrow, "elm,state,bottom", "elm");
589          edje_object_part_swallow(wd->base,
590                                   "elm.swallow.arrow_down",
591                                   wd->arrow);
592          if (base_size.w > 0)
593            {
594               if (x < ((arrow_size.w * 0.5) + base_size.x))
595                 x = 0;
596               else if (x > (base_size.x + base_size.w - (arrow_size.w * 0.5)))
597                 x = base_size.w - arrow_size.w;
598               else x = x - base_size.x - (arrow_size.w * 0.5);
599               drag = (double) (x) / (double) (base_size.w - arrow_size.w);
600               edje_object_part_drag_value_set(wd->base,
601                                               "elm.swallow.arrow_down",
602                                               drag,
603                                               0);
604            }
605          break;
606       default:
607          break;
608      }
609 }
610
611 static void
612 _show_signal_emit(Evas_Object *obj, Elm_Ctxpopup_Direction dir)
613 {
614    Widget_Data *wd;
615
616    wd = elm_widget_data_get(obj);
617    if (!wd || wd->visible) return;
618
619    switch (dir)
620      {
621         case ELM_CTXPOPUP_DIRECTION_UP:
622            edje_object_signal_emit(wd->base, "elm,state,show,up", "elm");
623            break;
624         case ELM_CTXPOPUP_DIRECTION_LEFT:
625            edje_object_signal_emit(wd->base, "elm,state,show,left", "elm");
626            break;
627         case ELM_CTXPOPUP_DIRECTION_RIGHT:
628            edje_object_signal_emit(wd->base, "elm,state,show,right", "elm");
629            break;
630         case ELM_CTXPOPUP_DIRECTION_DOWN:
631            edje_object_signal_emit(wd->base, "elm,state,show,down", "elm");
632            break;
633         default:
634            break;
635      }
636 }
637
638 static void
639 _sizing_eval(Evas_Object *obj)
640 {
641    Widget_Data *wd;
642    Eina_List *elist;
643    Elm_Ctxpopup_Item *item;
644    Evas_Coord_Rectangle rect = { 0, 0, 1, 1 };
645    Evas_Coord_Point box_size = { 0, 0 };
646    Evas_Coord_Point _box_size = { 0, 0 };
647
648    wd = elm_widget_data_get(obj);
649    if (!wd) return;
650
651    //Box, Scroller
652    EINA_LIST_FOREACH(wd->items, elist, item)
653      {
654         _item_sizing_eval(item);
655         evas_object_size_hint_min_get(VIEW(item), &_box_size.x, &_box_size.y);
656         if (!wd->horizontal)
657           {
658              if (_box_size.x > box_size.x)
659                box_size.x = _box_size.x;
660              if (_box_size.y != -1)
661                box_size.y += _box_size.y;
662           }
663         else
664           {
665              if (_box_size.x != -1)
666                box_size.x += _box_size.x;
667              if (_box_size.y > box_size.y)
668                box_size.y = _box_size.y;
669           }
670      }
671
672    if (!wd->content)
673      {
674         evas_object_size_hint_min_set(wd->box, box_size.x, box_size.y);
675         evas_object_size_hint_min_set(wd->scr, box_size.x, box_size.y);
676      }
677
678    //Base
679    wd->dir = _calc_base_geometry(obj, &rect);
680    _show_signal_emit(obj, wd->dir);
681    _update_arrow(obj, wd->dir, rect);
682    _shift_base_by_arrow(wd->arrow, wd->dir, &rect);
683
684    //resize scroller according to final size.
685    if (!wd->content)
686      evas_object_smart_calculate(wd->scr);
687
688    evas_object_move(wd->base, rect.x, rect.y);
689    evas_object_resize(wd->base, rect.w, rect.h);
690 }
691
692 static void
693 _shift_base_by_arrow(Evas_Object *arrow, Elm_Ctxpopup_Direction dir,
694                      Evas_Coord_Rectangle *rect)
695 {
696    Evas_Coord arrow_w, arrow_h;
697
698    evas_object_geometry_get(arrow, NULL, NULL, &arrow_w, &arrow_h);
699
700    switch (dir)
701      {
702       case ELM_CTXPOPUP_DIRECTION_RIGHT:
703          rect->x += arrow_w;
704          break;
705       case ELM_CTXPOPUP_DIRECTION_LEFT:
706          rect->x -= arrow_w;
707          break;
708       case ELM_CTXPOPUP_DIRECTION_DOWN:
709          rect->y += arrow_h;
710          break;
711       case ELM_CTXPOPUP_DIRECTION_UP:
712          rect->y -= arrow_h;
713          break;
714       default:
715          break;
716      }
717 }
718
719 static void
720 _del_pre_hook(Evas_Object *obj)
721 {
722    Widget_Data *wd;
723
724    wd = elm_widget_data_get(obj);
725    if (!wd) return;
726
727    _parent_cut_off(obj);
728 }
729
730 static void
731 _del_hook(Evas_Object *obj)
732 {
733    Widget_Data *wd;
734
735    wd = elm_widget_data_get(obj);
736    if (!wd) return;
737
738    elm_ctxpopup_clear(obj);
739    evas_object_del(wd->arrow);
740    evas_object_del(wd->base);
741    free(wd);
742 }
743
744 //FIXME: lost the content size when theme hook is called.
745 static void
746 _theme_hook(Evas_Object *obj)
747 {
748    Widget_Data *wd;
749    Eina_List *elist;
750    Elm_Ctxpopup_Item *item;
751    Eina_Bool rtl;
752
753    wd = elm_widget_data_get(obj);
754    if (!wd) return;
755
756    _elm_widget_mirrored_reload(obj);
757    rtl = elm_widget_mirrored_get(obj);
758
759    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg",
760                          elm_widget_style_get(obj));
761    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base",
762                          elm_widget_style_get(obj));
763    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow",
764                          elm_widget_style_get(obj));
765
766    //Items
767    EINA_LIST_FOREACH(wd->items, elist, item)
768      {
769         edje_object_mirrored_set(VIEW(item), rtl);
770
771         if (item->label && item->icon)
772           _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
773                                 "icon_text_style_item",
774                                 elm_widget_style_get(obj));
775         else if (item->label)
776           _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "text_style_item",
777                                 elm_widget_style_get(obj));
778         else if (item->icon)
779           _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "icon_style_item",
780                                 elm_widget_style_get(obj));
781         if (item->label)
782           edje_object_part_text_set(VIEW(item), "elm.text", item->label);
783
784         if (elm_widget_item_disabled_get(item))
785           edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
786
787         edje_object_message_signal_process(VIEW(item));
788      }
789
790    if (wd->scr)
791      {
792         if (!strncmp(elm_object_style_get(obj), "default", strlen("default")))
793            elm_object_style_set(wd->scr, "ctxpopup");
794         else
795            elm_object_style_set(wd->scr, elm_object_style_get(obj));
796      }
797
798    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
799
800    if (wd->visible)
801      {
802         _scroller_size_reset(wd);
803         _sizing_eval(obj);
804      }
805 }
806
807 static void
808 _content_set_hook(Evas_Object *obj, const char *part,
809                   Evas_Object *content)
810 {
811    ELM_CHECK_WIDTYPE(obj, widtype);
812    Evas_Coord min_w = -1, min_h = -1;
813
814    Widget_Data *wd;
815
816    if (part && strcmp(part, "default")) return;
817
818    wd = elm_widget_data_get(obj);
819    if ((!wd) || (!content)) return;
820
821    if (wd->items) elm_ctxpopup_clear(obj);
822    if (wd->content) evas_object_del(wd->content);
823
824    //Use Box
825    wd->box = elm_box_add(obj);
826    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
827                                     EVAS_HINT_EXPAND);
828    evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND,
829                                     EVAS_HINT_EXPAND);
830    evas_object_size_hint_fill_set(content, EVAS_HINT_FILL,
831                                   EVAS_HINT_FILL);
832    evas_object_show(content);
833    evas_object_size_hint_min_get(content, &min_w, &min_h);
834    evas_object_size_hint_min_set(wd->box, min_w, min_h);
835    elm_box_pack_end(wd->box, content);
836
837    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_RESIZE,
838                                   _content_resize, obj);
839    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_DEL,
840                                   _content_del, obj);
841
842    elm_widget_sub_object_add(obj, wd->box);
843    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->box);
844
845    wd->content = content;
846    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
847
848    if (wd->visible)
849      _sizing_eval(obj);
850 }
851
852 static Evas_Object *
853 _content_unset_hook(Evas_Object *obj, const char *part)
854 {
855    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
856
857    Widget_Data *wd;
858    Evas_Object *content;
859    if (part && strcmp(part, "default")) return NULL;
860    wd = elm_widget_data_get(obj);
861    if (!wd) return NULL;
862
863    content = wd->content;
864    if (!content || !wd->box) return NULL;
865
866    edje_object_part_unswallow(wd->base, wd->box);
867    elm_widget_sub_object_del(obj, wd->box);
868    evas_object_event_callback_del(wd->box, EVAS_CALLBACK_DEL, _content_del);
869    edje_object_signal_emit(wd->base, "elm,state,content,disable", "elm");
870
871    evas_object_del(wd->box);
872    wd->box = NULL;
873    wd->content = NULL;
874    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
875
876    return content;
877 }
878
879 static Evas_Object *
880 _content_get_hook(const Evas_Object *obj, const char *part)
881 {
882    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
883    Widget_Data *wd;
884    if (part && strcmp(part, "default")) return NULL;
885    wd = elm_widget_data_get(obj);
886    if (!wd) return NULL;
887    return wd->content;
888 }
889
890 static void
891 _item_text_set_hook(Elm_Object_Item *it,
892                     const char *part,
893                     const char *label)
894 {
895    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
896
897    Widget_Data *wd;
898    Elm_Ctxpopup_Item *ctxpopup_it;
899
900    if (part && strcmp(part, "default")) return;
901
902    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
903
904    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
905    if (!wd) return;
906
907    _item_label_set(ctxpopup_it, label);
908    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
909
910    if (wd->visible)
911      {
912         _scroller_size_reset(wd);
913         _sizing_eval(WIDGET(ctxpopup_it));
914      }
915 }
916
917 static const char *
918 _item_text_get_hook(const Elm_Object_Item *it, const char *part)
919 {
920    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
921    Elm_Ctxpopup_Item *ctxpopup_it;
922    if (part && strcmp(part, "default")) return NULL;
923    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
924    return ctxpopup_it->label;
925 }
926
927 static void
928 _item_content_set_hook(Elm_Object_Item *it,
929                        const char *part,
930                        Evas_Object *content)
931 {
932    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
933    Widget_Data *wd;
934    Elm_Ctxpopup_Item *ctxpopup_it;
935
936    if (part && strcmp(part, "icon")) return;
937
938    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
939
940    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
941    if (!wd) return;
942
943    _item_icon_set(ctxpopup_it, content);
944    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
945
946    if (wd->visible)
947      {
948         _scroller_size_reset(wd);
949         _sizing_eval(WIDGET(ctxpopup_it));
950      }
951 }
952
953 static Evas_Object *
954 _item_content_get_hook(const Elm_Object_Item *it, const char *part)
955 {
956    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
957    Elm_Ctxpopup_Item *ctxpopup_it;
958    if (part && strcmp(part, "icon")) return NULL;
959    ctxpopup_it  = (Elm_Ctxpopup_Item *) it;
960    return ctxpopup_it->icon;
961 }
962
963 static void
964 _item_disable_set_hook(Elm_Object_Item *it)
965 {
966    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
967
968    Widget_Data *wd;
969    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
970
971    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
972    if (!wd) return;
973
974    if (elm_widget_item_disabled_get(it))
975      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,disabled", "elm");
976    else
977      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,enabled", "elm");
978 }
979
980 static void
981 _item_signal_emit_hook(Elm_Object_Item *it,
982                        const char *emission,
983                        const char *source)
984 {
985    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
986    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
987    edje_object_signal_emit(VIEW(ctxpopup_it), emission, source);
988 }
989
990 static void
991 _bg_clicked_cb(void *data, Evas_Object *obj __UNUSED__,
992                const char *emission __UNUSED__, const char *source __UNUSED__)
993 {
994    evas_object_hide(data);
995 }
996
997 static void
998 _ctxpopup_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
999                void *event_info __UNUSED__)
1000 {
1001    Widget_Data *wd;
1002
1003    wd = elm_widget_data_get(obj);
1004    if (!wd) return;
1005
1006    if ((!wd->items) && (!wd->content)) return;
1007
1008    wd->visible = EINA_TRUE;
1009
1010    evas_object_show(wd->bg);
1011    evas_object_show(wd->base);
1012    evas_object_show(wd->arrow);
1013
1014    edje_object_signal_emit(wd->bg, "elm,state,show", "elm");
1015    edje_object_signal_emit(wd->base, "elm,state,show", "elm");
1016
1017    _sizing_eval(obj);
1018
1019    elm_object_focus_set(obj, EINA_TRUE);
1020 }
1021
1022 static void
1023 _hide(Evas_Object *obj)
1024 {
1025    Widget_Data *wd = elm_widget_data_get(obj);
1026
1027    if ((!wd) || (!wd->visible)) return;
1028
1029    evas_object_hide(wd->bg);
1030    evas_object_hide(wd->arrow);
1031    evas_object_hide(wd->base);
1032
1033    _scroller_size_reset(wd);
1034
1035    evas_object_smart_callback_call(obj, SIG_DISMISSED, NULL);
1036    wd->visible = EINA_FALSE;
1037 }
1038
1039 static void
1040 _ctxpopup_hide(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1041                void *event_info __UNUSED__)
1042 {
1043    _hide(obj);
1044 }
1045
1046 static void
1047 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1048                 void *event_info __UNUSED__)
1049 {
1050    Widget_Data *wd;
1051
1052    wd = elm_widget_data_get(data);
1053    if (!wd) return;
1054
1055    elm_box_recalculate(wd->box);
1056    _sizing_eval(data);
1057 }
1058
1059 static void
1060 _scroller_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
1061                  void *event_info __UNUSED__)
1062 {
1063    Widget_Data *wd;
1064    Evas_Coord w, h;
1065
1066    wd = elm_widget_data_get(data);
1067    if (!wd) return;
1068    if (!wd->visible) return;
1069    if (wd->finished) return;
1070
1071    evas_object_geometry_get(obj, 0, 0, &w, &h);
1072
1073    if (w != 0 && h != 0)
1074      {
1075         if ((w <= wd->max_sc_w) && (h <= wd->max_sc_h))
1076           {
1077              _sizing_eval(data);
1078              wd->finished = EINA_TRUE;
1079              return;
1080           }
1081      }
1082
1083    if (wd->max_sc_w < w)
1084      wd->max_sc_w = w;
1085    if (wd->max_sc_h < h)
1086      wd->max_sc_h = h;
1087
1088    _sizing_eval(data);
1089 }
1090
1091 static void
1092 _ctxpopup_move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1093                void *event_info __UNUSED__)
1094 {
1095    Widget_Data *wd;
1096
1097    wd = elm_widget_data_get(obj);
1098
1099    if (!wd) return;
1100
1101    if (wd->visible)
1102      evas_object_show(wd->arrow);
1103
1104    _scroller_size_reset(wd);
1105    _sizing_eval(obj);
1106 }
1107
1108 static void
1109 _item_select_cb(void *data, Evas_Object *obj __UNUSED__,
1110                 const char *emission __UNUSED__, const char *source __UNUSED__)
1111 {
1112    Elm_Ctxpopup_Item *item = data;
1113
1114    if (!item) return;
1115    if (elm_widget_item_disabled_get(item)) return;
1116
1117    if (item->func)
1118      item->func((void*) item->base.data, WIDGET(item), data);
1119 }
1120
1121 static void
1122 _item_icon_set(Elm_Ctxpopup_Item *item, Evas_Object *icon)
1123 {
1124    if (item->icon)
1125      evas_object_del(item->icon);
1126
1127    item->icon = icon;
1128    if (!icon) return;
1129
1130    edje_object_part_swallow(VIEW(item), "elm.swallow.icon", item->icon);
1131    edje_object_message_signal_process(VIEW(item));
1132 }
1133
1134 static void
1135 _item_label_set(Elm_Ctxpopup_Item *item, const char *label)
1136 {
1137    if (!eina_stringshare_replace(&item->label, label))
1138      return;
1139
1140    edje_object_part_text_set(VIEW(item), "elm.text", label);
1141    edje_object_message_signal_process(VIEW(item));
1142 }
1143
1144 static void
1145 _item_new(Elm_Ctxpopup_Item *item, char *group_name)
1146 {
1147    Widget_Data *wd;
1148
1149    wd = elm_widget_data_get(WIDGET(item));
1150    if (!wd) return;
1151
1152    VIEW(item) = edje_object_add(evas_object_evas_get(wd->base));
1153    edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
1154    _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", group_name,
1155                          elm_widget_style_get(WIDGET(item)));
1156    edje_object_signal_callback_add(VIEW(item), "elm,action,click", "",
1157                                    _item_select_cb, item);
1158    evas_object_size_hint_align_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
1159    evas_object_show(VIEW(item));
1160 }
1161
1162 static void
1163 _content_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1164              void *event_info __UNUSED__)
1165 {
1166    elm_object_content_unset(data);
1167 }
1168
1169 static void
1170 _list_del(Widget_Data *wd)
1171 {
1172    if (!wd->scr) return;
1173
1174    edje_object_part_unswallow(wd->base, wd->scr);
1175    evas_object_del(wd->scr);
1176    wd->scr = NULL;
1177    wd->box = NULL;
1178 }
1179
1180 static void
1181 _list_new(Evas_Object *obj)
1182 {
1183    Widget_Data *wd;
1184    wd = elm_widget_data_get(obj);
1185    if (!wd) return;
1186
1187    //scroller
1188    wd->scr = elm_scroller_add(obj);
1189    elm_object_style_set(wd->scr, "ctxpopup");
1190    evas_object_size_hint_align_set(wd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
1191    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE,
1192                                   _scroller_resize, obj);
1193    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->scr);
1194
1195    //box
1196    wd->box = elm_box_add(obj);
1197    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
1198                                     EVAS_HINT_EXPAND);
1199
1200    elm_object_content_set(wd->scr, wd->box);
1201    elm_ctxpopup_horizontal_set(obj, wd->horizontal);
1202 }
1203
1204 static void
1205 _remove_items(Widget_Data *wd)
1206 {
1207    Eina_List *elist;
1208    Elm_Ctxpopup_Item *item;
1209
1210    if (!wd->items) return;
1211
1212    EINA_LIST_FOREACH(wd->items, elist, item)
1213      {
1214         if (item->label)
1215           eina_stringshare_del(item->label);
1216         if (item->icon)
1217           evas_object_del(item->icon);
1218         wd->items = eina_list_remove(wd->items, item);
1219         free(item);
1220      }
1221
1222    wd->items = NULL;
1223 }
1224
1225 EAPI Evas_Object *
1226 elm_ctxpopup_add(Evas_Object *parent)
1227 {
1228    Evas_Object *obj;
1229    Evas *e;
1230    Widget_Data *wd;
1231
1232    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1233
1234    ELM_SET_WIDTYPE(widtype, "ctxpopup");
1235    elm_widget_type_set(obj, "ctxpopup");
1236    elm_widget_data_set(obj, wd);
1237    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1238    elm_widget_del_hook_set(obj, _del_hook);
1239    elm_widget_theme_hook_set(obj, _theme_hook);
1240    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1241    elm_widget_can_focus_set(obj, EINA_TRUE);
1242    elm_widget_event_hook_set(obj, _event_hook);
1243    elm_widget_content_set_hook_set(obj, _content_set_hook);
1244    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
1245    elm_widget_content_get_hook_set(obj, _content_get_hook);
1246
1247    //Background
1248    wd->bg = edje_object_add(e);
1249    elm_widget_sub_object_add(obj, wd->bg);
1250    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg", "default");
1251    edje_object_signal_callback_add(wd->bg,
1252                                    "elm,action,click",
1253                                    "",
1254                                    _bg_clicked_cb,
1255                                     obj);
1256    //Base
1257    wd->base = edje_object_add(e);
1258    elm_widget_sub_object_add(obj, wd->base);
1259    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base", "default");
1260
1261    //Arrow
1262    wd->arrow = edje_object_add(e);
1263    elm_widget_sub_object_add(obj, wd->arrow);
1264    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow", "default");
1265
1266    wd->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1267    wd->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1268    wd->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1269    wd->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1270    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1271
1272    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _ctxpopup_show,
1273                                   NULL);
1274    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _ctxpopup_hide,
1275                                   NULL);
1276    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _ctxpopup_move,
1277                                   NULL);
1278    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1279    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1280    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1281    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1282
1283    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1284
1285    //default parent is to be hover parent
1286    elm_ctxpopup_hover_parent_set(obj, parent);
1287
1288    return obj;
1289 }
1290
1291 EAPI Evas_Object *
1292 elm_ctxpopup_item_icon_get(const Elm_Object_Item *it)
1293 {
1294    return _item_content_get_hook(it, "icon");
1295 }
1296
1297 EAPI void
1298 elm_ctxpopup_item_icon_set(Elm_Object_Item *it, Evas_Object *icon)
1299 {
1300    _item_content_set_hook(it, "icon", icon);
1301 }
1302
1303 EAPI const char *
1304 elm_ctxpopup_item_label_get(const Elm_Object_Item *it)
1305 {
1306    return _item_text_get_hook(it, NULL);
1307 }
1308
1309 EAPI void
1310 elm_ctxpopup_item_label_set(Elm_Object_Item *it, const char *label)
1311 {
1312    _item_text_set_hook(it, NULL, label);
1313 }
1314
1315 EAPI void
1316 elm_ctxpopup_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
1317 {
1318    ELM_CHECK_WIDTYPE(obj, widtype);
1319
1320    Widget_Data *wd;
1321    Evas_Coord x, y, w, h;
1322
1323    wd = elm_widget_data_get(obj);
1324    if ((!wd) || (!parent)) return;
1325
1326    _parent_cut_off(obj);
1327
1328    if (parent)
1329      {
1330         evas_object_event_callback_add(parent,
1331                                        EVAS_CALLBACK_DEL,
1332                                        _parent_del,
1333                                        obj);
1334         evas_object_event_callback_add(parent,
1335                                        EVAS_CALLBACK_MOVE,
1336                                        _parent_move,
1337                                        obj);
1338         evas_object_event_callback_add(parent,
1339                                        EVAS_CALLBACK_RESIZE,
1340                                        _parent_resize,
1341                                        obj);
1342      }
1343
1344    elm_widget_sub_object_add(parent, obj);
1345    wd->parent = parent;
1346
1347    //Update Background
1348    evas_object_geometry_get(parent, &x, &y, &w, &h);
1349    evas_object_move(wd->bg, x, y);
1350    evas_object_resize(wd->bg, w, h);
1351
1352    if (wd->visible) _sizing_eval(obj);
1353 }
1354
1355 EAPI Evas_Object *
1356 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1357 {
1358    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1359
1360    Widget_Data *wd;
1361
1362    wd = elm_widget_data_get(obj);
1363    if (!wd) return NULL;
1364
1365    return wd->parent;
1366 }
1367
1368 EAPI void
1369 elm_ctxpopup_clear(Evas_Object * obj)
1370 {
1371    ELM_CHECK_WIDTYPE(obj, widtype);
1372
1373    Widget_Data *wd = elm_widget_data_get(obj);
1374    if (!wd) return;
1375
1376    _remove_items(wd);
1377    _list_del(wd);
1378    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1379 }
1380
1381 EAPI void
1382 elm_ctxpopup_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1383 {
1384    ELM_CHECK_WIDTYPE(obj, widtype);
1385
1386    Widget_Data *wd;
1387
1388    wd = elm_widget_data_get(obj);
1389    if (!wd) return;
1390
1391    wd->horizontal = !!horizontal;
1392
1393    if ((!wd->scr) && (!wd->box))
1394       return;
1395
1396    if (!horizontal)
1397      {
1398         elm_box_horizontal_set(wd->box, EINA_FALSE);
1399         elm_scroller_bounce_set(wd->scr, EINA_FALSE, EINA_TRUE);
1400      }
1401    else
1402      {
1403         elm_box_horizontal_set(wd->box, EINA_TRUE);
1404         elm_scroller_bounce_set(wd->scr, EINA_TRUE, EINA_FALSE);
1405      }
1406
1407    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1408
1409    if (wd->visible)
1410       _sizing_eval(obj);
1411 }
1412
1413 EAPI Eina_Bool
1414 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
1415 {
1416    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1417
1418    Widget_Data *wd;
1419
1420    wd = elm_widget_data_get(obj);
1421    if (!wd) return EINA_FALSE;
1422
1423    return wd->horizontal;
1424 }
1425
1426 EAPI Elm_Object_Item *
1427 elm_ctxpopup_item_append(Evas_Object *obj, const char *label,
1428                          Evas_Object *icon, Evas_Smart_Cb func,
1429                          const void *data)
1430 {
1431    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1432
1433    Widget_Data *wd;
1434    Evas_Object *content;
1435    Elm_Ctxpopup_Item *item;
1436
1437    wd = elm_widget_data_get(obj);
1438    if (!wd) return NULL;
1439
1440    item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
1441    if (!item) return NULL;
1442
1443    elm_widget_item_disable_set_hook_set(item, _item_disable_set_hook);
1444    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
1445    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
1446    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
1447    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
1448    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
1449
1450    //The first item is appended.
1451    content = elm_object_content_unset(obj);
1452    if (content) evas_object_del(content);
1453
1454    if (!wd->items)
1455      _list_new(obj);
1456
1457    item->func = func;
1458    item->base.data = data;
1459
1460    if (icon && label)
1461      _item_new(item, "icon_text_style_item");
1462    else if (label)
1463      _item_new(item, "text_style_item");
1464    else
1465      _item_new(item, "icon_style_item");
1466
1467    _item_icon_set(item, icon);
1468    _item_label_set(item, label);
1469    elm_box_pack_end(wd->box, VIEW(item));
1470    wd->items = eina_list_append(wd->items, item);
1471    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1472
1473    if (wd->visible)
1474      {
1475         _scroller_size_reset(wd);
1476         _sizing_eval(obj);
1477      }
1478
1479    return (Elm_Object_Item *) item;
1480 }
1481
1482 EAPI void
1483 elm_ctxpopup_item_del(Elm_Object_Item *it)
1484 {
1485    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1486
1487    Widget_Data *wd;
1488    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
1489
1490    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
1491    if (!wd) return;
1492
1493    if (ctxpopup_it->icon)
1494      evas_object_del(ctxpopup_it->icon);
1495    if (VIEW(ctxpopup_it))
1496      evas_object_del(VIEW(ctxpopup_it));
1497
1498    eina_stringshare_del(ctxpopup_it->label);
1499
1500    wd->items = eina_list_remove(wd->items, ctxpopup_it);
1501
1502    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1503
1504    elm_widget_item_del(ctxpopup_it);
1505
1506    if (eina_list_count(wd->items) < 1)
1507      {
1508         evas_object_hide(WIDGET(ctxpopup_it));
1509         return;
1510      }
1511
1512    if (wd->visible)
1513      _sizing_eval(WIDGET(ctxpopup_it));
1514
1515 }
1516
1517 EAPI void
1518 elm_ctxpopup_item_disabled_set(Elm_Object_Item *it, Eina_Bool disabled)
1519 {
1520    elm_object_item_disabled_set(it, disabled);
1521 }
1522
1523 EAPI Eina_Bool
1524 elm_ctxpopup_item_disabled_get(const Elm_Object_Item *it)
1525 {
1526    return elm_object_item_disabled_get(it);
1527 }
1528
1529 EAPI void
1530 elm_ctxpopup_content_set(Evas_Object *obj, Evas_Object *content)
1531 {
1532    elm_object_content_set(obj, content);
1533 }
1534
1535 EAPI Evas_Object *
1536 elm_ctxpopup_content_unset(Evas_Object *obj)
1537 {
1538    return elm_object_content_unset(obj);
1539 }
1540
1541 EAPI void
1542 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
1543                                     Elm_Ctxpopup_Direction first,
1544                                     Elm_Ctxpopup_Direction second,
1545                                     Elm_Ctxpopup_Direction third,
1546                                     Elm_Ctxpopup_Direction fourth)
1547 {
1548    ELM_CHECK_WIDTYPE(obj, widtype);
1549    Widget_Data *wd;
1550
1551    wd = elm_widget_data_get(obj);
1552    if (!wd) return;
1553
1554    wd->dir_priority[0] = first;
1555    wd->dir_priority[1] = second;
1556    wd->dir_priority[2] = third;
1557    wd->dir_priority[3] = fourth;
1558
1559    if (wd->visible)
1560      _sizing_eval(obj);
1561 }
1562
1563 EAPI void
1564 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
1565                                     Elm_Ctxpopup_Direction *first,
1566                                     Elm_Ctxpopup_Direction *second,
1567                                     Elm_Ctxpopup_Direction *third,
1568                                     Elm_Ctxpopup_Direction *fourth)
1569 {
1570    ELM_CHECK_WIDTYPE(obj, widtype);
1571    Widget_Data *wd;
1572
1573    wd = elm_widget_data_get(obj);
1574    if (!wd) return;
1575
1576    if (first) *first = wd->dir_priority[0];
1577    if (second) *second = wd->dir_priority[1];
1578    if (third) *third = wd->dir_priority[2];
1579    if (fourth) *fourth = wd->dir_priority[3];
1580 }
1581
1582 EAPI Elm_Ctxpopup_Direction
1583 elm_ctxpopup_direction_get(const Evas_Object *obj)
1584 {
1585    ELM_CHECK_WIDTYPE(obj, widtype) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1586    Widget_Data *wd;
1587
1588    wd = elm_widget_data_get(obj);
1589    if (!wd) return ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1590    return wd->dir;
1591 }