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