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