1 #include <Elementary.h>
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Content_Info Content_Info;
8 # define MAX(a, b) (((a) > (b)) ? (a) : (b))
11 #define ELM_HOVER_PARTS_FOREACH unsigned int i = 0; \
12 for (i = 0; i < sizeof(wd->subs) / sizeof(wd->subs[0]); i++)
14 static const char *_directions[] = {
26 #define _HOV_LEFT (_directions[0])
27 #define _HOV_TOP_LEFT (_directions[1])
28 #define _HOV_TOP (_directions[2])
29 #define _HOV_TOP_RIGHT (_directions[2])
30 #define _HOV_RIGHT (_directions[4])
31 #define _HOV_BOTTOM_RIGHT (_directions[5])
32 #define _HOV_BOTTOM (_directions[6])
33 #define _HOV_BOTTOM_LEFT (_directions[7])
34 #define _HOV_MIDDLE (_directions[8])
44 Evas_Object *hov, *cov;
45 Evas_Object *offset, *size;
46 Evas_Object *parent, *target;
48 Content_Info subs[sizeof(_directions)/sizeof(_directions[0])];
51 static const char *widtype = NULL;
52 static void _del_pre_hook(Evas_Object *obj);
53 static void _del_hook(Evas_Object *obj);
54 static void _mirrored_set(Evas_Object *obj, Eina_Bool rtl);
55 static void _theme_hook(Evas_Object *obj);
56 static void _sizing_eval(Evas_Object *obj);
57 static void _reval_content(Evas_Object *obj);
58 static void _sub_del(void *data, Evas_Object *obj, void *event_info);
59 static void _hov_show_do(Evas_Object *obj);
60 static void _hov_move(void *data, Evas *e, Evas_Object *obj, void *event_info);
61 static void _hov_resize(void *data, Evas *e, Evas_Object *obj, void *event_info);
62 static void _hov_show(void *data, Evas *e, Evas_Object *obj, void *event_info);
63 static void _hov_hide(void *data, Evas *e, Evas_Object *obj, void *event_info);
64 static void _on_focus_hook(void *data, Evas_Object *obj);
65 static void _elm_hover_sub_obj_placement_eval_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
66 static void _elm_hover_sub_obj_placement_eval(Evas_Object *obj);
68 static const char SIG_CLICKED[] = "clicked";
69 static const char SIG_SMART_LOCATION_CHANGED[] = "smart,changed";
70 static const Evas_Smart_Cb_Description _signals[] = {
72 {SIG_SMART_LOCATION_CHANGED, ""},
77 _del_pre_hook(Evas_Object *obj)
79 Widget_Data *wd = elm_widget_data_get(obj);
83 if (evas_object_visible_get(obj))
84 evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
85 elm_hover_target_set(obj, NULL);
86 elm_hover_parent_set(obj, NULL);
87 evas_object_event_callback_del_full(wd->hov, EVAS_CALLBACK_MOVE, _hov_move, obj);
88 evas_object_event_callback_del_full(wd->hov, EVAS_CALLBACK_RESIZE, _hov_resize, obj);
89 evas_object_event_callback_del_full(wd->hov, EVAS_CALLBACK_SHOW, _hov_show, obj);
90 evas_object_event_callback_del_full(wd->hov, EVAS_CALLBACK_HIDE, _hov_hide, obj);
94 _del_hook(Evas_Object *obj)
96 Widget_Data *wd = elm_widget_data_get(obj);
102 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
104 Widget_Data *wd = elm_widget_data_get(obj);
106 if (elm_widget_focus_get(obj))
108 edje_object_signal_emit(wd->cov, "elm,action,focus", "elm");
109 evas_object_focus_set(wd->cov, EINA_TRUE);
113 edje_object_signal_emit(wd->cov, "elm,action,unfocus", "elm");
114 evas_object_focus_set(wd->cov, EINA_FALSE);
119 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
121 Widget_Data *wd = elm_widget_data_get(obj);
123 edje_object_mirrored_set(wd->cov, rtl);
127 _theme_hook(Evas_Object *obj)
129 Widget_Data *wd = elm_widget_data_get(obj);
131 _elm_widget_mirrored_reload(obj);
132 _mirrored_set(obj, elm_widget_mirrored_get(obj));
133 // FIXME: hover contents doesn't seem to propagate resizes properly
134 _elm_theme_object_set(obj, wd->cov, "hover", "base", elm_widget_style_get(obj));
135 edje_object_scale_set(wd->cov, elm_widget_scale_get(obj) *
139 _elm_hover_sub_obj_placement_eval(obj);
143 if (evas_object_visible_get(wd->cov)) _hov_show_do(obj);
147 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
151 wd = elm_widget_data_get(obj);
155 edje_object_signal_emit(wd->cov, emission, source);
159 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
163 wd = elm_widget_data_get(obj);
167 edje_object_signal_callback_add(wd->hov, emission, source, func_cb, data);
171 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
175 wd = elm_widget_data_get(obj);
177 edje_object_signal_callback_del_full(wd->hov, emission, source, func_cb,
182 _elm_hover_left_space_calc(Widget_Data *wd, Evas_Coord *spc_l, Evas_Coord *spc_t, Evas_Coord *spc_r, Evas_Coord *spc_b)
184 Evas_Coord x = 0, y = 0, w = 0, h = 0, x2 = 0, y2 = 0, w2 = 0, h2 = 0;
187 evas_object_geometry_get(wd->parent, &x, &y, &w, &h);
189 evas_object_geometry_get(wd->target, &x2, &y2, &w2, &h2);
192 *spc_r = (x + w) - (x2 + w2);
199 *spc_b = (y + h) - (y2 + h2);
207 _sizing_eval(Evas_Object *obj)
209 Widget_Data *wd = elm_widget_data_get(obj);
210 Evas_Coord ofs_x, x = 0, y = 0, w = 0, h = 0, x2 = 0, y2 = 0, w2 = 0, h2 = 0;
212 if (wd->parent) evas_object_geometry_get(wd->parent, &x, &y, &w, &h);
213 if (wd->hov) evas_object_geometry_get(wd->hov, &x2, &y2, &w2, &h2);
215 if (elm_widget_mirrored_get(obj))
216 ofs_x = w - (x2 - x) - w2;
220 evas_object_move(wd->cov, x, y);
221 evas_object_resize(wd->cov, w, h);
222 evas_object_size_hint_min_set(wd->offset, ofs_x, y2 - y);
223 evas_object_size_hint_min_set(wd->size, w2, h2);
224 edje_object_part_swallow(wd->cov, "elm.swallow.offset", wd->offset);
225 edje_object_part_swallow(wd->cov, "elm.swallow.size", wd->size);
229 _reval_content(Evas_Object *obj)
231 Widget_Data *wd = elm_widget_data_get(obj);
235 ELM_HOVER_PARTS_FOREACH
238 snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", wd->subs[i].swallow);
239 edje_object_part_swallow(wd->cov, buf, wd->subs[i].obj);
244 _elm_hover_smart_content_location_get(Widget_Data *wd, Evas_Coord spc_l, Evas_Coord spc_t, Evas_Coord spc_r, Evas_Coord spc_b)
246 Evas_Coord c_w = 0, c_h = 0, mid_w, mid_h;
249 evas_object_size_hint_min_get(wd->smt_sub, &c_w, &c_h);
256 max = MAX(spc_t, spc_r);
257 max = MAX(max, spc_b);
262 return _HOV_TOP_RIGHT;
270 return _HOV_BOTTOM_RIGHT;
271 else if (mid_h > spc_b)
272 return _HOV_TOP_RIGHT;
278 return _HOV_BOTTOM_RIGHT;
283 max = MAX(spc_t, spc_l);
284 max = MAX(max, spc_b);
289 return _HOV_TOP_LEFT;
297 return _HOV_BOTTOM_LEFT;
298 else if (mid_h > spc_b)
299 return _HOV_TOP_LEFT;
305 return _HOV_BOTTOM_LEFT;
311 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
317 wd = elm_widget_data_get(obj);
323 if (wd->smt_sub == sub)
328 ELM_HOVER_PARTS_FOREACH
330 if (wd->subs[i].obj == sub)
332 wd->subs[i].obj = NULL;
340 _hov_show_do(Evas_Object *obj)
342 Widget_Data *wd = elm_widget_data_get(obj);
348 evas_object_show(wd->cov);
349 edje_object_signal_emit(wd->cov, "elm,action,show", "elm");
352 ELM_HOVER_PARTS_FOREACH
358 snprintf(buf, sizeof(buf), "elm,action,slot,%s,show",
359 wd->subs[i].swallow);
360 edje_object_signal_emit(wd->cov, buf, "elm");
366 _hov_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
372 _hov_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
378 _hov_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
384 _hov_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
386 Widget_Data *wd = elm_widget_data_get(data);
390 edje_object_signal_emit(wd->cov, "elm,action,hide", "elm");
391 evas_object_hide(wd->cov);
394 ELM_HOVER_PARTS_FOREACH
400 snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide",
401 wd->subs[i].swallow);
402 edje_object_signal_emit(wd->cov, buf, "elm");
408 _target_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
410 Widget_Data *wd = elm_widget_data_get(data);
416 _target_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
418 Widget_Data *wd = elm_widget_data_get(data);
423 _elm_hover_sub_obj_placement_eval(data);
427 _signal_dismiss(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
429 Widget_Data *wd = elm_widget_data_get(data);
431 evas_object_hide(data);
432 evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
436 _parent_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
442 _parent_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
448 _parent_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
453 _parent_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
455 Widget_Data *wd = elm_widget_data_get(data);
457 evas_object_hide(wd->cov);
461 _parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
463 Widget_Data *wd = elm_widget_data_get(data);
465 elm_hover_parent_set(data, NULL);
470 elm_hover_add(Evas_Object *parent)
476 ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
478 ELM_SET_WIDTYPE(widtype, "hover");
479 elm_widget_type_set(obj, "hover");
480 elm_widget_sub_object_add(parent, obj);
481 elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
482 elm_widget_data_set(obj, wd);
483 elm_widget_del_pre_hook_set(obj, _del_pre_hook);
484 elm_widget_theme_hook_set(obj, _theme_hook);
485 elm_widget_del_hook_set(obj, _del_hook);
486 elm_widget_can_focus_set(obj, EINA_TRUE);
487 elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
488 elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
489 elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
491 ELM_HOVER_PARTS_FOREACH
492 wd->subs[i].swallow = _directions[i];
494 wd->hov = evas_object_rectangle_add(e);
495 evas_object_pass_events_set(wd->hov, EINA_TRUE);
496 evas_object_color_set(wd->hov, 0, 0, 0, 0);
497 elm_widget_resize_object_set(obj, wd->hov);
498 evas_object_event_callback_add(wd->hov, EVAS_CALLBACK_MOVE, _hov_move, obj);
499 evas_object_event_callback_add(wd->hov, EVAS_CALLBACK_RESIZE, _hov_resize, obj);
500 evas_object_event_callback_add(wd->hov, EVAS_CALLBACK_SHOW, _hov_show, obj);
501 evas_object_event_callback_add(wd->hov, EVAS_CALLBACK_HIDE, _hov_hide, obj);
503 wd->cov = edje_object_add(e);
504 _elm_theme_object_set(obj, wd->cov, "hover", "base", "default");
505 elm_widget_sub_object_add(obj, wd->cov);
506 edje_object_signal_callback_add(wd->cov, "elm,action,dismiss", "",
507 _signal_dismiss, obj);
509 wd->offset = evas_object_rectangle_add(e);
510 evas_object_pass_events_set(wd->offset, EINA_TRUE);
511 evas_object_color_set(wd->offset, 0, 0, 0, 0);
512 elm_widget_sub_object_add(obj, wd->offset);
514 wd->size = evas_object_rectangle_add(e);
515 evas_object_pass_events_set(wd->size, EINA_TRUE);
516 evas_object_color_set(wd->size, 0, 0, 0, 0);
517 elm_widget_sub_object_add(obj, wd->size);
519 edje_object_part_swallow(wd->cov, "elm.swallow.offset", wd->offset);
520 edje_object_part_swallow(wd->cov, "elm.swallow.size", wd->size);
522 evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
524 elm_hover_parent_set(obj, parent);
525 evas_object_smart_callbacks_descriptions_set(obj, _signals);
527 _mirrored_set(obj, elm_widget_mirrored_get(obj));
533 elm_hover_target_set(Evas_Object *obj, Evas_Object *target)
535 ELM_CHECK_WIDTYPE(obj, widtype);
536 Widget_Data *wd = elm_widget_data_get(obj);
540 evas_object_event_callback_del_full(wd->target, EVAS_CALLBACK_DEL,
542 evas_object_event_callback_del_full(wd->target, EVAS_CALLBACK_MOVE,
548 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_DEL,
550 evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOVE,
552 elm_widget_hover_object_set(target, obj);
559 elm_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
561 ELM_CHECK_WIDTYPE(obj, widtype);
562 Widget_Data *wd = elm_widget_data_get(obj);
566 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_MOVE,
568 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_RESIZE,
569 _parent_resize, obj);
570 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_SHOW,
572 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_HIDE,
574 evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_DEL,
580 evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_MOVE,
582 evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_RESIZE,
583 _parent_resize, obj);
584 evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_SHOW,
586 evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_HIDE,
588 evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_DEL,
590 // elm_widget_sub_object_add(parent, obj);
596 elm_hover_target_get(const Evas_Object *obj)
598 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
599 Widget_Data *wd = elm_widget_data_get(obj);
600 if (!wd) return NULL;
606 elm_hover_parent_get(const Evas_Object *obj)
608 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
609 Widget_Data *wd = elm_widget_data_get(obj);
610 if (!wd) return NULL;
616 _elm_hover_subs_del(Widget_Data *wd)
618 ELM_HOVER_PARTS_FOREACH
622 evas_object_del(wd->subs[i].obj);
623 wd->subs[i].obj = NULL;
629 _elm_hover_sub_obj_placement_eval(Evas_Object *obj)
631 Evas_Coord spc_l, spc_r, spc_t, spc_b;
632 const char *smart_dir;
636 wd = elm_widget_data_get(obj);
640 _elm_hover_left_space_calc(wd, &spc_l, &spc_t, &spc_r, &spc_b);
642 edje_object_part_unswallow(wd->cov, wd->smt_sub);
644 smart_dir = _elm_hover_smart_content_location_get(wd, spc_l, spc_t, spc_r,
646 evas_object_smart_callback_call(obj, SIG_SMART_LOCATION_CHANGED,
649 if (elm_widget_mirrored_get(obj))
651 if (smart_dir == _HOV_BOTTOM_LEFT)
652 smart_dir = _HOV_BOTTOM_RIGHT;
653 else if (smart_dir == _HOV_BOTTOM_RIGHT)
654 smart_dir = _HOV_BOTTOM_LEFT;
655 else if (smart_dir == _HOV_RIGHT)
656 smart_dir = _HOV_LEFT;
657 else if (smart_dir == _HOV_LEFT)
658 smart_dir = _HOV_RIGHT;
659 else if (smart_dir == _HOV_TOP_RIGHT)
660 smart_dir = _HOV_TOP_LEFT;
661 else if (smart_dir == _HOV_TOP_LEFT)
662 smart_dir = _HOV_TOP_RIGHT;
664 snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", smart_dir);
665 edje_object_part_swallow(wd->cov, buf, wd->smt_sub);
669 _elm_hover_sub_obj_placement_eval_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
671 _elm_hover_sub_obj_placement_eval(data);
675 elm_hover_content_set(Evas_Object *obj, const char *swallow, Evas_Object *content)
677 ELM_CHECK_WIDTYPE(obj, widtype);
681 wd = elm_widget_data_get(obj);
685 if (!strcmp(swallow, "smart"))
687 if (wd->smt_sub != content)
689 _elm_hover_subs_del(wd);
690 wd->smt_sub = content;
695 elm_widget_sub_object_add(obj, content);
696 evas_object_event_callback_add(wd->smt_sub,
697 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
698 _elm_hover_sub_obj_placement_eval_cb,
701 _elm_hover_sub_obj_placement_eval(obj);
709 evas_object_del(wd->smt_sub);
713 ELM_HOVER_PARTS_FOREACH
715 if (!strcmp(swallow, wd->subs[i].swallow))
717 if (content == wd->subs[i].obj)
719 evas_object_del(wd->subs[i].obj);
720 wd->subs[i].obj = NULL;
726 snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", swallow);
727 elm_widget_sub_object_add(obj, content);
728 edje_object_part_swallow(wd->cov, buf, content);
729 wd->subs[i].obj = content;
740 elm_hover_content_get(const Evas_Object *obj, const char *swallow)
742 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
746 wd = elm_widget_data_get(obj);
750 if (!strcmp(swallow, "smart"))
753 ELM_HOVER_PARTS_FOREACH
754 if (!strcmp(swallow, wd->subs[i].swallow))
755 return wd->subs[i].obj;
761 _elm_hover_sub_obj_unparent(Evas_Object *obj)
765 wd = elm_widget_data_get(obj);
767 elm_widget_sub_object_del(obj, wd->smt_sub);
768 evas_object_event_callback_del_full(wd->smt_sub,
769 EVAS_CALLBACK_CHANGED_SIZE_HINTS,
770 _elm_hover_sub_obj_placement_eval_cb,
772 edje_object_part_unswallow(wd->cov, wd->smt_sub);
777 elm_hover_content_unset(Evas_Object *obj, const char *swallow)
779 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
783 wd = elm_widget_data_get(obj);
787 if (!strcmp(swallow, "smart"))
789 Evas_Object *content;
794 content = wd->smt_sub;
795 _elm_hover_sub_obj_unparent(obj);
799 ELM_HOVER_PARTS_FOREACH
801 if (!strcmp(swallow, wd->subs[i].swallow))
803 Evas_Object *content;
805 if (!wd->subs[i].obj)
808 content = wd->subs[i].obj;
809 elm_widget_sub_object_del(obj, wd->subs[i].obj);
810 edje_object_part_unswallow(wd->cov, wd->subs[i].obj);
811 wd->subs[i].obj = NULL;
821 elm_hover_best_content_location_get(const Evas_Object *obj, Elm_Hover_Axis pref_axis)
823 ELM_CHECK_WIDTYPE(obj, widtype) NULL;
825 Evas_Coord spc_l, spc_r, spc_t, spc_b;
828 wd = elm_widget_data_get(obj);
832 _elm_hover_left_space_calc(wd, &spc_l, &spc_t, &spc_r, &spc_b);
834 if (pref_axis == ELM_HOVER_AXIS_HORIZONTAL)
836 if (spc_l < spc_r) return _HOV_RIGHT;
837 else return _HOV_LEFT;
839 else if (pref_axis == ELM_HOVER_AXIS_VERTICAL)
841 if (spc_t < spc_b) return _HOV_BOTTOM;
842 else return _HOV_TOP;
847 if (spc_t > spc_r) return _HOV_TOP;
848 else if (spc_b > spc_r) return _HOV_BOTTOM;
851 if (spc_t > spc_r) return _HOV_TOP;
852 else if (spc_b > spc_r) return _HOV_BOTTOM;