[access][ctxpopup][popup] parent could be any object such as elm_list which does
[platform/upstream/elementary.git] / src / lib / elc_ctxpopup.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_ctxpopup.h"
4
5 EAPI Eo_Op ELM_OBJ_CTXPOPUP_BASE_ID = EO_NOOP;
6
7 #define MY_CLASS ELM_OBJ_CTXPOPUP_CLASS
8
9 #define MY_CLASS_NAME "elm_ctxpopup"
10
11 EAPI const char ELM_CTXPOPUP_SMART_NAME[] = "elm_ctxpopup";
12
13 static const char SIG_DISMISSED[] = "dismissed";
14 static const char SIG_LANG_CHANGED[] = "language,changed";
15
16 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
17    {SIG_DISMISSED, ""},
18    {SIG_LANG_CHANGED, ""},
19    {NULL, NULL}
20 };
21
22 static void
23 _elm_ctxpopup_smart_translate(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
24 {
25    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
26    evas_object_hide(obj);
27
28    if (ret) *ret = EINA_TRUE;
29 }
30
31 static void
32 _elm_ctxpopup_smart_focus_next_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list)
33 {
34    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
35    *ret = EINA_TRUE;
36 }
37
38 static void
39 _elm_ctxpopup_smart_focus_direction_manager_is(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list)
40 {
41    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
42    *ret = EINA_FALSE;
43 }
44
45 static void
46 _elm_ctxpopup_smart_focus_next(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
47 {
48    Elm_Ctxpopup_Smart_Data *sd = _pd;
49
50    Elm_Focus_Direction dir = va_arg(*list, Elm_Focus_Direction);
51    Evas_Object **next =  va_arg(*list, Evas_Object **);
52    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
53    if (ret) *ret = EINA_FALSE;
54
55    if (!sd)
56      return;
57
58    if (!elm_widget_focus_next_get(sd->box, dir, next))
59      {
60         elm_widget_focused_object_clear(sd->box);
61         elm_widget_focus_next_get(sd->box, dir, next);
62      }
63
64    if (ret) *ret = EINA_TRUE;
65 }
66
67 static void
68 _elm_ctxpopup_smart_event(Eo *obj, void *_pd, va_list *list)
69 {
70    Evas_Object *src = va_arg(*list, Evas_Object *);
71    (void)src;
72    Evas_Callback_Type type = va_arg(*list, Evas_Callback_Type);
73    void *event_info = va_arg(*list, void *);
74    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
75    if (ret) *ret = EINA_FALSE;
76
77    Evas_Event_Key_Down *ev = event_info;
78
79    Elm_Ctxpopup_Smart_Data *sd = _pd;
80
81    if (elm_widget_disabled_get(obj)) return;
82    if (type != EVAS_CALLBACK_KEY_DOWN) return;
83    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
84
85    if (!strcmp(ev->keyname, "Tab"))
86      {
87         if (evas_key_modifier_is_set(ev->modifiers, "Shift"))
88           elm_widget_focus_cycle(sd->box, ELM_FOCUS_PREVIOUS);
89         else
90           elm_widget_focus_cycle(sd->box, ELM_FOCUS_NEXT);
91         if (ret) *ret = EINA_TRUE;
92         return;
93      }
94
95    if (strcmp(ev->keyname, "Escape")) return;
96
97    evas_object_hide(obj);
98    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
99    if (ret) *ret = EINA_TRUE;
100 }
101
102 static void
103 _x_pos_adjust(Evas_Coord_Point *pos,
104               Evas_Coord_Point *base_size,
105               Evas_Coord_Rectangle *hover_area)
106 {
107    pos->x -= (base_size->x / 2);
108
109    if (pos->x < hover_area->x)
110      pos->x = hover_area->x;
111    else if ((pos->x + base_size->x) > (hover_area->x + hover_area->w))
112      pos->x = (hover_area->x + hover_area->w) - base_size->x;
113
114    if (base_size->x > hover_area->w)
115      base_size->x -= (base_size->x - hover_area->w);
116
117    if (pos->x < hover_area->x)
118      pos->x = hover_area->x;
119 }
120
121 static void
122 _y_pos_adjust(Evas_Coord_Point *pos,
123               Evas_Coord_Point *base_size,
124               Evas_Coord_Rectangle *hover_area)
125 {
126    pos->y -= (base_size->y / 2);
127
128    if (pos->y < hover_area->y)
129      pos->y = hover_area->y;
130    else if ((pos->y + base_size->y) > (hover_area->y + hover_area->h))
131      pos->y = hover_area->y + hover_area->h - base_size->y;
132
133    if (base_size->y > hover_area->h)
134      base_size->y -= (base_size->y - hover_area->h);
135
136    if (pos->y < hover_area->y)
137      pos->y = hover_area->y;
138 }
139
140 static Elm_Ctxpopup_Direction
141 _base_geometry_calc(Evas_Object *obj,
142                     Evas_Coord_Rectangle *rect)
143 {
144    Elm_Ctxpopup_Direction dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
145    Evas_Coord_Rectangle hover_area;
146    Evas_Coord_Point pos = {0, 0};
147    Evas_Coord_Point arrow_size;
148    Evas_Coord_Point base_size;
149    Evas_Coord_Point max_size;
150    Evas_Coord_Point min_size;
151    Evas_Coord_Point temp;
152    int idx;
153
154    ELM_CTXPOPUP_DATA_GET(obj, sd);
155    Elm_Widget_Smart_Data *wd = eo_data_get(obj, ELM_OBJ_WIDGET_CLASS);
156
157    if (!rect) return ELM_CTXPOPUP_DIRECTION_DOWN;
158
159    edje_object_part_geometry_get
160      (sd->arrow, "ctxpopup_arrow", NULL, NULL, &arrow_size.x, &arrow_size.y);
161    evas_object_resize(sd->arrow, arrow_size.x, arrow_size.y);
162
163    //Initialize Area Rectangle.
164    evas_object_geometry_get
165      (sd->parent, &hover_area.x, &hover_area.y, &hover_area.w,
166      &hover_area.h);
167
168    evas_object_geometry_get(obj, &pos.x, &pos.y, NULL, NULL);
169
170    //recalc the edje
171    edje_object_size_min_calc
172      (wd->resize_obj, &base_size.x, &base_size.y);
173    evas_object_smart_calculate(wd->resize_obj);
174
175    //Limit to Max Size
176    evas_object_size_hint_max_get(obj, &max_size.x, &max_size.y);
177
178    if ((max_size.y > 0) && (base_size.y > max_size.y))
179      base_size.y = max_size.y;
180
181    if ((max_size.x > 0) && (base_size.x > max_size.x))
182      base_size.x = max_size.x;
183
184    //Limit to Min Size
185    evas_object_size_hint_min_get(obj, &min_size.x, &min_size.y);
186
187    if ((min_size.y > 0) && (base_size.y < min_size.y))
188      base_size.y = min_size.y;
189
190    if ((min_size.x > 0) && (base_size.x < min_size.x))
191      base_size.x = min_size.x;
192
193    //Check the Which direction is available.
194    //If find a avaialble direction, it adjusts position and size.
195    for (idx = 0; idx < 4; idx++)
196      {
197         switch (sd->dir_priority[idx])
198           {
199            case ELM_CTXPOPUP_DIRECTION_UP:
200              temp.y = (pos.y - base_size.y);
201              if ((temp.y - arrow_size.y) < hover_area.y)
202                continue;
203
204              _x_pos_adjust(&pos, &base_size, &hover_area);
205              pos.y -= base_size.y;
206              dir = ELM_CTXPOPUP_DIRECTION_UP;
207              break;
208
209            case ELM_CTXPOPUP_DIRECTION_LEFT:
210              temp.x = (pos.x - base_size.x);
211              if ((temp.x - arrow_size.x) < hover_area.x)
212                continue;
213
214              _y_pos_adjust(&pos, &base_size, &hover_area);
215              pos.x -= base_size.x;
216              dir = ELM_CTXPOPUP_DIRECTION_LEFT;
217              break;
218
219            case ELM_CTXPOPUP_DIRECTION_RIGHT:
220              temp.x = (pos.x + base_size.x);
221              if ((temp.x + arrow_size.x) >
222                  (hover_area.x + hover_area.w))
223                continue;
224
225              _y_pos_adjust(&pos, &base_size, &hover_area);
226              dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
227              break;
228
229            case ELM_CTXPOPUP_DIRECTION_DOWN:
230              temp.y = (pos.y + base_size.y);
231              if ((temp.y + arrow_size.y) >
232                  (hover_area.y + hover_area.h))
233                continue;
234
235              _x_pos_adjust(&pos, &base_size, &hover_area);
236              dir = ELM_CTXPOPUP_DIRECTION_DOWN;
237              break;
238
239            default:
240              continue;
241           }
242         break;
243      }
244
245    //In this case, all directions are invalid because of lack of space.
246    if (idx == 4)
247      {
248         Evas_Coord length[2];
249
250         if (!sd->horizontal)
251           {
252              length[0] = pos.y - hover_area.y;
253              length[1] = (hover_area.y + hover_area.h) - pos.y;
254
255              // ELM_CTXPOPUP_DIRECTION_UP
256              if (length[0] > length[1])
257                {
258                   _x_pos_adjust(&pos, &base_size, &hover_area);
259                   pos.y -= base_size.y;
260                   dir = ELM_CTXPOPUP_DIRECTION_UP;
261                   if (pos.y < (hover_area.y + arrow_size.y))
262                     {
263                        base_size.y -= ((hover_area.y + arrow_size.y) - pos.y);
264                        pos.y = hover_area.y + arrow_size.y;
265                     }
266                }
267              //ELM_CTXPOPUP_DIRECTION_DOWN
268              else
269                {
270                   _x_pos_adjust(&pos, &base_size, &hover_area);
271                   dir = ELM_CTXPOPUP_DIRECTION_DOWN;
272                   if ((pos.y + arrow_size.y + base_size.y) >
273                       (hover_area.y + hover_area.h))
274                     base_size.y -=
275                       ((pos.y + arrow_size.y + base_size.y) -
276                        (hover_area.y + hover_area.h));
277                }
278           }
279         else
280           {
281              length[0] = pos.x - hover_area.x;
282              length[1] = (hover_area.x + hover_area.w) - pos.x;
283
284              //ELM_CTXPOPUP_DIRECTION_LEFT
285              if (length[0] > length[1])
286                {
287                   _y_pos_adjust(&pos, &base_size, &hover_area);
288                   pos.x -= base_size.x;
289                   dir = ELM_CTXPOPUP_DIRECTION_LEFT;
290                   if (pos.x < (hover_area.x + arrow_size.x))
291                     {
292                        base_size.x -= ((hover_area.x + arrow_size.x) - pos.x);
293                        pos.x = hover_area.x + arrow_size.x;
294                     }
295                }
296              //ELM_CTXPOPUP_DIRECTION_RIGHT
297              else
298                {
299                   _y_pos_adjust(&pos, &base_size, &hover_area);
300                   dir = ELM_CTXPOPUP_DIRECTION_RIGHT;
301                   if (pos.x + (arrow_size.x + base_size.x) >
302                       hover_area.x + hover_area.w)
303                     base_size.x -=
304                       ((pos.x + arrow_size.x + base_size.x) -
305                        (hover_area.x + hover_area.w));
306                }
307           }
308      }
309
310    //Final position and size.
311    rect->x = pos.x;
312    rect->y = pos.y;
313    rect->w = base_size.x;
314    rect->h = base_size.y;
315
316    return dir;
317 }
318
319 static void
320 _arrow_update(Evas_Object *obj,
321               Elm_Ctxpopup_Direction dir,
322               Evas_Coord_Rectangle base_size)
323 {
324    Evas_Coord_Rectangle arrow_size;
325    Evas_Coord x, y;
326    double drag;
327
328    ELM_CTXPOPUP_DATA_GET(obj, sd);
329    Elm_Widget_Smart_Data *wd = eo_data_get(obj, ELM_OBJ_WIDGET_CLASS);
330
331    evas_object_geometry_get(obj, &x, &y, NULL, NULL);
332    evas_object_geometry_get
333      (sd->arrow, NULL, NULL, &arrow_size.w, &arrow_size.h);
334
335    /* arrow is not being kept as sub-object on purpose, here. the
336     * design of the widget does not help with the contrary */
337
338    switch (dir)
339      {
340       case ELM_CTXPOPUP_DIRECTION_RIGHT:
341         edje_object_signal_emit(sd->arrow, "elm,state,left", "elm");
342         edje_object_part_swallow
343            (wd->resize_obj,
344             (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
345              "elm.swallow.arrow_left"), sd->arrow);
346
347         if (base_size.h > 0)
348           {
349              if (y < ((arrow_size.h * 0.5) + base_size.y))
350                y = 0;
351              else if (y > base_size.y + base_size.h - (arrow_size.h * 0.5))
352                y = base_size.h - arrow_size.h;
353              else
354                y = y - base_size.y - (arrow_size.h * 0.5);
355              drag = (double)(y) / (double)(base_size.h - arrow_size.h);
356              edje_object_part_drag_value_set
357                 (wd->resize_obj,
358                  (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_right" :
359                   "elm.swallow.arrow_left"), 1, drag);
360           }
361         break;
362
363       case ELM_CTXPOPUP_DIRECTION_LEFT:
364         edje_object_signal_emit(sd->arrow, "elm,state,right", "elm");
365         edje_object_part_swallow
366            (wd->resize_obj,
367             (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
368              "elm.swallow.arrow_right"), sd->arrow);
369
370         if (base_size.h > 0)
371           {
372              if (y < ((arrow_size.h * 0.5) + base_size.y))
373                y = 0;
374              else if (y > (base_size.y + base_size.h - (arrow_size.h * 0.5)))
375                y = base_size.h - arrow_size.h;
376              else
377                y = y - base_size.y - (arrow_size.h * 0.5);
378              drag = (double)(y) / (double)(base_size.h - arrow_size.h);
379              edje_object_part_drag_value_set
380                 (wd->resize_obj,
381                  (elm_widget_mirrored_get(obj) ? "elm.swallow.arrow_left" :
382                   "elm.swallow.arrow_right"), 0, drag);
383           }
384         break;
385
386       case ELM_CTXPOPUP_DIRECTION_DOWN:
387         edje_object_signal_emit(sd->arrow, "elm,state,top", "elm");
388         edje_object_part_swallow
389           (wd->resize_obj, "elm.swallow.arrow_up",
390           sd->arrow);
391
392         if (base_size.w > 0)
393           {
394              if (x < ((arrow_size.w * 0.5) + base_size.x))
395                x = 0;
396              else if (x > (base_size.x + base_size.w - (arrow_size.w * 0.5)))
397                x = base_size.w - arrow_size.w;
398              else
399                x = x - base_size.x - (arrow_size.w * 0.5);
400              drag = (double)(x) / (double)(base_size.w - arrow_size.w);
401              edje_object_part_drag_value_set
402                (wd->resize_obj, "elm.swallow.arrow_up", drag,
403                1);
404           }
405         break;
406
407       case ELM_CTXPOPUP_DIRECTION_UP:
408         edje_object_signal_emit(sd->arrow, "elm,state,bottom", "elm");
409         edje_object_part_swallow
410           (wd->resize_obj, "elm.swallow.arrow_down",
411           sd->arrow);
412
413         if (base_size.w > 0)
414           {
415              if (x < ((arrow_size.w * 0.5) + base_size.x))
416                x = 0;
417              else if (x > (base_size.x + base_size.w - (arrow_size.w * 0.5)))
418                x = base_size.w - arrow_size.w;
419              else x = x - base_size.x - (arrow_size.w * 0.5);
420              drag = (double)(x) / (double)(base_size.w - arrow_size.w);
421              edje_object_part_drag_value_set
422                (wd->resize_obj, "elm.swallow.arrow_down",
423                drag, 0);
424           }
425         break;
426
427       default:
428         break;
429      }
430
431    //should be here for getting accurate geometry value
432    evas_object_smart_calculate(wd->resize_obj);
433 }
434
435 static void
436 _show_signals_emit(Evas_Object *obj,
437                    Elm_Ctxpopup_Direction dir)
438 {
439    ELM_CTXPOPUP_DATA_GET(obj, sd);
440
441    if (!sd->visible) return;
442    if ((sd->list) && (!sd->list_visible)) return;
443
444    switch (dir)
445      {
446       case ELM_CTXPOPUP_DIRECTION_UP:
447         elm_layout_signal_emit(obj, "elm,state,show,up", "elm");
448         break;
449
450       case ELM_CTXPOPUP_DIRECTION_LEFT:
451         elm_layout_signal_emit(obj,
452               (elm_widget_mirrored_get(obj) ? "elm,state,show,right" :
453                "elm,state,show,left"), "elm");
454         break;
455
456       case ELM_CTXPOPUP_DIRECTION_RIGHT:
457         elm_layout_signal_emit(obj,
458               (elm_widget_mirrored_get(obj) ? "elm,state,show,left" :
459                "elm,state,show,right"), "elm");
460         break;
461
462       case ELM_CTXPOPUP_DIRECTION_DOWN:
463         elm_layout_signal_emit(obj, "elm,state,show,down", "elm");
464         break;
465
466       default:
467         break;
468      }
469
470    edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
471    elm_layout_signal_emit(obj, "elm,state,show", "elm");
472 }
473
474 static void
475 _hide_signals_emit(Evas_Object *obj,
476                    Elm_Ctxpopup_Direction dir)
477 {
478    ELM_CTXPOPUP_DATA_GET(obj, sd);
479
480    if (!sd->visible) return;
481
482    switch (dir)
483      {
484       case ELM_CTXPOPUP_DIRECTION_UP:
485         elm_layout_signal_emit(obj, "elm,state,hide,up", "elm");
486         break;
487
488       case ELM_CTXPOPUP_DIRECTION_LEFT:
489         elm_layout_signal_emit(obj,
490               (elm_widget_mirrored_get(obj) ? "elm,state,hide,right" :
491                "elm,state,hide,left"), "elm");
492         break;
493
494       case ELM_CTXPOPUP_DIRECTION_RIGHT:
495         elm_layout_signal_emit(obj,
496               (elm_widget_mirrored_get(obj) ? "elm,state,hide,left" :
497                "elm,state,hide,right"), "elm");
498         break;
499
500       case ELM_CTXPOPUP_DIRECTION_DOWN:
501         elm_layout_signal_emit(obj, "elm,state,hide,down", "elm");
502         break;
503
504       default:
505         break;
506      }
507
508    edje_object_signal_emit(sd->bg, "elm,state,hide", "elm");
509 }
510
511 static void
512 _base_shift_by_arrow(Evas_Object *arrow,
513                      Elm_Ctxpopup_Direction dir,
514                      Evas_Coord_Rectangle *rect)
515 {
516    Evas_Coord arrow_w, arrow_h;
517
518    evas_object_geometry_get(arrow, NULL, NULL, &arrow_w, &arrow_h);
519    switch (dir)
520      {
521       case ELM_CTXPOPUP_DIRECTION_RIGHT:
522         rect->x += arrow_w;
523         break;
524
525       case ELM_CTXPOPUP_DIRECTION_LEFT:
526         rect->x -= arrow_w;
527         break;
528
529       case ELM_CTXPOPUP_DIRECTION_DOWN:
530         rect->y += arrow_h;
531         break;
532
533       case ELM_CTXPOPUP_DIRECTION_UP:
534         rect->y -= arrow_h;
535         break;
536
537       default:
538         break;
539      }
540 }
541
542 static void
543 _elm_ctxpopup_smart_layout_sub_object_add_enable(Eo *obj EINA_UNUSED, void *_pd EINA_UNUSED, va_list *list)
544 {
545    Eina_Bool *enable = va_arg(*list, Eina_Bool *);
546    *enable = EINA_FALSE;
547 }
548
549 static void
550 _elm_ctxpopup_smart_sub_object_add(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
551 {
552    Evas_Object *sobj = va_arg(*list, Evas_Object *);
553    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
554    Eina_Bool int_ret;
555
556    eo_do_super(obj, elm_wdg_sub_object_add(sobj, &int_ret));
557
558    if (ret) *ret = int_ret;
559 }
560
561 static void
562 _elm_ctxpopup_smart_sizing_eval(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
563 {
564    Evas_Coord_Rectangle rect = { 0, 0, 1, 1 };
565    Evas_Coord_Point list_size = { 0, 0 };
566
567    Elm_Ctxpopup_Smart_Data *sd = _pd;
568    Elm_Widget_Smart_Data *wd = eo_data_get(obj, ELM_OBJ_WIDGET_CLASS);
569
570    if (!sd->arrow) return;  /* simple way to flag "under deletion" */
571
572    //Base
573    sd->dir = _base_geometry_calc(obj, &rect);
574
575    _arrow_update(obj, sd->dir, rect);
576
577    _base_shift_by_arrow(sd->arrow, sd->dir, &rect);
578
579    if ((sd->list) && (sd->list_visible))
580      {
581         evas_object_geometry_get(sd->list, 0, 0, &list_size.x, &list_size.y);
582         if ((list_size.x >= rect.w) || (list_size.y >= rect.h))
583           {
584              elm_list_mode_set(sd->list, ELM_LIST_COMPRESS);
585              evas_object_size_hint_min_set(sd->box, rect.w, rect.h);
586              evas_object_size_hint_min_set(obj, rect.w, rect.h);
587           }
588      }
589
590    evas_object_move(wd->resize_obj, rect.x, rect.y);
591    evas_object_resize(wd->resize_obj, rect.w, rect.h);
592
593    _show_signals_emit(obj, sd->dir);
594 }
595
596 static void
597 _on_parent_del(void *data,
598                Evas *e __UNUSED__,
599                Evas_Object *obj __UNUSED__,
600                void *event_info __UNUSED__)
601 {
602    evas_object_del(data);
603 }
604
605 static void
606 _on_parent_move(void *data,
607                 Evas *e __UNUSED__,
608                 Evas_Object *obj __UNUSED__,
609                 void *event_info __UNUSED__)
610 {
611    ELM_CTXPOPUP_DATA_GET(data, sd);
612
613    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
614
615    if (sd->visible) elm_layout_sizing_eval(data);
616 }
617
618 static void
619 _on_parent_resize(void *data,
620                   Evas *e __UNUSED__,
621                   Evas_Object *obj __UNUSED__,
622                   void *event_info __UNUSED__)
623 {
624    ELM_CTXPOPUP_DATA_GET(data, sd);
625
626    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
627
628    evas_object_hide(data);
629    evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
630 }
631
632 static void
633 _parent_detach(Evas_Object *obj)
634 {
635    ELM_CTXPOPUP_DATA_GET(obj, sd);
636
637    if (!sd->parent) return;
638
639    evas_object_event_callback_del_full
640      (sd->parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
641    evas_object_event_callback_del_full
642      (sd->parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
643    evas_object_event_callback_del_full
644      (sd->parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
645 }
646
647 static void
648 _on_content_resized(void *data,
649                     Evas *e __UNUSED__,
650                     Evas_Object *obj __UNUSED__,
651                     void *event_info __UNUSED__)
652 {
653    ELM_CTXPOPUP_DATA_GET(data, sd);
654
655    elm_box_recalculate(sd->box);
656    elm_layout_sizing_eval(data);
657 }
658
659 //FIXME: lost the content size when theme hook is called.
660 static void
661 _elm_ctxpopup_smart_theme(Eo *obj, void *_pd, va_list *list)
662 {
663    Elm_Ctxpopup_Smart_Data *sd = _pd;
664
665    Eina_Bool int_ret;
666    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
667    if (ret) *ret = EINA_FALSE;
668
669    eo_do_super(obj, elm_wdg_theme(&int_ret));
670    if (!int_ret) return;
671
672    elm_widget_theme_object_set
673      (obj, sd->bg, "ctxpopup", "bg", elm_widget_style_get(obj));
674    elm_widget_theme_object_set
675      (obj, sd->arrow, "ctxpopup", "arrow", elm_widget_style_get(obj));
676
677    if (sd->list)
678      {
679         if (!strncmp(elm_object_style_get(obj), "default", strlen("default")))
680           elm_object_style_set(sd->list, "ctxpopup");
681         else
682           elm_object_style_set(sd->list, elm_object_style_get(obj));
683      }
684
685    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
686
687    if (sd->visible) elm_layout_sizing_eval(obj);
688
689    if (ret) *ret = EINA_TRUE;
690 }
691
692 /* kind of a big and tricky override here: an internal box will hold
693  * the actual content. content aliases won't be of much help here */
694 static void
695 _elm_ctxpopup_smart_content_set(Eo *obj, void *_pd, va_list *list)
696 {
697    Evas_Coord min_w = -1, min_h = -1;
698
699    Elm_Ctxpopup_Smart_Data *sd = _pd;
700    const char *part = va_arg(*list, const char *);
701    Evas_Object *content = va_arg(*list, Evas_Object *);
702    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
703    Eina_Bool int_ret = EINA_TRUE;
704
705    if ((part) && (strcmp(part, "default")))
706      {
707         eo_do_super(obj, elm_obj_container_content_set(part, content, &int_ret));
708         goto end;
709      }
710
711    if (!content)
712      {
713         int_ret = EINA_FALSE;
714         goto end;
715      }
716
717    if (content == sd->content) goto end;
718
719    if (sd->content) evas_object_del(sd->content);
720    if (sd->content == sd->list) sd->list = NULL;
721
722    evas_object_size_hint_weight_set
723      (content, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
724    evas_object_size_hint_fill_set
725      (content, EVAS_HINT_FILL, EVAS_HINT_FILL);
726
727    /* since it's going to be a box content, not a layout's... */
728    evas_object_show(content);
729
730    evas_object_size_hint_min_get(content, &min_w, &min_h);
731    evas_object_size_hint_min_set(sd->box, min_w, min_h);
732    elm_box_pack_end(sd->box, content);
733
734    sd->content = content;
735    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
736
737    if (sd->visible) elm_layout_sizing_eval(obj);
738
739 end:
740    if (ret) *ret = int_ret;
741 }
742
743 static void
744 _elm_ctxpopup_smart_content_get(Eo *obj, void *_pd, va_list *list)
745 {
746    const char *part = va_arg(*list, const char *);
747    Evas_Object **ret = va_arg(*list, Evas_Object **);
748    *ret = NULL;
749
750    if ((part) && (strcmp(part, "default")))
751      {
752         eo_do_super(obj, elm_obj_container_content_get(part, ret));
753         return;
754      }
755
756    Elm_Ctxpopup_Smart_Data *sd = _pd;
757
758    *ret = sd->content;
759 }
760
761 static void
762 _elm_ctxpopup_smart_content_unset(Eo *obj, void *_pd, va_list *list)
763 {
764    Evas_Object *content;
765
766    const char *part = va_arg(*list, const char *);
767    Evas_Object **ret = va_arg(*list, Evas_Object **);
768
769    if ((part) && (strcmp(part, "default")))
770      {
771         eo_do_super(obj, elm_obj_container_content_unset(part, &content));
772         goto end;
773      }
774
775    Elm_Ctxpopup_Smart_Data *sd = _pd;
776    content = sd->content;
777    if (!content) goto end;
778
779    sd->content = NULL;
780    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
781
782    if (sd->visible) elm_layout_sizing_eval(obj);
783
784 end:
785    if (ret) *ret = content;
786 }
787
788 static void
789 _item_text_set_hook(Elm_Object_Item *it,
790                     const char *part,
791                     const char *label)
792 {
793    Elm_Ctxpopup_Item *ctxpopup_it;
794
795    if ((part) && (strcmp(part, "default"))) return;
796
797    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
798
799    ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
800
801    elm_object_item_part_text_set(ctxpopup_it->list_item, "default", label);
802    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
803
804    if (sd->visible) elm_layout_sizing_eval(WIDGET(ctxpopup_it));
805 }
806
807 static const char *
808 _item_text_get_hook(const Elm_Object_Item *it,
809                     const char *part)
810 {
811    Elm_Ctxpopup_Item *ctxpopup_it;
812
813    if (part && strcmp(part, "default")) return NULL;
814
815    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
816    return elm_object_item_part_text_get(ctxpopup_it->list_item, "default");
817 }
818
819 static void
820 _item_content_set_hook(Elm_Object_Item *it,
821                        const char *part,
822                        Evas_Object *content)
823 {
824    Elm_Ctxpopup_Item *ctxpopup_it;
825
826    if ((part) && (strcmp(part, "icon"))
827        && (strcmp(part, "start"))
828        && (strcmp(part, "end"))) return;
829
830    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
831
832    ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
833
834    if ((part) && (!strcmp(part, "end")))
835      elm_object_item_part_content_set(ctxpopup_it->list_item, "end", content);
836    else
837      elm_object_item_part_content_set
838        (ctxpopup_it->list_item, "start", content);
839
840    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
841
842    if (sd->visible) elm_layout_sizing_eval(WIDGET(ctxpopup_it));
843 }
844
845 static Evas_Object *
846 _item_content_get_hook(const Elm_Object_Item *it,
847                        const char *part)
848 {
849    Elm_Ctxpopup_Item *ctxpopup_it;
850
851    if (part && strcmp(part, "icon") && strcmp(part, "start")
852        && strcmp(part, "end")) return NULL;
853
854    ctxpopup_it = (Elm_Ctxpopup_Item *)it;
855
856    if (part && !strcmp(part, "end"))
857      return elm_object_item_part_content_get(ctxpopup_it->list_item, "end");
858    else
859      return elm_object_item_part_content_get(ctxpopup_it->list_item, "start");
860 }
861
862 static void
863 _item_disable_hook(Elm_Object_Item *it)
864 {
865    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
866
867    elm_object_item_disabled_set
868      (ctxpopup_it->list_item, elm_widget_item_disabled_get(ctxpopup_it));
869 }
870
871 static void
872 _item_signal_emit_hook(Elm_Object_Item *it,
873                        const char *emission,
874                        const char *source)
875 {
876    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
877
878    elm_object_item_signal_emit(ctxpopup_it->list_item, emission, source);
879 }
880
881 static void
882 _bg_clicked_cb(void *data,
883                Evas_Object *obj __UNUSED__,
884                const char *emission __UNUSED__,
885                const char *source __UNUSED__)
886 {
887    ELM_CTXPOPUP_DATA_GET(data, sd);
888
889    _hide_signals_emit(data, sd->dir);
890 }
891
892 static void
893 _on_show(void *data __UNUSED__,
894          Evas *e __UNUSED__,
895          Evas_Object *obj,
896          void *event_info __UNUSED__)
897 {
898    ELM_CTXPOPUP_DATA_GET(obj, sd);
899
900    if (sd->list)
901      {
902         elm_list_go(sd->list);
903         sd->visible = EINA_TRUE;
904         elm_object_focus_set(obj, EINA_TRUE);
905         return;
906      }
907
908    if (!sd->content) return;
909
910    sd->visible = EINA_TRUE;
911
912    evas_object_show(sd->bg);
913    evas_object_show(sd->arrow);
914
915    edje_object_signal_emit(sd->bg, "elm,state,show", "elm");
916    elm_layout_signal_emit(obj, "elm,state,show", "elm");
917
918    elm_layout_sizing_eval(obj);
919
920    elm_object_focus_set(obj, EINA_TRUE);
921 }
922
923 static void
924 _on_hide(void *data __UNUSED__,
925          Evas *e __UNUSED__,
926          Evas_Object *obj,
927          void *event_info __UNUSED__)
928 {
929    ELM_CTXPOPUP_DATA_GET(obj, sd);
930
931    if (!sd->visible) return;
932
933    evas_object_hide(sd->bg);
934    evas_object_hide(sd->arrow);
935
936    sd->visible = EINA_FALSE;
937    sd->list_visible = EINA_FALSE;
938 }
939
940 static void
941 _on_move(void *data __UNUSED__,
942          Evas *e __UNUSED__,
943          Evas_Object *obj,
944          void *event_info __UNUSED__)
945 {
946    ELM_CTXPOPUP_DATA_GET(obj, sd);
947
948    if (sd->visible) evas_object_show(sd->arrow);
949
950    elm_layout_sizing_eval(obj);
951 }
952
953 static void
954 _hide_finished_cb(void *data,
955                   Evas_Object *obj __UNUSED__,
956                   const char *emission __UNUSED__,
957                   const char *source __UNUSED__)
958 {
959    evas_object_hide(data);
960    evas_object_smart_callback_call(data, SIG_DISMISSED, NULL);
961 }
962
963 static void
964 _list_resize_cb(void *data,
965                 Evas *e __UNUSED__,
966                 Evas_Object *obj __UNUSED__,
967                 void *event_info __UNUSED__)
968 {
969    ELM_CTXPOPUP_DATA_GET(data, sd);
970
971    if (!sd->visible) return;
972    if (sd->list_visible) return;
973
974    sd->list_visible = EINA_TRUE;
975
976    evas_object_show(sd->bg);
977    evas_object_show(sd->arrow);
978
979    elm_layout_sizing_eval(data);
980 }
981
982 static void
983 _ctxpopup_restack_cb(void *data __UNUSED__,
984                      Evas *e __UNUSED__,
985                      Evas_Object *obj,
986                      void *event_info __UNUSED__)
987 {
988    ELM_CTXPOPUP_DATA_GET(obj, sd);
989
990    evas_object_layer_set(sd->bg, evas_object_layer_get(obj));
991 }
992
993 static void
994 _list_del(Elm_Ctxpopup_Smart_Data *sd)
995 {
996    if (!sd->list) return;
997
998    evas_object_del(sd->list);
999    sd->list = NULL;
1000 }
1001
1002 static Eina_Bool
1003 _item_del_pre_hook(Elm_Object_Item *it)
1004 {
1005    Evas_Object *list;
1006    Elm_Ctxpopup_Item *ctxpopup_it = (Elm_Ctxpopup_Item *)it;
1007
1008    ELM_CTXPOPUP_DATA_GET(WIDGET(ctxpopup_it), sd);
1009
1010    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1011
1012    list = elm_object_item_widget_get(ctxpopup_it->list_item);
1013
1014    if (eina_list_count(elm_list_items_get(list)) < 2)
1015      {
1016         elm_object_item_del(ctxpopup_it->list_item);
1017         sd->items = eina_list_remove(sd->items, ctxpopup_it);
1018         evas_object_hide(WIDGET(ctxpopup_it));
1019
1020         return EINA_TRUE;
1021      }
1022
1023    elm_object_item_del(ctxpopup_it->list_item);
1024    sd->items = eina_list_remove(sd->items, ctxpopup_it);
1025    if (sd->list_visible) elm_layout_sizing_eval(WIDGET(ctxpopup_it));
1026
1027    return EINA_TRUE;
1028 }
1029
1030 static void
1031 _elm_ctxpopup_smart_disable(Eo *obj, void *_pd, va_list *list)
1032 {
1033    Elm_Ctxpopup_Smart_Data *sd = _pd;
1034
1035    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
1036    if (ret) *ret = EINA_FALSE;
1037    Eina_Bool int_ret;
1038
1039    eo_do_super(obj, elm_wdg_disable(&int_ret));
1040    if (!int_ret) return;
1041
1042    elm_object_disabled_set(sd->list, elm_widget_disabled_get(obj));
1043
1044    if (ret) *ret = EINA_TRUE;
1045 }
1046
1047 static void
1048 _elm_ctxpopup_smart_add(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
1049 {
1050    Elm_Ctxpopup_Smart_Data *priv = _pd;
1051
1052    eo_do_super(obj, evas_obj_smart_add());
1053
1054    elm_layout_theme_set(obj, "ctxpopup", "base", elm_widget_style_get(obj));
1055    elm_layout_signal_callback_add
1056      (obj, "elm,action,hide,finished", "", _hide_finished_cb, obj);
1057
1058    //Background
1059    priv->bg = edje_object_add(evas_object_evas_get(obj));
1060    elm_widget_theme_object_set(obj, priv->bg, "ctxpopup", "bg", "default");
1061    edje_object_signal_callback_add
1062      (priv->bg, "elm,action,click", "", _bg_clicked_cb, obj);
1063
1064    evas_object_stack_below(priv->bg, obj);
1065
1066    //Arrow
1067    priv->arrow = edje_object_add(evas_object_evas_get(obj));
1068    elm_widget_theme_object_set
1069      (obj, priv->arrow, "ctxpopup", "arrow", "default");
1070
1071    priv->dir_priority[0] = ELM_CTXPOPUP_DIRECTION_UP;
1072    priv->dir_priority[1] = ELM_CTXPOPUP_DIRECTION_LEFT;
1073    priv->dir_priority[2] = ELM_CTXPOPUP_DIRECTION_RIGHT;
1074    priv->dir_priority[3] = ELM_CTXPOPUP_DIRECTION_DOWN;
1075    priv->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1076
1077    evas_object_event_callback_add
1078      (obj, EVAS_CALLBACK_RESTACK, _ctxpopup_restack_cb, obj);
1079
1080    priv->box = elm_box_add(obj);
1081    evas_object_size_hint_weight_set
1082      (priv->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1083
1084    evas_object_event_callback_add
1085      (priv->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1086
1087    /* box will be our content placeholder, thus the parent's version call */
1088    Eina_Bool ret;
1089    eo_do_super(obj, elm_obj_container_content_set("elm.swallow.content", priv->box, &ret));
1090
1091    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW, _on_show, NULL);
1092    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE, _on_hide, NULL);
1093    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _on_move, NULL);
1094
1095    elm_widget_can_focus_set(obj, EINA_TRUE);
1096 }
1097
1098 static void
1099 _elm_ctxpopup_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
1100 {
1101    Elm_Ctxpopup_Smart_Data *sd = _pd;
1102    Elm_Ctxpopup_Item *it;
1103
1104    evas_object_event_callback_del_full
1105      (sd->box, EVAS_CALLBACK_RESIZE, _on_content_resized, obj);
1106    _parent_detach(obj);
1107
1108    elm_ctxpopup_clear(obj);
1109    evas_object_del(sd->arrow);
1110    sd->arrow = NULL; /* stops _sizing_eval() from going on on deletion */
1111
1112    evas_object_del(sd->bg);
1113    sd->bg = NULL;
1114
1115    EINA_LIST_FREE (sd->items, it)
1116      elm_widget_item_free(it);
1117
1118    eo_do_super(obj, evas_obj_smart_del());
1119 }
1120
1121 static void
1122 _elm_ctxpopup_smart_parent_set(Eo *obj, void *_pd EINA_UNUSED, va_list *list)
1123 {
1124    Evas_Object *parent = va_arg(*list, Evas_Object *);
1125    //default parent is to be hover parent
1126    elm_ctxpopup_hover_parent_set(obj, parent);
1127 }
1128
1129 EAPI Evas_Object *
1130 elm_ctxpopup_add(Evas_Object *parent)
1131 {
1132    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1133    Evas_Object *obj = eo_add(MY_CLASS, parent);
1134    eo_unref(obj);
1135
1136    /* access: parent could be any object such as elm_list which does
1137       not know elc_ctxpopup as its child object in the focus_next(); */
1138    Elm_Widget_Smart_Data *wd = eo_data_get(obj, ELM_OBJ_WIDGET_CLASS);
1139    wd->highlight_root = EINA_TRUE;
1140
1141    return obj;
1142 }
1143
1144 static void
1145 _constructor(Eo *obj, void *_pd EINA_UNUSED, va_list *list EINA_UNUSED)
1146 {
1147    eo_do_super(obj, eo_constructor());
1148    eo_do(obj,
1149          evas_obj_type_set(MY_CLASS_NAME),
1150          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks, NULL));
1151
1152    if (!elm_widget_sub_object_add(eo_parent_get(obj), obj))
1153      ERR("could not add %p as sub object of %p", obj, eo_parent_get(obj));
1154 }
1155
1156 EAPI void
1157 elm_ctxpopup_hover_parent_set(Evas_Object *obj,
1158                               Evas_Object *parent)
1159 {
1160    ELM_CTXPOPUP_CHECK(obj);
1161    eo_do(obj, elm_obj_ctxpopup_hover_parent_set(parent));
1162 }
1163
1164 static void
1165 _hover_parent_set(Eo *obj, void *_pd, va_list *list)
1166 {
1167    Evas_Coord x, y, w, h;
1168    Evas_Object *parent = va_arg(*list, Evas_Object *);
1169
1170    Elm_Ctxpopup_Smart_Data *sd = _pd;
1171
1172    if (!parent) return;
1173
1174    _parent_detach(obj);
1175
1176    evas_object_event_callback_add
1177      (parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
1178    evas_object_event_callback_add
1179      (parent, EVAS_CALLBACK_MOVE, _on_parent_move, obj);
1180    evas_object_event_callback_add
1181      (parent, EVAS_CALLBACK_RESIZE, _on_parent_resize, obj);
1182
1183    sd->parent = parent;
1184
1185    //Update Background
1186    evas_object_geometry_get(parent, &x, &y, &w, &h);
1187    evas_object_move(sd->bg, x, y);
1188    evas_object_resize(sd->bg, w, h);
1189
1190    if (sd->visible) elm_layout_sizing_eval(obj);
1191 }
1192
1193 EAPI Evas_Object *
1194 elm_ctxpopup_hover_parent_get(const Evas_Object *obj)
1195 {
1196    ELM_CTXPOPUP_CHECK(obj) NULL;
1197    Evas_Object *ret = NULL;
1198    eo_do((Eo *) obj, elm_obj_ctxpopup_hover_parent_get(&ret));
1199    return ret;
1200 }
1201
1202 static void
1203 _hover_parent_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
1204 {
1205    Evas_Object **ret = va_arg(*list, Evas_Object **);
1206    Elm_Ctxpopup_Smart_Data *sd = _pd;
1207    *ret = sd->parent;
1208 }
1209
1210 EAPI void
1211 elm_ctxpopup_clear(Evas_Object *obj)
1212 {
1213    ELM_CTXPOPUP_CHECK(obj);
1214    eo_do(obj, elm_obj_ctxpopup_clear());
1215 }
1216
1217 static void
1218 _clear(Eo *obj EINA_UNUSED, void *_pd, va_list *list EINA_UNUSED)
1219 {
1220    Elm_Ctxpopup_Smart_Data *sd = _pd;
1221
1222    _list_del(sd);
1223    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1224 }
1225
1226 EAPI void
1227 elm_ctxpopup_horizontal_set(Evas_Object *obj,
1228                             Eina_Bool horizontal)
1229 {
1230    ELM_CTXPOPUP_CHECK(obj);
1231    eo_do(obj, elm_obj_ctxpopup_horizontal_set(horizontal));
1232 }
1233
1234 static void
1235 _horizontal_set(Eo *obj, void *_pd, va_list *list)
1236 {
1237    Eina_Bool horizontal = va_arg(*list, int);
1238    Elm_Ctxpopup_Smart_Data *sd = _pd;
1239
1240    sd->horizontal = !!horizontal;
1241
1242    if (!sd->list) return;
1243
1244    elm_list_horizontal_set(sd->list, sd->horizontal);
1245
1246    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1247
1248    if (sd->visible) elm_layout_sizing_eval(obj);
1249 }
1250
1251 EAPI Eina_Bool
1252 elm_ctxpopup_horizontal_get(const Evas_Object *obj)
1253 {
1254    ELM_CTXPOPUP_CHECK(obj) EINA_FALSE;
1255    Eina_Bool ret = EINA_FALSE;
1256    eo_do((Eo *) obj, elm_obj_ctxpopup_horizontal_get(&ret));
1257    return ret;
1258 }
1259
1260 static void
1261 _horizontal_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
1262 {
1263    Eina_Bool *ret = va_arg(*list, Eina_Bool *);
1264    Elm_Ctxpopup_Smart_Data *sd = _pd;
1265
1266    *ret = sd->horizontal;
1267 }
1268
1269 EAPI Elm_Object_Item *
1270 elm_ctxpopup_item_append(Evas_Object *obj,
1271                          const char *label,
1272                          Evas_Object *icon,
1273                          Evas_Smart_Cb func,
1274                          const void *data)
1275 {
1276
1277    ELM_CTXPOPUP_CHECK(obj) NULL;
1278    Elm_Object_Item *ret = NULL;
1279    eo_do(obj, elm_obj_ctxpopup_item_append(label, icon, func, data, &ret));
1280    return ret;
1281 }
1282
1283 static void
1284 _item_wrap_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
1285 {
1286    Elm_Ctxpopup_Item *item = data;
1287    item->wcb.org_func_cb((void *)item->wcb.org_data, item->wcb.cobj, item);
1288 }
1289
1290 static void
1291 _item_append(Eo *obj, void *_pd, va_list *list)
1292 {
1293    const char *label = va_arg(*list, const char *);
1294    Evas_Object *icon = va_arg(*list, Evas_Object *);
1295    Evas_Smart_Cb func = va_arg(*list, Evas_Smart_Cb);
1296    const void *data = va_arg(*list, const void *);
1297    Elm_Object_Item **ret = va_arg(*list, Elm_Object_Item **);
1298    *ret = NULL;
1299
1300    Elm_Ctxpopup_Item *item;
1301
1302    Elm_Ctxpopup_Smart_Data *sd = _pd;
1303
1304    item = elm_widget_item_new(obj, Elm_Ctxpopup_Item);
1305    if (!item) return;
1306
1307    elm_widget_item_del_pre_hook_set(item, _item_del_pre_hook);
1308    elm_widget_item_disable_hook_set(item, _item_disable_hook);
1309    elm_widget_item_text_set_hook_set(item, _item_text_set_hook);
1310    elm_widget_item_text_get_hook_set(item, _item_text_get_hook);
1311    elm_widget_item_content_set_hook_set(item, _item_content_set_hook);
1312    elm_widget_item_content_get_hook_set(item, _item_content_get_hook);
1313    elm_widget_item_signal_emit_hook_set(item, _item_signal_emit_hook);
1314
1315    if (!sd->list)
1316      {
1317         //The first item is appended.
1318         sd->list = elm_list_add(obj);
1319         elm_list_mode_set(sd->list, ELM_LIST_EXPAND);
1320         elm_list_horizontal_set(sd->list, sd->horizontal);
1321         evas_object_event_callback_add
1322           (sd->list, EVAS_CALLBACK_RESIZE, _list_resize_cb, obj);
1323         elm_layout_content_set(obj, "default", sd->list);
1324      }
1325
1326    item->wcb.org_func_cb = func;
1327    item->wcb.org_data = data;
1328    item->wcb.cobj = obj;
1329    item->list_item =
1330      elm_list_item_append(sd->list, label, icon, NULL, _item_wrap_cb, item);
1331    sd->items = eina_list_append(sd->items, item);
1332
1333    sd->dir = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1334
1335    if (sd->visible) elm_layout_sizing_eval(obj);
1336
1337    *ret = (Elm_Object_Item *)item;
1338 }
1339
1340 EAPI void
1341 elm_ctxpopup_direction_priority_set(Evas_Object *obj,
1342                                     Elm_Ctxpopup_Direction first,
1343                                     Elm_Ctxpopup_Direction second,
1344                                     Elm_Ctxpopup_Direction third,
1345                                     Elm_Ctxpopup_Direction fourth)
1346 {
1347    ELM_CTXPOPUP_CHECK(obj);
1348    eo_do(obj, elm_obj_ctxpopup_direction_priority_set(first, second, third, fourth));
1349 }
1350
1351 static void
1352 _direction_priority_set(Eo *obj, void *_pd, va_list *list)
1353 {
1354    Elm_Ctxpopup_Direction first = va_arg(*list, Elm_Ctxpopup_Direction);
1355    Elm_Ctxpopup_Direction second = va_arg(*list, Elm_Ctxpopup_Direction);
1356    Elm_Ctxpopup_Direction third = va_arg(*list, Elm_Ctxpopup_Direction);
1357    Elm_Ctxpopup_Direction fourth = va_arg(*list, Elm_Ctxpopup_Direction);
1358
1359    Elm_Ctxpopup_Smart_Data *sd = _pd;
1360
1361    sd->dir_priority[0] = first;
1362    sd->dir_priority[1] = second;
1363    sd->dir_priority[2] = third;
1364    sd->dir_priority[3] = fourth;
1365
1366    if (sd->visible) elm_layout_sizing_eval(obj);
1367 }
1368
1369 EAPI void
1370 elm_ctxpopup_direction_priority_get(Evas_Object *obj,
1371                                     Elm_Ctxpopup_Direction *first,
1372                                     Elm_Ctxpopup_Direction *second,
1373                                     Elm_Ctxpopup_Direction *third,
1374                                     Elm_Ctxpopup_Direction *fourth)
1375 {
1376    ELM_CTXPOPUP_CHECK(obj);
1377    eo_do(obj, elm_obj_ctxpopup_direction_priority_get(first, second, third, fourth));
1378 }
1379
1380 static void
1381 _direction_priority_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
1382 {
1383    Elm_Ctxpopup_Direction *first = va_arg(*list, Elm_Ctxpopup_Direction *);
1384    Elm_Ctxpopup_Direction *second = va_arg(*list, Elm_Ctxpopup_Direction *);
1385    Elm_Ctxpopup_Direction *third = va_arg(*list, Elm_Ctxpopup_Direction *);
1386    Elm_Ctxpopup_Direction *fourth = va_arg(*list, Elm_Ctxpopup_Direction *);
1387
1388    Elm_Ctxpopup_Smart_Data *sd = _pd;
1389
1390    if (first) *first = sd->dir_priority[0];
1391    if (second) *second = sd->dir_priority[1];
1392    if (third) *third = sd->dir_priority[2];
1393    if (fourth) *fourth = sd->dir_priority[3];
1394 }
1395
1396 EAPI Elm_Ctxpopup_Direction
1397 elm_ctxpopup_direction_get(const Evas_Object *obj)
1398 {
1399    ELM_CTXPOPUP_CHECK(obj) ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1400    Elm_Ctxpopup_Direction ret = ELM_CTXPOPUP_DIRECTION_UNKNOWN;
1401    eo_do((Eo *) obj, elm_obj_ctxpopup_direction_get(&ret));
1402    return ret;
1403 }
1404
1405 static void
1406 _direction_get(Eo *obj EINA_UNUSED, void *_pd, va_list *list)
1407 {
1408    Elm_Ctxpopup_Direction *ret = va_arg(*list, Elm_Ctxpopup_Direction *);
1409    Elm_Ctxpopup_Smart_Data *sd = _pd;
1410
1411    *ret = sd->dir;
1412 }
1413
1414 EAPI void
1415 elm_ctxpopup_dismiss(Evas_Object *obj)
1416 {
1417    ELM_CTXPOPUP_CHECK(obj);
1418    eo_do(obj, elm_obj_ctxpopup_dismiss());
1419 }
1420
1421 static void
1422 _dismiss(Eo *obj, void *_pd, va_list *list EINA_UNUSED)
1423 {
1424    Elm_Ctxpopup_Smart_Data *sd = _pd;
1425
1426    _hide_signals_emit(obj, sd->dir);
1427 }
1428
1429 static void
1430 _class_constructor(Eo_Class *klass)
1431 {
1432    const Eo_Op_Func_Description func_desc[] = {
1433         EO_OP_FUNC(EO_BASE_ID(EO_BASE_SUB_ID_CONSTRUCTOR), _constructor),
1434
1435         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_ADD), _elm_ctxpopup_smart_add),
1436         EO_OP_FUNC(EVAS_OBJ_SMART_ID(EVAS_OBJ_SMART_SUB_ID_DEL), _elm_ctxpopup_smart_del),
1437
1438         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_PARENT_SET), _elm_ctxpopup_smart_parent_set),
1439         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_DISABLE), _elm_ctxpopup_smart_disable),
1440         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_EVENT), _elm_ctxpopup_smart_event),
1441         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_THEME), _elm_ctxpopup_smart_theme),
1442         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_SUB_OBJECT_ADD), _elm_ctxpopup_smart_sub_object_add),
1443         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT_MANAGER_IS), _elm_ctxpopup_smart_focus_next_manager_is),
1444         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_NEXT),  _elm_ctxpopup_smart_focus_next),
1445         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_FOCUS_DIRECTION_MANAGER_IS), _elm_ctxpopup_smart_focus_direction_manager_is),
1446         EO_OP_FUNC(ELM_WIDGET_ID(ELM_WIDGET_SUB_ID_TRANSLATE), _elm_ctxpopup_smart_translate),
1447
1448         EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_SET), _elm_ctxpopup_smart_content_set),
1449         EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_GET), _elm_ctxpopup_smart_content_get),
1450         EO_OP_FUNC(ELM_OBJ_CONTAINER_ID(ELM_OBJ_CONTAINER_SUB_ID_CONTENT_UNSET), _elm_ctxpopup_smart_content_unset),
1451
1452         EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SIZING_EVAL), _elm_ctxpopup_smart_sizing_eval),
1453         EO_OP_FUNC(ELM_OBJ_LAYOUT_ID(ELM_OBJ_LAYOUT_SUB_ID_SUB_OBJECT_ADD_ENABLE), _elm_ctxpopup_smart_layout_sub_object_add_enable),
1454
1455         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_HOVER_PARENT_SET), _hover_parent_set),
1456         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_HOVER_PARENT_GET), _hover_parent_get),
1457         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_CLEAR), _clear),
1458         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_HORIZONTAL_SET), _horizontal_set),
1459         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_HORIZONTAL_GET), _horizontal_get),
1460         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_ITEM_APPEND), _item_append),
1461         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_PRIORITY_SET), _direction_priority_set),
1462         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_PRIORITY_GET), _direction_priority_get),
1463         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_GET), _direction_get),
1464         EO_OP_FUNC(ELM_OBJ_CTXPOPUP_ID(ELM_OBJ_CTXPOPUP_SUB_ID_DISMISS), _dismiss),
1465         EO_OP_FUNC_SENTINEL
1466    };
1467    eo_class_funcs_set(klass, func_desc);
1468
1469    evas_smart_legacy_type_register(MY_CLASS_NAME, klass);
1470 }
1471 static const Eo_Op_Description op_desc[] = {
1472      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_HOVER_PARENT_SET, "Set the Ctxpopup's parent."),
1473      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_HOVER_PARENT_GET, "Get the Ctxpopup's parent."),
1474      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_CLEAR, "Clear all items in the given ctxpopup object."),
1475      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_HORIZONTAL_SET, "Change the ctxpopup's orientation to horizontal or vertical."),
1476      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_HORIZONTAL_GET, "Get the value of current ctxpopup object's orientation."),
1477      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_ITEM_APPEND, "Add a new item to a ctxpopup object."),
1478      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_PRIORITY_SET, "Set the direction priority of a ctxpopup."),
1479      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_PRIORITY_GET, "Get the direction priority of a ctxpopup."),
1480      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_DIRECTION_GET, "Get the current direction of a ctxpopup."),
1481      EO_OP_DESCRIPTION(ELM_OBJ_CTXPOPUP_SUB_ID_DISMISS, "Dismiss a ctxpopup object."),
1482      EO_OP_DESCRIPTION_SENTINEL
1483 };
1484 static const Eo_Class_Description class_desc = {
1485      EO_VERSION,
1486      MY_CLASS_NAME,
1487      EO_CLASS_TYPE_REGULAR,
1488      EO_CLASS_DESCRIPTION_OPS(&ELM_OBJ_CTXPOPUP_BASE_ID, op_desc, ELM_OBJ_CTXPOPUP_SUB_ID_LAST),
1489      NULL,
1490      sizeof(Elm_Ctxpopup_Smart_Data),
1491      _class_constructor,
1492      NULL
1493 };
1494 EO_DEFINE_CLASS(elm_obj_ctxpopup_class_get, &class_desc, ELM_OBJ_LAYOUT_CLASS, NULL);