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