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