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