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