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