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