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