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