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