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