elementary/menu, ctxpopup, index, segment_control, diskselector, multibuttonentry...
[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    _parent_cut_off(obj);
733 }
734
735 static void
736 _del_hook(Evas_Object *obj)
737 {
738    Widget_Data *wd;
739
740    wd = elm_widget_data_get(obj);
741    if (!wd) return;
742
743    elm_ctxpopup_clear(obj);
744    evas_object_del(wd->arrow);
745    evas_object_del(wd->base);
746    free(wd);
747 }
748
749 //FIXME: lost the content size when theme hook is called.
750 static void
751 _theme_hook(Evas_Object *obj)
752 {
753    Widget_Data *wd;
754    Eina_List *elist;
755    Elm_Ctxpopup_Item *item;
756    Eina_Bool rtl;
757
758    wd = elm_widget_data_get(obj);
759    if (!wd) return;
760
761    _elm_widget_mirrored_reload(obj);
762    rtl = elm_widget_mirrored_get(obj);
763
764    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg",
765                          elm_widget_style_get(obj));
766    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base",
767                          elm_widget_style_get(obj));
768    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow",
769                          elm_widget_style_get(obj));
770
771    //Items
772    EINA_LIST_FOREACH(wd->items, elist, item)
773      {
774         edje_object_mirrored_set(VIEW(item), rtl);
775
776         if (item->label && item->icon)
777           _elm_theme_object_set(obj, VIEW(item), "ctxpopup",
778                                 "icon_text_style_item",
779                                 elm_widget_style_get(obj));
780         else if (item->label)
781           _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "text_style_item",
782                                 elm_widget_style_get(obj));
783         else if (item->icon)
784           _elm_theme_object_set(obj, VIEW(item), "ctxpopup", "icon_style_item",
785                                 elm_widget_style_get(obj));
786         if (item->label)
787           edje_object_part_text_set(VIEW(item), "elm.text", item->label);
788
789         if (elm_widget_item_disabled_get(item))
790           edje_object_signal_emit(VIEW(item), "elm,state,disabled", "elm");
791
792         edje_object_message_signal_process(VIEW(item));
793      }
794
795    if (wd->scr)
796      {
797         if (!strncmp(elm_object_style_get(obj), "default", strlen("default")))
798            elm_object_style_set(wd->scr, "ctxpopup");
799         else
800            elm_object_style_set(wd->scr, elm_object_style_get(obj));
801      }
802
803    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
804
805    if (wd->visible)
806      {
807         _scroller_size_reset(wd);
808         _sizing_eval(obj);
809      }
810 }
811
812 static void
813 _content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
814 {
815    ELM_CHECK_WIDTYPE(obj, widtype);
816    Evas_Coord min_w = -1, min_h = -1;
817
818    Widget_Data *wd;
819
820    if (part && strcmp(part, "default")) return;
821
822    wd = elm_widget_data_get(obj);
823    if ((!wd) || (!content)) return;
824
825    if (wd->items) elm_ctxpopup_clear(obj);
826    if (wd->content) evas_object_del(wd->content);
827
828    //Use Box
829    wd->box = elm_box_add(obj);
830    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
831                                     EVAS_HINT_EXPAND);
832    evas_object_size_hint_weight_set(content, EVAS_HINT_EXPAND,
833                                     EVAS_HINT_EXPAND);
834    evas_object_size_hint_fill_set(content, EVAS_HINT_FILL,
835                                   EVAS_HINT_FILL);
836    evas_object_show(content);
837    evas_object_size_hint_min_get(content, &min_w, &min_h);
838    evas_object_size_hint_min_set(wd->box, min_w, min_h);
839    elm_box_pack_end(wd->box, content);
840
841    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_RESIZE,
842                                   _content_resize, obj);
843    evas_object_event_callback_add(wd->box, EVAS_CALLBACK_DEL,
844                                   _content_del, obj);
845
846    elm_widget_sub_object_add(obj, wd->box);
847    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->box);
848
849    wd->content = content;
850    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
851
852    if (wd->visible)
853      _sizing_eval(obj);
854 }
855
856 static Evas_Object *
857 _content_unset_hook(Evas_Object *obj, const char *part)
858 {
859    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
860
861    Widget_Data *wd;
862    Evas_Object *content;
863    if (part && strcmp(part, "default")) return NULL;
864    wd = elm_widget_data_get(obj);
865    if (!wd) return NULL;
866
867    content = wd->content;
868    if (!content || !wd->box) return NULL;
869
870    edje_object_part_unswallow(wd->base, wd->box);
871    elm_widget_sub_object_del(obj, wd->box);
872    evas_object_event_callback_del(wd->box, EVAS_CALLBACK_DEL, _content_del);
873    edje_object_signal_emit(wd->base, "elm,state,content,disable", "elm");
874
875    evas_object_del(wd->box);
876    wd->box = NULL;
877    wd->content = NULL;
878    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
879
880    return content;
881 }
882
883 static Evas_Object *
884 _content_get_hook(const Evas_Object *obj, const char *part)
885 {
886    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
887    Widget_Data *wd;
888    if (part && strcmp(part, "default")) return NULL;
889    wd = elm_widget_data_get(obj);
890    if (!wd) return NULL;
891    return wd->content;
892 }
893
894 static void
895 _item_text_set_hook(Elm_Object_Item *it, const char *part, const char *label)
896 {
897    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
898
899    Widget_Data *wd;
900    Elm_Ctxpopup_Item *ctxpopup_it;
901
902    if (part && strcmp(part, "default")) return;
903
904    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
905
906    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
907    if (!wd) return;
908
909    _item_label_set(ctxpopup_it, label);
910    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
911
912    if (wd->visible)
913      {
914         _scroller_size_reset(wd);
915         _sizing_eval(WIDGET(ctxpopup_it));
916      }
917 }
918
919 static const char *
920 _item_text_get_hook(const Elm_Object_Item *it, const char *part)
921 {
922    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
923    Elm_Ctxpopup_Item *ctxpopup_it;
924    if (part && strcmp(part, "default")) return NULL;
925    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
926    return ctxpopup_it->label;
927 }
928
929 static void
930 _item_content_set_hook(Elm_Object_Item *it,
931                        const char *part,
932                        Evas_Object *content)
933 {
934    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
935    Widget_Data *wd;
936    Elm_Ctxpopup_Item *ctxpopup_it;
937
938    if (part && strcmp(part, "icon")) return;
939
940    ctxpopup_it = (Elm_Ctxpopup_Item *) it;
941
942    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
943    if (!wd) return;
944
945    _item_icon_set(ctxpopup_it, content);
946    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
947
948    if (wd->visible)
949      {
950         _scroller_size_reset(wd);
951         _sizing_eval(WIDGET(ctxpopup_it));
952      }
953 }
954
955 static Evas_Object *
956 _item_content_get_hook(const Elm_Object_Item *it, const char *part)
957 {
958    ELM_OBJ_ITEM_CHECK_OR_RETURN(it, NULL);
959    Elm_Ctxpopup_Item *ctxpopup_it;
960    if (part && strcmp(part, "icon")) return NULL;
961    ctxpopup_it  = (Elm_Ctxpopup_Item *) it;
962    return ctxpopup_it->icon;
963 }
964
965 static void
966 _item_disable_hook(Elm_Object_Item *it)
967 {
968    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
969
970    Widget_Data *wd;
971    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
972
973    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
974    if (!wd) return;
975
976    if (elm_widget_item_disabled_get(it))
977      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,disabled", "elm");
978    else
979      edje_object_signal_emit(VIEW(ctxpopup_it), "elm,state,enabled", "elm");
980 }
981
982 static void
983 _item_signal_emit_hook(Elm_Object_Item *it, const char *emission,
984                        const char *source)
985 {
986    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
987    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
988    edje_object_signal_emit(VIEW(ctxpopup_it), emission, source);
989 }
990
991 static void
992 _bg_clicked_cb(void *data, Evas_Object *obj __UNUSED__,
993                const char *emission __UNUSED__, const char *source __UNUSED__)
994 {
995    evas_object_hide(data);
996 }
997
998 static void
999 _ctxpopup_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1000                void *event_info __UNUSED__)
1001 {
1002    Widget_Data *wd;
1003
1004    wd = elm_widget_data_get(obj);
1005    if (!wd) return;
1006
1007    if ((!wd->items) && (!wd->content)) return;
1008
1009    wd->visible = EINA_TRUE;
1010
1011    evas_object_show(wd->bg);
1012    evas_object_show(wd->base);
1013    evas_object_show(wd->arrow);
1014
1015    edje_object_signal_emit(wd->bg, "elm,state,show", "elm");
1016    edje_object_signal_emit(wd->base, "elm,state,show", "elm");
1017
1018    _sizing_eval(obj);
1019
1020    elm_object_focus_set(obj, EINA_TRUE);
1021 }
1022
1023 static void
1024 _hide(Evas_Object *obj)
1025 {
1026    Widget_Data *wd = elm_widget_data_get(obj);
1027
1028    if ((!wd) || (!wd->visible)) return;
1029
1030    evas_object_hide(wd->bg);
1031    evas_object_hide(wd->arrow);
1032    evas_object_hide(wd->base);
1033
1034    _scroller_size_reset(wd);
1035
1036    evas_object_smart_callback_call(obj, SIG_DISMISSED, NULL);
1037    wd->visible = EINA_FALSE;
1038 }
1039
1040 static void
1041 _ctxpopup_hide(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1042                void *event_info __UNUSED__)
1043 {
1044    _hide(obj);
1045 }
1046
1047 static void
1048 _content_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1049                 void *event_info __UNUSED__)
1050 {
1051    Widget_Data *wd = elm_widget_data_get(data);
1052    if (!wd) return;
1053    elm_box_recalculate(wd->box);
1054    _sizing_eval(data);
1055 }
1056
1057 static void
1058 _scroller_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj,
1059                  void *event_info __UNUSED__)
1060 {
1061    Widget_Data *wd;
1062    Evas_Coord w, h;
1063
1064    wd = elm_widget_data_get(data);
1065    if (!wd) return;
1066    if (!wd->visible) return;
1067    if (wd->finished) return;
1068
1069    evas_object_geometry_get(obj, 0, 0, &w, &h);
1070
1071    if (w != 0 && h != 0)
1072      {
1073         if ((w <= wd->max_sc_w) && (h <= wd->max_sc_h))
1074           {
1075              _sizing_eval(data);
1076              wd->finished = EINA_TRUE;
1077              return;
1078           }
1079      }
1080
1081    if (wd->max_sc_w < w)
1082      wd->max_sc_w = w;
1083    if (wd->max_sc_h < h)
1084      wd->max_sc_h = h;
1085
1086    _sizing_eval(data);
1087 }
1088
1089 static void
1090 _ctxpopup_move(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj,
1091                void *event_info __UNUSED__)
1092 {
1093    Widget_Data *wd;
1094
1095    wd = elm_widget_data_get(obj);
1096
1097    if (!wd) return;
1098
1099    if (wd->visible)
1100      evas_object_show(wd->arrow);
1101
1102    _scroller_size_reset(wd);
1103    _sizing_eval(obj);
1104 }
1105
1106 static void
1107 _restack(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
1108 {
1109    Widget_Data *wd = elm_widget_data_get(obj);
1110    if (!wd) return;
1111    evas_object_layer_set(wd->bg,
1112                          evas_object_layer_get(obj));
1113    evas_object_layer_set(wd->base,
1114                          evas_object_layer_get(obj));
1115 }
1116
1117 static void
1118 _item_select_cb(void *data, Evas_Object *obj __UNUSED__,
1119                 const char *emission __UNUSED__, const char *source __UNUSED__)
1120 {
1121    Elm_Ctxpopup_Item *item = data;
1122
1123    if (!item) return;
1124    if (elm_widget_item_disabled_get(item)) return;
1125
1126    if (item->func)
1127      item->func((void*) item->base.data, WIDGET(item), data);
1128 }
1129
1130 static void
1131 _item_icon_set(Elm_Ctxpopup_Item *item, Evas_Object *icon)
1132 {
1133    if (item->icon)
1134      evas_object_del(item->icon);
1135
1136    item->icon = icon;
1137    if (!icon) return;
1138
1139    edje_object_part_swallow(VIEW(item), "elm.swallow.icon", item->icon);
1140    edje_object_message_signal_process(VIEW(item));
1141 }
1142
1143 static void
1144 _item_label_set(Elm_Ctxpopup_Item *item, const char *label)
1145 {
1146    if (!eina_stringshare_replace(&item->label, label))
1147      return;
1148
1149    edje_object_part_text_set(VIEW(item), "elm.text", label);
1150    edje_object_message_signal_process(VIEW(item));
1151 }
1152
1153 static void
1154 _item_new(Elm_Ctxpopup_Item *item, char *group_name)
1155 {
1156    Widget_Data *wd;
1157
1158    wd = elm_widget_data_get(WIDGET(item));
1159    if (!wd) return;
1160
1161    VIEW(item) = edje_object_add(evas_object_evas_get(wd->base));
1162    edje_object_mirrored_set(VIEW(item), elm_widget_mirrored_get(WIDGET(item)));
1163    _elm_theme_object_set(WIDGET(item), VIEW(item), "ctxpopup", group_name,
1164                          elm_widget_style_get(WIDGET(item)));
1165    edje_object_signal_callback_add(VIEW(item), "elm,action,click", "",
1166                                    _item_select_cb, item);
1167    evas_object_size_hint_align_set(VIEW(item), EVAS_HINT_FILL, EVAS_HINT_FILL);
1168    evas_object_show(VIEW(item));
1169 }
1170
1171 static void
1172 _content_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__,
1173              void *event_info __UNUSED__)
1174 {
1175    elm_object_content_unset(data);
1176 }
1177
1178 static void
1179 _list_del(Widget_Data *wd)
1180 {
1181    if (!wd->scr) return;
1182
1183    edje_object_part_unswallow(wd->base, wd->scr);
1184    evas_object_del(wd->scr);
1185    wd->scr = NULL;
1186    wd->box = NULL;
1187 }
1188
1189 static void
1190 _list_new(Evas_Object *obj)
1191 {
1192    Widget_Data *wd;
1193    wd = elm_widget_data_get(obj);
1194    if (!wd) return;
1195
1196    //scroller
1197    wd->scr = elm_scroller_add(obj);
1198    elm_object_style_set(wd->scr, "ctxpopup");
1199    evas_object_size_hint_align_set(wd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
1200    evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_RESIZE,
1201                                   _scroller_resize, obj);
1202    edje_object_part_swallow(wd->base, "elm.swallow.content", wd->scr);
1203
1204    //box
1205    wd->box = elm_box_add(obj);
1206    evas_object_size_hint_weight_set(wd->box, EVAS_HINT_EXPAND,
1207                                     EVAS_HINT_EXPAND);
1208
1209    elm_object_content_set(wd->scr, wd->box);
1210    elm_ctxpopup_horizontal_set(obj, wd->horizontal);
1211 }
1212
1213 static void
1214 _remove_items(Widget_Data *wd)
1215 {
1216    Eina_List *elist;
1217    Elm_Ctxpopup_Item *item;
1218
1219    if (!wd->items) return;
1220
1221    EINA_LIST_FOREACH(wd->items, elist, item)
1222      {
1223         if (item->label)
1224           eina_stringshare_del(item->label);
1225         if (item->icon)
1226           evas_object_del(item->icon);
1227         wd->items = eina_list_remove(wd->items, item);
1228         elm_widget_item_free(item);
1229      }
1230
1231    wd->items = NULL;
1232 }
1233
1234 static void
1235 _item_del_pre_hook(Elm_Object_Item *it)
1236 {
1237    ELM_OBJ_ITEM_CHECK_OR_RETURN(it);
1238
1239    Widget_Data *wd;
1240    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *) it;
1241
1242    wd = elm_widget_data_get(WIDGET(ctxpopup_it));
1243    if (!wd) return;
1244
1245    if (ctxpopup_it->icon)
1246      evas_object_del(ctxpopup_it->icon);
1247    if (VIEW(ctxpopup_it))
1248      evas_object_del(VIEW(ctxpopup_it));
1249
1250    eina_stringshare_del(ctxpopup_it->label);
1251
1252    wd->items = eina_list_remove(wd->items, ctxpopup_it);
1253
1254    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1255
1256    if (eina_list_count(wd->items) < 1)
1257      {
1258         evas_object_hide(WIDGET(ctxpopup_it));
1259         return;
1260      }
1261
1262    if (wd->visible)
1263      _sizing_eval(WIDGET(ctxpopup_it));
1264 }
1265
1266 EAPI Evas_Object *
1267 elm_ctxpopup_add(Evas_Object *parent)
1268 {
1269    Evas_Object *obj;
1270    Evas *e;
1271    Widget_Data *wd;
1272
1273    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
1274
1275    ELM_SET_WIDTYPE(widtype, "ctxpopup");
1276    elm_widget_type_set(obj, "ctxpopup");
1277    elm_widget_data_set(obj, wd);
1278    elm_widget_del_pre_hook_set(obj, _del_pre_hook);
1279    elm_widget_del_hook_set(obj, _del_hook);
1280    elm_widget_theme_hook_set(obj, _theme_hook);
1281    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1282    elm_widget_can_focus_set(obj, EINA_TRUE);
1283    elm_widget_event_hook_set(obj, _event_hook);
1284    elm_widget_content_set_hook_set(obj, _content_set_hook);
1285    elm_widget_content_unset_hook_set(obj, _content_unset_hook);
1286    elm_widget_content_get_hook_set(obj, _content_get_hook);
1287
1288    //Background
1289    wd->bg = edje_object_add(e);
1290    elm_widget_sub_object_add(obj, wd->bg);
1291    _elm_theme_object_set(obj, wd->bg, "ctxpopup", "bg", "default");
1292    edje_object_signal_callback_add(wd->bg,
1293                                    "elm,action,click",
1294                                    "",
1295                                    _bg_clicked_cb,
1296                                     obj);
1297    //Base
1298    wd->base = edje_object_add(e);
1299    elm_widget_sub_object_add(obj, wd->base);
1300    _elm_theme_object_set(obj, wd->base, "ctxpopup", "base", "default");
1301
1302    //Arrow
1303    wd->arrow = edje_object_add(e);
1304    elm_widget_sub_object_add(obj, wd->arrow);
1305    _elm_theme_object_set(obj, wd->arrow, "ctxpopup", "arrow", "default");
1306
1307    wd->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1308    wd->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1309    wd->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1310    wd->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1311    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1312
1313    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _ctxpopup_show,
1314                                   NULL);
1315    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _ctxpopup_hide,
1316                                   NULL);
1317    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _ctxpopup_move,
1318                                   NULL);
1319    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESTACK, _restack, obj);
1320    evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
1321    evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
1322    evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
1323    evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
1324
1325    evas_object_smart_callbacks_descriptions_set(obj, _signals);
1326
1327    //default parent is to be hover parent
1328    elm_ctxpopup_hover_parent_set(obj, parent);
1329
1330    return obj;
1331 }
1332
1333 EAPI Evas_Object *
1334 elm_ctxpopup_item_icon_get(const Elm_Object_Item *it)
1335 {
1336    return _item_content_get_hook(it, "icon");
1337 }
1338
1339 EAPI void
1340 elm_ctxpopup_item_icon_set(Elm_Object_Item *it, Evas_Object *icon)
1341 {
1342    _item_content_set_hook(it, "icon", icon);
1343 }
1344
1345 EAPI const char *
1346 elm_ctxpopup_item_label_get(const Elm_Object_Item *it)
1347 {
1348    return _item_text_get_hook(it, NULL);
1349 }
1350
1351 EAPI void
1352 elm_ctxpopup_item_label_set(Elm_Object_Item *it, const char *label)
1353 {
1354    _item_text_set_hook(it, NULL, label);
1355 }
1356
1357 EAPI void
1358 elm_ctxpopup_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
1359 {
1360    ELM_CHECK_WIDTYPE(obj, widtype);
1361
1362    Widget_Data *wd;
1363    Evas_Coord x, y, w, h;
1364
1365    wd = elm_widget_data_get(obj);
1366    if ((!wd) || (!parent)) return;
1367
1368    _parent_cut_off(obj);
1369
1370    if (parent)
1371      {
1372         evas_object_event_callback_add(parent,
1373                                        EVAS_CALLBACK_DEL,
1374                                        _parent_del,
1375                                        obj);
1376         evas_object_event_callback_add(parent,
1377                                        EVAS_CALLBACK_MOVE,
1378                                        _parent_move,
1379                                        obj);
1380         evas_object_event_callback_add(parent,
1381                                        EVAS_CALLBACK_RESIZE,
1382                                        _parent_resize,
1383                                        obj);
1384      }
1385
1386    elm_widget_sub_object_add(parent, obj);
1387    wd->parent = parent;
1388
1389    //Update Background
1390    evas_object_geometry_get(parent, &x, &y, &w, &h);
1391    evas_object_move(wd->bg, x, y);
1392    evas_object_resize(wd->bg, w, h);
1393
1394    if (wd->visible) _sizing_eval(obj);
1395 }
1396
1397 EAPI Evas_Object *
1398 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1399 {
1400    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1401
1402    Widget_Data *wd;
1403
1404    wd = elm_widget_data_get(obj);
1405    if (!wd) return NULL;
1406
1407    return wd->parent;
1408 }
1409
1410 EAPI void
1411 elm_ctxpopup_clear(Evas_Object * obj)
1412 {
1413    ELM_CHECK_WIDTYPE(obj, widtype);
1414
1415    Widget_Data *wd = elm_widget_data_get(obj);
1416    if (!wd) return;
1417
1418    _remove_items(wd);
1419    _list_del(wd);
1420    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1421 }
1422
1423 EAPI void
1424 elm_ctxpopup_horizontal_set(Evas_Object *obj, Eina_Bool horizontal)
1425 {
1426    ELM_CHECK_WIDTYPE(obj, widtype);
1427
1428    Widget_Data *wd;
1429
1430    wd = elm_widget_data_get(obj);
1431    if (!wd) return;
1432
1433    wd->horizontal = !!horizontal;
1434
1435    if ((!wd->scr) && (!wd->box))
1436       return;
1437
1438    if (!horizontal)
1439      {
1440         elm_box_horizontal_set(wd->box, EINA_FALSE);
1441         elm_scroller_bounce_set(wd->scr, EINA_FALSE, EINA_TRUE);
1442      }
1443    else
1444      {
1445         elm_box_horizontal_set(wd->box, EINA_TRUE);
1446         elm_scroller_bounce_set(wd->scr, EINA_TRUE, EINA_FALSE);
1447      }
1448
1449    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1450
1451    if (wd->visible)
1452       _sizing_eval(obj);
1453 }
1454
1455 EAPI Eina_Bool
1456 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
1457 {
1458    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1459
1460    Widget_Data *wd;
1461
1462    wd = elm_widget_data_get(obj);
1463    if (!wd) return EINA_FALSE;
1464
1465    return wd->horizontal;
1466 }
1467
1468 EAPI Elm_Object_Item *
1469 elm_ctxpopup_item_append(Evas_Object *obj, const char *label,
1470                          Evas_Object *icon, Evas_Smart_Cb func,
1471                          const void *data)
1472 {
1473    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1474
1475    Widget_Data *wd;
1476    Evas_Object *content;
1477    Elm_Ctxpopup_Item *item;
1478
1479    wd = elm_widget_data_get(obj);
1480    if (!wd) return NULL;
1481
1482    item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
1483    if (!item) return NULL;
1484
1485    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
1486    elm_widget_item_disable_hook_set(item, _item_disable_hook);
1487    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
1488    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
1489    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
1490    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
1491    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
1492
1493    //The first item is appended.
1494    content = elm_object_content_unset(obj);
1495    if (content) evas_object_del(content);
1496
1497    if (!wd->items)
1498      _list_new(obj);
1499
1500    item->func = func;
1501    item->base.data = data;
1502
1503    if (icon && label)
1504      _item_new(item, "icon_text_style_item");
1505    else if (label)
1506      _item_new(item, "text_style_item");
1507    else
1508      _item_new(item, "icon_style_item");
1509
1510    _item_icon_set(item, icon);
1511    _item_label_set(item, label);
1512    elm_box_pack_end(wd->box, VIEW(item));
1513    wd->items = eina_list_append(wd->items, item);
1514    wd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1515
1516    if (wd->visible)
1517      {
1518         _scroller_size_reset(wd);
1519         _sizing_eval(obj);
1520      }
1521
1522    return (Elm_Object_Item *) item;
1523 }
1524
1525 EAPI void
1526 elm_ctxpopup_item_del(Elm_Object_Item *it)
1527 {
1528    elm_object_item_del(it);
1529 }
1530
1531 EAPI void
1532 elm_ctxpopup_item_disabled_set(Elm_Object_Item *it, Eina_Bool disabled)
1533 {
1534    elm_object_item_disabled_set(it, disabled);
1535 }
1536
1537 EAPI Eina_Bool
1538 elm_ctxpopup_item_disabled_get(const Elm_Object_Item *it)
1539 {
1540    return elm_object_item_disabled_get(it);
1541 }
1542
1543 EAPI void
1544 elm_ctxpopup_content_set(Evas_Object *obj, Evas_Object *content)
1545 {
1546    elm_object_content_set(obj, content);
1547 }
1548
1549 EAPI Evas_Object *
1550 elm_ctxpopup_content_unset(Evas_Object *obj)
1551 {
1552    return elm_object_content_unset(obj);
1553 }
1554
1555 EAPI void
1556 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
1557                                     Elm_Ctxpopup_Direction first,
1558                                     Elm_Ctxpopup_Direction second,
1559                                     Elm_Ctxpopup_Direction third,
1560                                     Elm_Ctxpopup_Direction fourth)
1561 {
1562    ELM_CHECK_WIDTYPE(obj, widtype);
1563    Widget_Data *wd;
1564
1565    wd = elm_widget_data_get(obj);
1566    if (!wd) return;
1567
1568    wd->dir_priority[0] = first;
1569    wd->dir_priority[1] = second;
1570    wd->dir_priority[2] = third;
1571    wd->dir_priority[3] = fourth;
1572
1573    if (wd->visible)
1574      _sizing_eval(obj);
1575 }
1576
1577 EAPI void
1578 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
1579                                     Elm_Ctxpopup_Direction *first,
1580                                     Elm_Ctxpopup_Direction *second,
1581                                     Elm_Ctxpopup_Direction *third,
1582                                     Elm_Ctxpopup_Direction *fourth)
1583 {
1584    ELM_CHECK_WIDTYPE(obj, widtype);
1585    Widget_Data *wd;
1586
1587    wd = elm_widget_data_get(obj);
1588    if (!wd) return;
1589
1590    if (first) *first = wd->dir_priority[0];
1591    if (second) *second = wd->dir_priority[1];
1592    if (third) *third = wd->dir_priority[2];
1593    if (fourth) *fourth = wd->dir_priority[3];
1594 }
1595
1596 EAPI Elm_Ctxpopup_Direction
1597 elm_ctxpopup_direction_get(const Evas_Object *obj)
1598 {
1599    ELM_CHECK_WIDTYPE(obj, widtype) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1600    Widget_Data *wd;
1601
1602    wd = elm_widget_data_get(obj);
1603    if (!wd) return ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1604    return wd->dir;
1605 }