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