Elm ctxpopup: remove useless code until we actually support mirroring.
[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 _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
742    wd = elm_widget_data_get(obj);
743    if (!wd) return;
744
745    _elm_widget_mirrored_reload(obj);
746
747    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg",
748                          elm_widget_style_get(obj));
749    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base",
750                          elm_widget_style_get(obj));
751    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow",
752                          elm_widget_style_get(obj));
753
754    if (wd->list)
755      {
756         if (!strncmp(elm_object_style_get(obj), "default", strlen("default")))
757            elm_object_style_set(wd->list, "ctxpopup");
758         else
759            elm_object_style_set(wd->list, elm_object_style_get(obj));
760      }
761
762    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
763
764    if (wd->visible)
765      {
766         _sizing_eval(obj);
767      }
768 }
769
770 static void
771 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
772 {
773    ELM_CHECK_WIDTYPE(obj, widtype);
774    Evas_Coord min_w = -1, min_h = -1;
775    Widget_Data *wd;
776    if ((part) && (strcmp(part, "default"))) return;
777    wd = elm_widget_data_get(obj);
778    if ((!wd) || (!content)) return;
779    if (content == wd->content) return;
780
781    //TODO: wd->list
782    if (wd->content) evas_object_del(wd->content);
783
784    //Use Box
785    wd->box = elm_box_add(obj);
786    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
787                                     EVAS_HINT_EXPAND);
788    evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND,
789                                     EVAS_HINT_EXPAND);
790    evas_object_size_hint_fill_set(content, EVAS_HINT_FILL,
791                                   EVAS_HINT_FILL);
792    evas_object_show(content);
793    evas_object_size_hint_min_get(content, &min_w, &min_h);
794    evas_object_size_hint_min_set(wd->box, min_w, min_h);
795    elm_box_pack_end(wd->box, content);
796
797    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_RESIZE,
798                                   _content_resize, obj);
799    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_DEL,
800                                   _content_del, obj);
801
802    elm_widget_sub_object_add(obj, wd->box);
803    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->box);
804
805    wd->content = content;
806    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
807
808    if (wd->visible)
809      _sizing_eval(obj);
810 }
811
812 static Evas_Object *
813 _content_unset_hook(Evas_Object *obj, const char *part)
814 {
815    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
816
817    Widget_Data *wd;
818    Evas_Object *content;
819    if ((part) && (strcmp(part, "default"))) return NULL;
820    wd = elm_widget_data_get(obj);
821    if (!wd) return NULL;
822
823    content = wd->content;
824    if ((!content) || (!wd->box)) return NULL;
825
826    edje_object_part_unswallow(wd->base, wd->box);
827    elm_widget_sub_object_del(obj, wd->box);
828    evas_object_event_callback_del(wd->box, EVAS_CALLBACK_DEL, _content_del);
829    edje_object_signal_emit(wd->base, "elm,state,content,disable", "elm");
830
831    evas_object_del(wd->box);
832    wd->box = NULL;
833    wd->content = NULL;
834    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
835
836    return content;
837 }
838
839 static Evas_Object *
840 _content_get_hook(const Evas_Object *obj, const char *part)
841 {
842    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
843    Widget_Data *wd;
844    if ((part) && (strcmp(part, "default"))) return NULL;
845    wd = elm_widget_data_get(obj);
846    if (!wd) return NULL;
847    return wd->content;
848 }
849
850 static void
851 _item_text_set_hook(Elm_Object_Item *it, const char *part, const char *label)
852 {
853    Widget_Data *wd;
854    Elm_Ctxpopup_Item *ctxpopup_it;
855
856    if ((part) && (strcmp(part, "default"))) return;
857
858    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
859
860    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
861    if (!wd) return;
862
863    elm_object_item_part_text_set(ctxpopup_it->list_item, "default", label);
864    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
865
866    if (wd->visible)
867      {
868         _sizing_eval(WIDGET(ctxpopup_it));
869      }
870 }
871
872 static const char *
873 _item_text_get_hook(const Elm_Object_Item *it, const char *part)
874 {
875    Elm_Ctxpopup_Item *ctxpopup_it;
876    if (part && strcmp(part, "default")) return NULL;
877    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
878    return elm_object_item_part_text_get(ctxpopup_it->list_item, "default");
879 }
880
881 static void
882 _item_content_set_hook(Elm_Object_Item *it,
883                        const char *part,
884                        Evas_Object *content)
885 {
886    Widget_Data *wd;
887    Elm_Ctxpopup_Item *ctxpopup_it;
888
889    if ((part) && (strcmp(part, "icon"))
890        && (strcmp(part, "start"))
891        && (strcmp(part, "end"))) return;
892
893    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
894
895    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
896    if (!wd) return;
897
898    if ((part) && (!strcmp(part, "end")))
899       elm_object_item_part_content_set(ctxpopup_it->list_item, "end", content);
900    else
901       elm_object_item_part_content_set(ctxpopup_it->list_item, "start", content);
902
903    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
904
905    if (wd->visible)
906      {
907         _sizing_eval(WIDGET(ctxpopup_it));
908      }
909 }
910
911 static Evas_Object *
912 _item_content_get_hook(const Elm_Object_Item *it, const char *part)
913 {
914    Elm_Ctxpopup_Item *ctxpopup_it;
915
916    if (part && strcmp(part, "icon") && strcmp(part, "start")
917        && strcmp(part, "end")) return NULL;
918
919    ctxpopup_it  = (Elm_Ctxpopup_Item *)it;
920
921    if (part && !strcmp(part, "end"))
922       return elm_object_item_part_content_get(ctxpopup_it->list_item, "end");
923    else
924       return elm_object_item_part_content_get(ctxpopup_it->list_item, "start");
925 }
926
927 static void
928 _item_disable_hook(Elm_Object_Item *it)
929 {
930    Widget_Data *wd;
931    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
932
933    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
934    if (!wd) return;
935
936    elm_object_item_disabled_set(ctxpopup_it->list_item,
937                                 elm_widget_item_disabled_get(ctxpopup_it));
938 }
939
940 static void
941 _item_signal_emit_hook(Elm_Object_Item *it, const char *emission,
942                        const char *source)
943 {
944    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
945    elm_object_item_signal_emit(ctxpopup_it->list_item, emission, source);
946 }
947
948 static void
949 _bg_clicked_cb(void *data, Evas_Object *obj __UNUSED__,
950                const char *emission __UNUSED__, const char *source __UNUSED__)
951 {
952    Widget_Data *wd = elm_widget_data_get(data);
953    if (!wd) return;
954    _hide_signal_emit(data, wd->dir);
955 }
956
957 static void
958 _ctxpopup_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
959                void *event_info __UNUSED__)
960 {
961    Widget_Data *wd;
962
963    wd = elm_widget_data_get(obj);
964    if (!wd) return;
965
966    if ((!wd->list) && (!wd->content)) return;
967
968    if (wd->list)
969      {
970         elm_list_go(wd->list);
971         wd->visible = EINA_TRUE;
972         return;
973      }
974
975    wd->visible = EINA_TRUE;
976
977    evas_object_show(wd->bg);
978    evas_object_show(wd->base);
979    evas_object_show(wd->arrow);
980
981    edje_object_signal_emit(wd->bg, "elm,state,show", "elm");
982    edje_object_signal_emit(wd->base, "elm,state,show", "elm");
983
984    _sizing_eval(obj);
985
986    elm_object_focus_set(obj, EINA_TRUE);
987 }
988
989 static void
990 _hide_finished(void *data, Evas_Object *obj __UNUSED__,
991                const char *emission __UNUSED__, const char *source __UNUSED__)
992 {
993    evas_object_hide(data);
994    evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
995 }
996
997 static void
998 _ctxpopup_hide(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
999                void *event_info __UNUSED__)
1000 {
1001    Widget_Data *wd = elm_widget_data_get(obj);
1002    if ((!wd) || (!wd->visible)) return;
1003
1004    evas_object_hide(wd->bg);
1005    evas_object_hide(wd->arrow);
1006    evas_object_hide(wd->base);
1007
1008    wd->visible = EINA_FALSE;
1009    wd->list_visible = EINA_FALSE;
1010 }
1011
1012 static void
1013 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1014                 void *event_info __UNUSED__)
1015 {
1016    Widget_Data *wd = elm_widget_data_get(data);
1017    if (!wd) return;
1018    elm_box_recalculate(wd->box);
1019    _sizing_eval(data);
1020 }
1021
1022 static void
1023 _list_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
1024                  void *event_info __UNUSED__)
1025 {
1026    Widget_Data *wd = elm_widget_data_get(data);
1027    if (!wd) return;
1028    if (!wd->visible) return;
1029    if (wd->list_visible) return;
1030
1031    wd->list_visible = EINA_TRUE;
1032
1033    evas_object_show(wd->bg);
1034    evas_object_show(wd->base);
1035    evas_object_show(wd->arrow);
1036    _sizing_eval(obj);
1037 }
1038
1039 static void
1040 _ctxpopup_move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1041                void *event_info __UNUSED__)
1042 {
1043    Widget_Data *wd;
1044
1045    wd = elm_widget_data_get(obj);
1046
1047    if (!wd) return;
1048
1049    if (wd->visible)
1050      evas_object_show(wd->arrow);
1051
1052    _sizing_eval(obj);
1053 }
1054
1055 static void
1056 _restack(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1057 {
1058    Widget_Data *wd = elm_widget_data_get(obj);
1059    if (!wd) return;
1060    evas_object_layer_set(wd->bg,
1061                          evas_object_layer_get(obj));
1062    evas_object_layer_set(wd->base,
1063                          evas_object_layer_get(obj));
1064 }
1065
1066 static void
1067 _content_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1068              void *event_info __UNUSED__)
1069 {
1070    elm_object_content_unset(data);
1071 }
1072
1073 static void
1074 _list_del(Widget_Data *wd)
1075 {
1076    if (!wd->list) return;
1077
1078    edje_object_part_unswallow(wd->base, wd->box);
1079    elm_box_unpack(wd->box, wd->list);
1080    evas_object_del(wd->list);
1081    wd->list = NULL;
1082    wd->box = NULL;
1083 }
1084
1085 static Eina_Bool
1086 _item_del_pre_hook(Elm_Object_Item *it)
1087 {
1088    Evas_Object *list;
1089    Widget_Data *wd;
1090    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1091
1092    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
1093    if (!wd) return EINA_FALSE;
1094
1095    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1096
1097    list = elm_object_item_widget_get(ctxpopup_it->list_item);
1098
1099    if (eina_list_count(elm_list_items_get(list)) < 2)
1100      {
1101         elm_object_item_del(ctxpopup_it->list_item);
1102         evas_object_hide(WIDGET(ctxpopup_it));
1103         return EINA_TRUE;
1104      }
1105
1106    elm_object_item_del(ctxpopup_it->list_item);
1107    if (wd->list_visible)
1108      _sizing_eval(WIDGET(ctxpopup_it));
1109
1110    return EINA_TRUE;
1111 }
1112
1113 static void
1114 _disable_hook(Evas_Object *obj)
1115 {
1116    //TODO: elm_object_disabled_set(); does not ignite this part
1117    Widget_Data *wd = elm_widget_data_get(obj);
1118    if (!wd) return;
1119
1120    elm_object_disabled_set(wd->list, elm_widget_disabled_get(obj));
1121 }
1122
1123 static void
1124 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
1125 {
1126    Widget_Data *wd = elm_widget_data_get(obj);
1127    if (!wd) return;
1128    edje_object_signal_emit(wd->base, emission, source);
1129 }
1130
1131 static void
1132 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
1133 {
1134    Widget_Data *wd = elm_widget_data_get(obj);
1135    if (!wd) return;
1136    edje_object_signal_callback_add(wd->base, emission, source, func_cb, data);
1137 }
1138
1139 static void
1140 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
1141 {
1142    Widget_Data *wd = elm_widget_data_get(obj);
1143    if (!wd) return;
1144    edje_object_signal_callback_del_full(wd->base, emission, source, func_cb, data);
1145 }
1146
1147 EAPI Evas_Object *
1148 elm_ctxpopup_add(Evas_Object *parent)
1149 {
1150    Evas_Object *obj;
1151    Evas *e;
1152    Widget_Data *wd;
1153
1154    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1155
1156    ELM_SET_WIDTYPE(widtype, "ctxpopup");
1157    elm_widget_type_set(obj, "ctxpopup");
1158    elm_widget_data_set(obj, wd);
1159    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1160    elm_widget_del_hook_set(obj, _del_hook);
1161    elm_widget_theme_hook_set(obj, _theme_hook);
1162    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1163    elm_widget_can_focus_set(obj, EINA_TRUE);
1164    elm_widget_event_hook_set(obj, _event_hook);
1165    elm_widget_content_set_hook_set(obj, _content_set_hook);
1166    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
1167    elm_widget_content_get_hook_set(obj, _content_get_hook);
1168    elm_widget_disable_hook_set(obj, _disable_hook);
1169    elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
1170    elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
1171    elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
1172
1173    //Background
1174    wd->bg = edje_object_add(e);
1175    elm_widget_sub_object_add(obj, wd->bg);
1176    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg", "default");
1177    edje_object_signal_callback_add(wd->bg,
1178                                    "elm,action,click",
1179                                    "",
1180                                    _bg_clicked_cb,
1181                                     obj);
1182    //Base
1183    wd->base = edje_object_add(e);
1184    elm_widget_sub_object_add(obj, wd->base);
1185    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base", "default");
1186    edje_object_signal_callback_add(wd->base, "elm,action,hide,finished", "",
1187                                    _hide_finished, obj);
1188
1189    //Arrow
1190    wd->arrow = edje_object_add(e);
1191    elm_widget_sub_object_add(obj, wd->arrow);
1192    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow", "default");
1193
1194    wd->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1195    wd->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1196    wd->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1197    wd->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1198    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1199
1200    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _ctxpopup_show,
1201                                   NULL);
1202    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _ctxpopup_hide,
1203                                   NULL);
1204    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _ctxpopup_move,
1205                                   NULL);
1206    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESTACK, _restack, obj);
1207    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1208    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1209    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1210    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1211
1212    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1213
1214    //default parent is to be hover parent
1215    elm_ctxpopup_hover_parent_set(obj, parent);
1216
1217    return obj;
1218 }
1219
1220 EAPI void
1221 elm_ctxpopup_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
1222 {
1223    ELM_CHECK_WIDTYPE(obj, widtype);
1224
1225    Widget_Data *wd;
1226    Evas_Coord x, y, w, h;
1227
1228    wd = elm_widget_data_get(obj);
1229    if ((!wd) || (!parent)) return;
1230
1231    _parent_cut_off(obj);
1232
1233    if (parent)
1234      {
1235         evas_object_event_callback_add(parent,
1236                                        EVAS_CALLBACK_DEL,
1237                                        _parent_del,
1238                                        obj);
1239         evas_object_event_callback_add(parent,
1240                                        EVAS_CALLBACK_MOVE,
1241                                        _parent_move,
1242                                        obj);
1243         evas_object_event_callback_add(parent,
1244                                        EVAS_CALLBACK_RESIZE,
1245                                        _parent_resize,
1246                                        obj);
1247      }
1248
1249    elm_widget_sub_object_add(parent, obj);
1250    wd->parent = parent;
1251
1252    //Update Background
1253    evas_object_geometry_get(parent, &x, &y, &w, &h);
1254    evas_object_move(wd->bg, x, y);
1255    evas_object_resize(wd->bg, w, h);
1256
1257    if (wd->visible) _sizing_eval(obj);
1258 }
1259
1260 EAPI Evas_Object *
1261 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1262 {
1263    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1264
1265    Widget_Data *wd;
1266
1267    wd = elm_widget_data_get(obj);
1268    if (!wd) return NULL;
1269
1270    return wd->parent;
1271 }
1272
1273 EAPI void
1274 elm_ctxpopup_clear(Evas_Object * obj)
1275 {
1276    ELM_CHECK_WIDTYPE(obj, widtype);
1277
1278    Widget_Data *wd = elm_widget_data_get(obj);
1279    if (!wd) return;
1280
1281    _list_del(wd);
1282    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1283 }
1284
1285 EAPI void
1286 elm_ctxpopup_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1287 {
1288    ELM_CHECK_WIDTYPE(obj, widtype);
1289
1290    Widget_Data *wd;
1291
1292    wd = elm_widget_data_get(obj);
1293    if (!wd) return;
1294
1295    wd->horizontal = !!horizontal;
1296
1297    if ((!wd->list))
1298       return;
1299
1300    if (!horizontal)
1301      {
1302         elm_list_horizontal_set(wd->list, wd->horizontal);
1303      }
1304    else
1305      {
1306         elm_list_horizontal_set(wd->list, wd->horizontal);
1307      }
1308
1309    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1310
1311    if (wd->visible)
1312       _sizing_eval(obj);
1313 }
1314
1315 EAPI Eina_Bool
1316 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
1317 {
1318    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1319
1320    Widget_Data *wd;
1321
1322    wd = elm_widget_data_get(obj);
1323    if (!wd) return EINA_FALSE;
1324
1325    return wd->horizontal;
1326 }
1327
1328 EAPI Elm_Object_Item *
1329 elm_ctxpopup_item_append(Evas_Object *obj, const char *label,
1330                          Evas_Object *icon, Evas_Smart_Cb func,
1331                          const void *data)
1332 {
1333    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1334
1335    Widget_Data *wd;
1336    Elm_Ctxpopup_Item *item;
1337
1338    wd = elm_widget_data_get(obj);
1339    if (!wd) return NULL;
1340
1341    item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
1342    if (!item) return NULL;
1343
1344    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
1345    elm_widget_item_disable_hook_set(item, _item_disable_hook);
1346    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
1347    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
1348    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
1349    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
1350    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
1351
1352    if (!wd->list)
1353      {
1354         //The first item is appended.
1355         wd->list = elm_list_add(obj);
1356         elm_list_mode_set(wd->list, ELM_LIST_EXPAND);
1357         elm_list_horizontal_set(wd->list, wd->horizontal);
1358         evas_object_event_callback_add(wd->list, EVAS_CALLBACK_RESIZE,
1359                                       _list_resize, obj);
1360         _content_set_hook(obj, "default", wd->list);
1361      }
1362
1363    item->list_item = elm_list_item_append(wd->list, label, icon, NULL, func, data);
1364
1365    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1366
1367    if (wd->visible) _sizing_eval(obj);
1368
1369    return (Elm_Object_Item *)item;
1370 }
1371
1372 EAPI void
1373 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
1374                                     Elm_Ctxpopup_Direction first,
1375                                     Elm_Ctxpopup_Direction second,
1376                                     Elm_Ctxpopup_Direction third,
1377                                     Elm_Ctxpopup_Direction fourth)
1378 {
1379    ELM_CHECK_WIDTYPE(obj, widtype);
1380    Widget_Data *wd;
1381
1382    wd = elm_widget_data_get(obj);
1383    if (!wd) return;
1384
1385    wd->dir_priority[0] = first;
1386    wd->dir_priority[1] = second;
1387    wd->dir_priority[2] = third;
1388    wd->dir_priority[3] = fourth;
1389
1390    if (wd->visible)
1391      _sizing_eval(obj);
1392 }
1393
1394 EAPI void
1395 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
1396                                     Elm_Ctxpopup_Direction *first,
1397                                     Elm_Ctxpopup_Direction *second,
1398                                     Elm_Ctxpopup_Direction *third,
1399                                     Elm_Ctxpopup_Direction *fourth)
1400 {
1401    ELM_CHECK_WIDTYPE(obj, widtype);
1402    Widget_Data *wd;
1403
1404    wd = elm_widget_data_get(obj);
1405    if (!wd) return;
1406
1407    if (first) *first = wd->dir_priority[0];
1408    if (second) *second = wd->dir_priority[1];
1409    if (third) *third = wd->dir_priority[2];
1410    if (fourth) *fourth = wd->dir_priority[3];
1411 }
1412
1413 EAPI Elm_Ctxpopup_Direction
1414 elm_ctxpopup_direction_get(const Evas_Object *obj)
1415 {
1416    ELM_CHECK_WIDTYPE(obj, widtype) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1417    Widget_Data *wd;
1418
1419    wd = elm_widget_data_get(obj);
1420    if (!wd) return ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1421    return wd->dir;
1422 }
1423
1424 EAPI void
1425 elm_ctxpopup_dismiss(Evas_Object *obj)
1426 {
1427    ELM_CHECK_WIDTYPE(obj, widtype);
1428    Widget_Data *wd = elm_widget_data_get(obj);
1429    if (!wd) return;
1430    _hide_signal_emit(obj, wd->dir);
1431 }