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