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