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