popup: add keybinding for popup "block,clicked" action
[platform/upstream/elementary.git] / src / lib / elc_hoversel.c
1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4
5 #define ELM_INTERFACE_ATSPI_ACCESSIBLE_PROTECTED
6 #define ELM_INTERFACE_ATSPI_WIDGET_ACTION_PROTECTED
7
8 #define ELM_WIDGET_ITEM_PROTECTED
9 #include <Elementary.h>
10 #include "elm_priv.h"
11 #include "elm_widget_hoversel.h"
12
13 #define MY_CLASS ELM_HOVERSEL_CLASS
14
15 #define MY_CLASS_NAME "Elm_Hoversel"
16 #define MY_CLASS_NAME_LEGACY "elm_hoversel"
17
18 static const char SIG_SELECTED[] = "selected";
19 static const char SIG_DISMISSED[] = "dismissed";
20 static const char SIG_EXPANDED[] = "expanded";
21 static const char SIG_ITEM_FOCUSED[] = "item,focused";
22 static const char SIG_ITEM_UNFOCUSED[] = "item,unfocused";
23
24 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
25    {SIG_SELECTED, ""},
26    {SIG_DISMISSED, ""},
27    {SIG_EXPANDED, ""},
28    {SIG_ITEM_FOCUSED, ""},
29    {SIG_ITEM_UNFOCUSED, ""},
30    {"clicked", ""}, /**< handled by parent button class */
31    {SIG_WIDGET_LANG_CHANGED, ""}, /**< handled by elm_widget */
32    {SIG_WIDGET_ACCESS_CHANGED, ""}, /**< handled by elm_widget */
33    {NULL, NULL}
34 };
35
36 static Eina_Bool _key_action_move(Evas_Object *obj, const char *params);
37 static Eina_Bool _key_action_activate(Evas_Object *obj, const char *params);
38
39 static const Elm_Action key_actions[] = {
40    {"move", _key_action_move},
41    {"activate", _key_action_activate},
42    {NULL, NULL}
43 };
44
45 EOLIAN static Eina_Bool
46 _elm_hoversel_elm_widget_translate(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
47 {
48    Eo *it;
49    Eina_List *l;
50
51    EINA_LIST_FOREACH(sd->items, l, it)
52      eo_do(it, elm_wdg_item_translate());
53
54    eo_do_super(obj, MY_CLASS, elm_obj_widget_translate());
55
56    return EINA_TRUE;
57 }
58
59 EOLIAN static Eina_Bool
60 _elm_hoversel_elm_widget_theme_apply(Eo *obj, Elm_Hoversel_Data *sd)
61 {
62    Eina_Bool int_ret = EINA_FALSE;
63
64    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, EINA_FALSE);
65
66    char buf[4096];
67    const char *style;
68
69    style = eina_stringshare_add(elm_widget_style_get(obj));
70
71    if (sd->horizontal)
72      snprintf(buf, sizeof(buf), "hoversel_horizontal/%s", style);
73    else
74      snprintf(buf, sizeof(buf), "hoversel_vertical/%s", style);
75
76    /* hoversel's style has an extra bit: orientation */
77    eina_stringshare_replace(&(wd->style), buf);
78
79    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_theme_apply());
80    if (!int_ret) return EINA_FALSE;
81
82    eina_stringshare_replace(&(wd->style), style);
83
84    eina_stringshare_del(style);
85
86    if (sd->hover)
87      elm_widget_mirrored_set(sd->hover, elm_widget_mirrored_get(obj));
88
89    elm_hoversel_hover_end(obj);
90
91    return EINA_TRUE;
92 }
93
94 static Eina_Bool
95 _on_hover_clicked(void *data EINA_UNUSED,
96                      Eo *obj, const Eo_Event_Description *desc EINA_UNUSED,
97                      void *event_info EINA_UNUSED)
98 {
99    const char *dismissstr;
100
101    dismissstr = edje_object_data_get(elm_layout_edje_get(obj), "dismiss");
102
103    if (!dismissstr || strcmp(dismissstr, "on"))
104      elm_hoversel_hover_end(data); // for backward compatibility
105
106    return EINA_TRUE;
107 }
108
109 static Eina_Bool
110 _on_item_clicked(void *data EINA_UNUSED,
111                      Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
112                      void *event_info EINA_UNUSED)
113 {
114    Elm_Hoversel_Item_Data *item = data;
115    Evas_Object *obj2 = WIDGET(item);
116    Elm_Object_Item *eo_it = EO_OBJ(item);
117
118    ELM_HOVERSEL_DATA_GET(obj2, sd);
119
120    if (item->func) item->func((void *)WIDGET_ITEM_DATA_GET(eo_it), obj2, eo_it);
121    eo_do(obj2, eo_event_callback_call(EVAS_SELECTABLE_INTERFACE_EVENT_SELECTED, eo_it));
122
123    if (sd->auto_update)
124      {
125         Evas_Object *ic;
126
127         ic = elm_object_part_content_unset(obj2, "icon");
128         ELM_SAFE_FREE(ic, evas_object_del);
129
130         if (item->icon_file)
131           {
132              ic = elm_icon_add(obj2);
133              elm_image_resizable_set(ic, EINA_FALSE, EINA_TRUE);
134              if (item->icon_type == ELM_ICON_FILE)
135                elm_image_file_set(ic, item->icon_file, item->icon_group);
136              else if (item->icon_type == ELM_ICON_STANDARD)
137                elm_icon_standard_set(ic, item->icon_file);
138              elm_object_part_content_set(obj2, "icon", ic);
139           }
140
141         if(item->label)
142           elm_object_text_set(obj2, item->label);
143      }
144
145    elm_hoversel_hover_end(obj2);
146
147    return EINA_TRUE;
148 }
149
150 static Eina_Bool
151 _item_focused_cb(void *data EINA_UNUSED,
152                      Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
153                      void *event_info EINA_UNUSED)
154 {
155    Elm_Hoversel_Item_Data *it = data;
156
157    eo_do(WIDGET(it), eo_event_callback_call(ELM_HOVERSEL_EVENT_ITEM_FOCUSED, EO_OBJ(it)));
158
159    return EINA_TRUE;
160 }
161
162 static Eina_Bool
163 _item_unfocused_cb(void *data EINA_UNUSED,
164                    Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
165                    void *event_info EINA_UNUSED)
166 {
167    Elm_Hoversel_Item_Data *it = data;
168
169    eo_do(WIDGET(it), eo_event_callback_call(ELM_HOVERSEL_EVENT_ITEM_UNFOCUSED, EO_OBJ(it)));
170
171    return EINA_TRUE;
172 }
173
174 static void
175 _create_scroller(Evas_Object *obj, Elm_Hoversel_Data *sd)
176 {
177    //table
178    sd->tbl = elm_table_add(obj);
179
180    //spacer
181    sd->spacer = evas_object_rectangle_add(evas_object_evas_get(obj));
182    evas_object_color_set(sd->spacer, 0, 0, 0, 0);
183    elm_table_pack(sd->tbl, sd->spacer, 0, 0, 1, 1);
184
185    //Scroller
186    sd->scr = elm_scroller_add(sd->tbl);
187    elm_object_style_set(sd->scr, "popup/no_inset_shadow");
188    evas_object_size_hint_weight_set(sd->scr, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
189    evas_object_size_hint_align_set(sd->scr, EVAS_HINT_FILL, EVAS_HINT_FILL);
190    if (sd->horizontal)
191      {
192         elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
193         elm_scroller_content_min_limit(sd->scr, EINA_FALSE, EINA_TRUE);
194         elm_scroller_bounce_set(sd->scr, EINA_TRUE, EINA_FALSE);
195      }
196    else
197      {
198         elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
199         elm_scroller_content_min_limit(sd->scr, EINA_TRUE, EINA_FALSE);
200         elm_scroller_bounce_set(sd->scr, EINA_FALSE, EINA_TRUE);
201      }
202    elm_table_pack(sd->tbl, sd->scr, 0, 0, 1, 1);
203    evas_object_show(sd->scr);
204 }
205
206 static void
207 _resizing_eval(Evas_Object *obj, Elm_Hoversel_Data *sd)
208 {
209    Evas_Object *bx = NULL;
210    const char *max_size_str;
211    int max_size = 0;
212    char buf[128];
213    Evas_Coord box_w = -1, box_h = -1;
214    Evas_Coord x, y, w, h, xx, yy, ww, hh, vw = 0, vh = 0;
215    double align_x;
216    Eina_List *l;
217    Evas_Object *it;
218    Evas_Coord obj_x, obj_y, obj_w, obj_h, it_w, it_h;
219
220    if (sd->scr)
221      bx = elm_object_content_get(sd->scr);
222
223    if ((!sd->expanded) || (!bx)) return;
224
225    edje_object_size_min_calc(elm_layout_edje_get(sd->scr), &vw, &vh);
226    evas_object_geometry_get(obj, &obj_x, &obj_y, &obj_w, &obj_h);
227
228    evas_object_size_hint_align_get(obj, &align_x, NULL);
229    if (!sd->horizontal && align_x == EVAS_HINT_FILL)
230      {
231         l = elm_box_children_get(bx);
232         EINA_LIST_FREE(l, it)
233           {
234              edje_object_size_min_calc(elm_layout_edje_get(it), &it_w, &it_h);
235              if ((obj_w - vw) > it_w)
236                evas_object_size_hint_min_set(it, (obj_w - vw), it_h);
237              else
238                evas_object_size_hint_min_set(it, it_w, it_h);
239           }
240      }
241
242    elm_box_recalculate(bx);
243    evas_object_size_hint_min_get(bx, &box_w, &box_h);
244
245    box_w += vw;
246    box_h += vh;
247
248    max_size_str = edje_object_data_get(elm_layout_edje_get(sd->hover), "max_size");
249    if (max_size_str)
250      max_size = (int)(atoi(max_size_str)
251                       * elm_config_scale_get()
252                       * elm_object_scale_get(obj))
253                       / edje_object_base_scale_get(elm_layout_edje_get(sd->hover));
254
255    if (sd->horizontal)
256      {
257         ww = (max_size > 0) ? MIN(box_w, max_size) : box_w ;
258         hh = box_h;
259
260         evas_object_size_hint_min_set(sd->spacer, ww, hh);
261
262         if (!sd->last_location)
263           sd->last_location = elm_hover_best_content_location_get(sd->hover, ELM_HOVER_AXIS_HORIZONTAL);
264      }
265    else
266      {
267         ww = box_w;
268         hh = (max_size > 0) ? MIN(box_h, max_size) : box_h ;
269
270         evas_object_size_hint_min_set(sd->spacer, ww, hh);
271
272         if (!sd->last_location)
273           sd->last_location = elm_hover_best_content_location_get(sd->hover, ELM_HOVER_AXIS_VERTICAL);
274      }
275
276    evas_object_geometry_get(sd->hover_parent, &x, &y, &w, &h);
277    if (eo_isa(sd->hover_parent, ELM_WIN_CLASS))
278      {
279         x = 0;
280         y = 0;
281      }
282
283    snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", sd->last_location);
284    edje_object_part_geometry_get(elm_layout_edje_get(sd->hover), buf, &xx, &yy, NULL, NULL);
285    xx += x;
286    yy += y;
287
288    if (sd->horizontal)
289      {
290         if (xx < obj_x)
291           {
292              xx = x;
293              if ((xx + ww) > obj_x)
294                ww = obj_x - xx;
295           }
296         else
297           {
298              if ((xx + ww) > (x + w))
299                ww = (x + w) - xx;
300           }
301
302         if (yy < 0) yy = y;
303         if ((yy + hh) > (y + h))
304           hh = (y + h) - yy;
305      }
306    else
307      {
308         if (yy < obj_y)
309           {
310              yy = y;
311              if ((yy + hh) > obj_y)
312                hh = obj_y - yy;
313           }
314         else
315           {
316              if ((yy + hh) > (y + h))
317                hh = (y + h) - yy;
318           }
319
320         if (xx < 0) xx = x;
321         if ((xx + ww) > (x + w))
322           ww = (x + w) - xx;
323      }
324
325    evas_object_size_hint_min_set(sd->spacer, ww, hh);
326 }
327
328 static void
329 _hover_end_finished(void *data,
330                     Evas_Object *obj EINA_UNUSED,
331                     const char *emission EINA_UNUSED,
332                     const char *source EINA_UNUSED)
333 {
334    Elm_Object_Item *eo_item;
335    Eina_List *l;
336    const char *dismissstr;
337
338    ELM_HOVERSEL_DATA_GET(data, sd);
339
340    dismissstr = edje_object_data_get(elm_layout_edje_get(sd->hover), "dismiss");
341
342    if (dismissstr && !strcmp(dismissstr, "on"))
343      {
344         sd->expanded = EINA_FALSE;
345
346         EINA_LIST_FOREACH(sd->items, l, eo_item)
347           {
348              ELM_HOVERSEL_ITEM_DATA_GET(eo_item, it);
349              VIEW(it) = NULL;
350           }
351         ELM_SAFE_FREE(sd->hover, evas_object_del);
352         sd->scr = NULL;
353         sd->last_location = NULL;
354
355         eo_do(data, eo_event_callback_call(ELM_HOVERSEL_EVENT_DISMISSED, NULL));
356      }
357 }
358
359 static void
360 _activate(Evas_Object *obj)
361 {
362    Elm_Object_Item *eo_item;
363    Evas_Object *bt, *bx, *ic;
364    const Eina_List *l;
365    char buf[4096];
366
367    ELM_HOVERSEL_DATA_GET(obj, sd);
368
369    if (sd->expanded)
370      {
371         elm_hoversel_hover_end(obj);
372         return;
373      }
374    sd->expanded = EINA_TRUE;
375
376    if (elm_widget_disabled_get(obj)) return;
377
378    sd->hover = elm_hover_add(sd->hover_parent);
379    elm_widget_sub_object_add(obj, sd->hover);
380
381    if (sd->horizontal)
382      snprintf(buf, sizeof(buf), "hoversel_horizontal/%s",
383               elm_widget_style_get(obj));
384    else
385      snprintf(buf, sizeof(buf), "hoversel_vertical/%s",
386               elm_widget_style_get(obj));
387
388    elm_object_style_set(sd->hover, buf);
389
390    eo_do(sd->hover, eo_event_callback_add
391      (EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED, _on_hover_clicked, obj));
392    elm_layout_signal_callback_add
393      (sd->hover, "elm,action,hide,finished", "elm", _hover_end_finished, obj);
394    elm_hover_target_set(sd->hover, obj);
395
396    /* hover's content */
397    bx = elm_box_add(sd->hover);
398    elm_box_homogeneous_set(bx, EINA_TRUE);
399    elm_box_horizontal_set(bx, sd->horizontal);
400
401    if (sd->horizontal)
402      snprintf(buf, sizeof(buf), "hoversel_horizontal_entry/%s",
403               elm_widget_style_get(obj));
404    else
405      snprintf(buf, sizeof(buf), "hoversel_vertical_entry/%s",
406               elm_widget_style_get(obj));
407
408    EINA_LIST_FOREACH(sd->items, l, eo_item)
409      {
410         ELM_HOVERSEL_ITEM_DATA_GET(eo_item, item);
411         VIEW(item) = bt = elm_button_add(bx);
412         elm_widget_mirrored_set(bt, elm_widget_mirrored_get(obj));
413         elm_object_style_set(bt, buf);
414         elm_object_text_set(bt, item->label);
415
416         if (item->icon_file)
417           {
418              ic = elm_icon_add(bt);
419              elm_image_resizable_set(ic, EINA_FALSE, EINA_TRUE);
420              if (item->icon_type == ELM_ICON_FILE)
421                elm_image_file_set(ic, item->icon_file, item->icon_group);
422              else if (item->icon_type == ELM_ICON_STANDARD)
423                elm_icon_standard_set(ic, item->icon_file);
424              elm_object_part_content_set(bt, "icon", ic);
425           }
426
427         evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
428         evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
429         elm_box_pack_end(bx, bt);
430         eo_do(bt, eo_event_callback_add
431           (EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED, _on_item_clicked, item));
432         evas_object_show(bt);
433         eo_do(bt,
434               eo_event_callback_add(ELM_WIDGET_EVENT_FOCUSED, _item_focused_cb, item),
435               eo_event_callback_add(ELM_WIDGET_EVENT_UNFOCUSED, _item_unfocused_cb, item));
436      }
437
438    _create_scroller(obj, sd);
439    elm_object_content_set(sd->scr, bx);
440
441    _resizing_eval(obj, sd);
442    elm_object_part_content_set(sd->hover, sd->last_location, sd->tbl);
443
444    eo_do(obj, eo_event_callback_call(ELM_HOVERSEL_EVENT_EXPANDED, NULL));
445    evas_object_show(sd->hover);
446 }
447
448 static Eina_Bool
449 _on_clicked(void *data EINA_UNUSED,
450             Eo *obj EINA_UNUSED, const Eo_Event_Description *desc EINA_UNUSED,
451             void *event_info EINA_UNUSED)
452 {
453    _activate(data);
454
455    return EINA_TRUE;
456 }
457
458 static void
459 _on_parent_del(void *data,
460                Evas *e EINA_UNUSED,
461                Evas_Object *obj EINA_UNUSED,
462                void *event_info EINA_UNUSED)
463 {
464    elm_hoversel_hover_parent_set(data, NULL);
465 }
466
467 static void
468 _elm_hoversel_item_elm_widget_item_part_text_set(Eo *eo_it EINA_UNUSED,
469                                             Elm_Hoversel_Item_Data *it,
470                                             const char *part,
471                                             const char *label)
472 {
473    if (part && strcmp(part, "default")) return;
474    eina_stringshare_replace(&it->label, label);
475
476    if (VIEW(it))
477      elm_object_text_set(VIEW(it), label);
478 }
479
480 static const char *
481 _elm_hoversel_item_elm_widget_item_part_text_get(Eo *eo_it EINA_UNUSED,
482                                             Elm_Hoversel_Item_Data *it,
483                                             const char *part)
484 {
485    if (part && strcmp(part, "default")) return NULL;
486    return it->label;
487 }
488
489 EOLIAN static void
490 _elm_hoversel_item_elm_widget_item_signal_emit(Eo *eo_it EINA_UNUSED,
491                                          Elm_Hoversel_Item_Data *it,
492                                          const char *emission,
493                                          const char *source)
494 {
495    elm_object_signal_emit(VIEW(it), emission, source);
496 }
497
498 EOLIAN static void
499 _elm_hoversel_item_elm_widget_item_style_set(Eo *eo_it EINA_UNUSED,
500                                              Elm_Hoversel_Item_Data *it,
501                                              const char *style)
502 {
503    elm_object_style_set(VIEW(it), style);
504 }
505
506 EOLIAN static const char *
507 _elm_hoversel_item_elm_widget_item_style_get(Eo *eo_it EINA_UNUSED,
508                                              Elm_Hoversel_Item_Data *it)
509 {
510    return elm_object_style_get(VIEW(it));
511 }
512
513 EOLIAN static void
514 _elm_hoversel_item_elm_widget_item_focus_set(Eo *eo_it EINA_UNUSED,
515                                              Elm_Hoversel_Item_Data *it,
516                                              Eina_Bool focused)
517 {
518    elm_object_focus_set(VIEW(it), focused);
519 }
520
521 EOLIAN static Eina_Bool
522 _elm_hoversel_item_elm_widget_item_focus_get(Eo *eo_it EINA_UNUSED,
523                                              Elm_Hoversel_Item_Data *it)
524 {
525    return elm_widget_focus_get(VIEW(it));
526 }
527
528 EOLIAN static void
529 _elm_hoversel_item_eo_base_destructor(Eo *eo_item, Elm_Hoversel_Item_Data *item)
530 {
531    ELM_HOVERSEL_DATA_GET_OR_RETURN(WIDGET(item), sd);
532
533    elm_hoversel_hover_end(WIDGET(item));
534    sd->items = eina_list_remove(sd->items, eo_item);
535    eina_stringshare_del(item->label);
536    eina_stringshare_del(item->icon_file);
537    eina_stringshare_del(item->icon_group);
538
539    eo_do_super(eo_item, ELM_HOVERSEL_ITEM_CLASS, eo_destructor());
540 }
541
542 static void
543 _on_move_resize(void * data,
544            Evas *e EINA_UNUSED,
545            Evas_Object *obj,
546            void *event_info EINA_UNUSED)
547 {
548    Elm_Hoversel_Data *sd = data;
549
550    _resizing_eval(obj, sd);
551 }
552
553 EOLIAN static void
554 _elm_hoversel_evas_object_smart_add(Eo *obj, Elm_Hoversel_Data *priv)
555 {
556    eo_do_super(obj, MY_CLASS, evas_obj_smart_add());
557    elm_widget_sub_object_parent_add(obj);
558
559    eo_do(obj, eo_event_callback_add(
560          EVAS_CLICKABLE_INTERFACE_EVENT_CLICKED, _on_clicked, obj));
561
562    //What are you doing here?
563    eo_do(obj, elm_obj_widget_theme_apply());
564
565    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOVE, _on_move_resize, priv);
566    evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _on_move_resize, priv);
567 }
568
569 EOLIAN static void
570 _elm_hoversel_evas_object_smart_del(Eo *obj, Elm_Hoversel_Data *sd)
571 {
572    Elm_Object_Item *eo_item;
573
574    EINA_LIST_FREE(sd->items, eo_item)
575      {
576         eo_del(eo_item);
577      }
578    elm_hoversel_hover_parent_set(obj, NULL);
579
580    eo_do_super(obj, MY_CLASS, evas_obj_smart_del());
581 }
582
583 EOLIAN static void
584 _elm_hoversel_evas_object_smart_show(Eo *obj, Elm_Hoversel_Data *sd)
585 {
586    eo_do_super(obj, MY_CLASS, evas_obj_smart_show());
587    evas_object_show(sd->hover);
588 }
589
590 EOLIAN static void
591 _elm_hoversel_evas_object_smart_hide(Eo *obj, Elm_Hoversel_Data *sd)
592 {
593    eo_do_super(obj, MY_CLASS, evas_obj_smart_hide());
594    evas_object_hide(sd->hover);
595 }
596
597 EOLIAN static void
598 _elm_hoversel_elm_widget_parent_set(Eo *obj, Elm_Hoversel_Data *_pd EINA_UNUSED, Evas_Object *parent)
599 {
600    elm_hoversel_hover_parent_set(obj, parent);
601 }
602
603 EOLIAN static Eina_Bool
604 _elm_hoversel_elm_button_admits_autorepeat_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd EINA_UNUSED)
605 {
606    return EINA_FALSE;
607 }
608
609 EAPI Evas_Object *
610 elm_hoversel_add(Evas_Object *parent)
611 {
612    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
613    Evas_Object *obj = eo_add(MY_CLASS, parent);
614    return obj;
615 }
616
617 EOLIAN static Eo *
618 _elm_hoversel_eo_base_constructor(Eo *obj, Elm_Hoversel_Data *_pd EINA_UNUSED)
619 {
620    obj = eo_do_super_ret(obj, MY_CLASS, obj, eo_constructor());
621    eo_do(obj,
622          evas_obj_type_set(MY_CLASS_NAME_LEGACY),
623          evas_obj_smart_callbacks_descriptions_set(_smart_callbacks),
624          elm_interface_atspi_accessible_role_set(ELM_ATSPI_ROLE_GLASS_PANE));
625
626    return obj;
627 }
628
629 EOLIAN static void
630 _elm_hoversel_eo_base_destructor(Eo *obj, Elm_Hoversel_Data *_pd EINA_UNUSED)
631 {
632    eo_do(obj, elm_obj_hoversel_clear());
633    eo_do_super(obj, MY_CLASS, eo_destructor());
634 }
635
636 EOLIAN static void
637 _elm_hoversel_hover_parent_set(Eo *obj, Elm_Hoversel_Data *sd, Evas_Object *parent)
638 {
639    if (sd->hover_parent)
640      evas_object_event_callback_del_full
641        (sd->hover_parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
642
643    sd->hover_parent = parent;
644    if (sd->hover_parent)
645      evas_object_event_callback_add
646        (sd->hover_parent, EVAS_CALLBACK_DEL, _on_parent_del, obj);
647 }
648
649 EOLIAN static Evas_Object*
650 _elm_hoversel_hover_parent_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
651 {
652    return sd->hover_parent;
653 }
654
655 EOLIAN static void
656 _elm_hoversel_horizontal_set(Eo *obj, Elm_Hoversel_Data *sd, Eina_Bool horizontal)
657 {
658    sd->horizontal = !!horizontal;
659
660    if (sd->scr)
661      {
662         if (sd->horizontal)
663           {
664              elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_AUTO, ELM_SCROLLER_POLICY_OFF);
665              elm_scroller_content_min_limit(sd->scr, EINA_FALSE, EINA_TRUE);
666              elm_scroller_bounce_set(sd->scr, EINA_TRUE, EINA_FALSE);
667           }
668         else
669           {
670              elm_scroller_policy_set(sd->scr, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_AUTO);
671              elm_scroller_content_min_limit(sd->scr, EINA_TRUE, EINA_FALSE);
672              elm_scroller_bounce_set(sd->scr, EINA_FALSE, EINA_TRUE);
673           }
674      }
675
676    eo_do(obj, elm_obj_widget_theme_apply());
677 }
678
679 EOLIAN static Eina_Bool
680 _elm_hoversel_horizontal_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
681 {
682    return sd->horizontal;
683 }
684
685 EOLIAN static void
686 _elm_hoversel_hover_begin(Eo *obj, Elm_Hoversel_Data *sd)
687 {
688    if (sd->hover) return;
689
690    _activate(obj);
691 }
692
693 EOLIAN static void
694 _elm_hoversel_hover_end(Eo *obj, Elm_Hoversel_Data *sd)
695 {
696
697    Elm_Object_Item *eo_item;
698    Eina_List *l;
699    const char *dismissstr;
700
701    if (!sd->hover) return;
702
703    dismissstr = edje_object_data_get(elm_layout_edje_get(sd->hover), "dismiss");
704
705    if (dismissstr && !strcmp(dismissstr, "on"))
706      {
707         elm_hover_dismiss(sd->hover);
708
709
710
711      }
712    else
713
714      {
715         sd->expanded = EINA_FALSE;
716
717         EINA_LIST_FOREACH(sd->items, l, eo_item)
718           {
719              ELM_HOVERSEL_ITEM_DATA_GET(eo_item, it);
720              VIEW(it) = NULL;
721           }
722         ELM_SAFE_FREE(sd->hover, evas_object_del);
723         sd->scr = NULL;
724         sd->last_location = NULL;
725
726         eo_do(obj, eo_event_callback_call(ELM_HOVERSEL_EVENT_DISMISSED, NULL));
727      } // for backward compatibility
728 }
729
730 EOLIAN static Eina_Bool
731 _elm_hoversel_expanded_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
732 {
733    return (sd->hover) ? EINA_TRUE : EINA_FALSE;
734 }
735
736 EOLIAN static void
737 _elm_hoversel_clear(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
738 {
739    Elm_Object_Item *it;
740    Eina_List *l, *ll;
741
742    EINA_LIST_FOREACH_SAFE(sd->items, l, ll, it)
743      {
744         eo_do(it, elm_wdg_item_del());
745      }
746 }
747
748 EOLIAN static const Eina_List*
749 _elm_hoversel_items_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
750 {
751    return sd->items;
752 }
753
754 EOLIAN static Eo *
755 _elm_hoversel_item_eo_base_constructor(Eo *obj, Elm_Hoversel_Item_Data *it)
756 {
757    obj = eo_do_super_ret(obj, ELM_HOVERSEL_ITEM_CLASS, obj, eo_constructor());
758    it->base = eo_data_scope_get(obj, ELM_WIDGET_ITEM_CLASS);
759
760    return obj;
761 }
762
763 EOLIAN static Elm_Object_Item*
764 _elm_hoversel_item_add(Eo *obj, Elm_Hoversel_Data *sd, const char *label, const char *icon_file, Elm_Icon_Type icon_type, Evas_Smart_Cb func, const void *data)
765 {
766    Eo *eo_item = eo_add(ELM_HOVERSEL_ITEM_CLASS, obj);
767    if (!eo_item) return NULL;
768
769    ELM_HOVERSEL_ITEM_DATA_GET(eo_item, item);
770
771    item->label = eina_stringshare_add(label);
772    item->icon_file = eina_stringshare_add(icon_file);
773    item->icon_type = icon_type;
774    item->func = func;
775    WIDGET_ITEM_DATA_SET(eo_item, data);
776
777    sd->items = eina_list_append(sd->items, eo_item);
778
779    return eo_item;
780 }
781
782 EOLIAN static void
783 _elm_hoversel_item_icon_set(Eo *eo_item EINA_UNUSED,
784                             Elm_Hoversel_Item_Data *item,
785                             const char *icon_file,
786                             const char *icon_group,
787                             Elm_Icon_Type icon_type)
788 {
789    eina_stringshare_replace(&item->icon_file, icon_file);
790    eina_stringshare_replace(&item->icon_group, icon_group);
791
792    item->icon_type = icon_type;
793 }
794
795 EOLIAN static void
796 _elm_hoversel_item_icon_get(Eo *eo_item EINA_UNUSED,
797                             Elm_Hoversel_Item_Data *item,
798                             const char **icon_file,
799                             const char **icon_group,
800                             Elm_Icon_Type *icon_type)
801 {
802    if (icon_file) *icon_file = item->icon_file;
803    if (icon_group) *icon_group = item->icon_group;
804    if (icon_type) *icon_type = item->icon_type;
805 }
806
807 static Elm_Object_Item *
808 item_focused_get(Elm_Hoversel_Data *sd)
809 {
810    Elm_Object_Item *eo_item;
811    Eina_List *l;
812
813    EINA_LIST_FOREACH(sd->items, l, eo_item)
814      {
815         ELM_HOVERSEL_ITEM_DATA_GET(eo_item, item);
816         if (elm_object_focus_get(VIEW(item)))
817           return eo_item;
818      }
819    return NULL;
820 }
821
822 static Eina_Bool
823 _key_action_move(Evas_Object *obj, const char *params)
824 {
825    ELM_HOVERSEL_DATA_GET(obj, sd);
826    const char *dir = params;
827
828    Elm_Object_Item  *eo_litem, *eo_fitem;
829    eo_litem = eina_list_last_data_get(sd->items);
830    eo_fitem = eina_list_data_get(sd->items);
831
832    _elm_widget_focus_auto_show(obj);
833    if (!strcmp(dir, "down"))
834      {
835         if ((!sd->horizontal) &&
836             (item_focused_get(sd) == eo_litem))
837           {
838             ELM_HOVERSEL_ITEM_DATA_GET(eo_fitem, fitem);
839             elm_object_focus_set(VIEW(fitem), EINA_TRUE);
840             return EINA_TRUE;
841           }
842         elm_widget_focus_cycle(sd->hover, ELM_FOCUS_DOWN);
843         return EINA_TRUE;
844      }
845    else if (!strcmp(dir, "up"))
846      {
847         if ((!sd->horizontal) &&
848             (item_focused_get(sd) == eo_fitem))
849           {
850             ELM_HOVERSEL_ITEM_DATA_GET(eo_litem, litem);
851             elm_object_focus_set(VIEW(litem), EINA_TRUE);
852             return EINA_TRUE;
853           }
854         elm_widget_focus_cycle(sd->hover, ELM_FOCUS_UP);
855         return EINA_TRUE;
856      }
857    else if (!strcmp(dir, "left"))
858      {
859         if (sd->horizontal &&
860             (item_focused_get(sd) == eo_fitem))
861           {
862             ELM_HOVERSEL_ITEM_DATA_GET(eo_litem, litem);
863             elm_object_focus_set(VIEW(litem), EINA_TRUE);
864             return EINA_TRUE;
865           }
866         elm_widget_focus_cycle(sd->hover, ELM_FOCUS_LEFT);
867         return EINA_TRUE;
868      }
869    else if (!strcmp(dir, "right"))
870      {
871         if (sd->horizontal &&
872             (item_focused_get(sd) == eo_litem))
873           {
874             ELM_HOVERSEL_ITEM_DATA_GET(eo_fitem, fitem);
875             elm_object_focus_set(VIEW(fitem), EINA_TRUE);
876             return EINA_TRUE;
877           }
878         elm_widget_focus_cycle(sd->hover, ELM_FOCUS_RIGHT);
879         return EINA_TRUE;
880      }
881    else return EINA_FALSE;
882 }
883
884 static Eina_Bool
885 _key_action_activate(Evas_Object *obj, const char *params EINA_UNUSED)
886 {
887    _activate(obj);
888    return EINA_TRUE;
889 }
890
891 EOLIAN static Eina_Bool
892 _elm_hoversel_elm_widget_event(Eo *obj, Elm_Hoversel_Data *sd, Evas_Object *src, Evas_Callback_Type type, void *event_info)
893 {
894    (void) src;
895    Eina_Bool int_ret = EINA_FALSE;
896    Evas_Event_Key_Down *ev = event_info;
897
898    eo_do_super(obj, MY_CLASS, int_ret = elm_obj_widget_event(src, type, event_info));
899    if (int_ret) return EINA_FALSE;
900
901    if (!sd || !sd->hover) return EINA_FALSE;
902    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
903    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
904
905    if (!_elm_config_key_binding_call(obj, ev, key_actions))
906      return EINA_FALSE;
907
908    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
909    return EINA_TRUE;
910 }
911
912 static void
913 _elm_hoversel_class_constructor(Eo_Class *klass)
914 {
915    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
916 }
917
918 EOLIAN const Elm_Atspi_Action *
919 _elm_hoversel_elm_interface_atspi_widget_action_elm_actions_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *pd EINA_UNUSED)
920 {
921    static Elm_Atspi_Action atspi_actions[] = {
922           { "activate", "activate", NULL, _key_action_activate},
923           { "move,up", "move", "up", _key_action_move},
924           { "move,down", "move", "down", _key_action_move},
925           { "move,left", "move", "left", _key_action_move},
926           { "move,right", "move", "right", _key_action_move},
927           { NULL, NULL, NULL, NULL}
928    };
929    return &atspi_actions[0];
930 }
931
932 EOLIAN void
933 _elm_hoversel_auto_update_set(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd, Eina_Bool auto_update)
934 {
935    sd->auto_update = !!auto_update;
936 }
937
938 EOLIAN Eina_Bool
939 _elm_hoversel_auto_update_get(Eo *obj EINA_UNUSED, Elm_Hoversel_Data *sd)
940 {
941    return sd->auto_update;
942 }
943
944 #include "elm_hoversel_item.eo.c"
945 #include "elm_hoversel.eo.c"