1 #include <Elementary.h>
3 #include "elm_widget_hover.h"
5 EAPI const char ELM_HOVER_SMART_NAME[] = "elm_hover";
8 # define MAX(a, b) (((a) > (b)) ? (a) : (b))
11 #define ELM_HOVER_PARTS_FOREACH unsigned int i; \
12 for (i = 0; i < sizeof(sd->subs) / sizeof(sd->subs[0]); i++)
14 #define _HOV_LEFT (&(sd->subs[0]))
15 #define _HOV_TOP_LEFT (&(sd->subs[1]))
16 #define _HOV_TOP (&(sd->subs[2]))
17 #define _HOV_TOP_RIGHT (&(sd->subs[2]))
18 #define _HOV_RIGHT (&(sd->subs[4]))
19 #define _HOV_BOTTOM_RIGHT (&(sd->subs[5]))
20 #define _HOV_BOTTOM (&(sd->subs[6]))
21 #define _HOV_BOTTOM_LEFT (&(sd->subs[7]))
22 #define _HOV_MIDDLE (&(sd->subs[8]))
24 const Elm_Layout_Part_Alias_Description _content_aliases[] =
26 {"left", "elm.swallow.slot.left"},
27 {"top-left", "elm.swallow.slot.top-left"},
28 {"top", "elm.swallow.slot.top"},
29 {"top-right", "elm.swallow.slot.top-right"},
30 {"right", "elm.swallow.slot.right"},
31 {"bottom-right", "elm.swallow.slot.bottom-right"},
32 {"bottom", "elm.swallow.slot.bottom"},
33 {"bottom-left", "elm.swallow.slot.bottom-left"},
34 {"middle", "elm.swallow.slot.middle"},
38 static const char SIG_CLICKED[] = "clicked";
39 static const char SIG_SMART_LOCATION_CHANGED[] = "smart,changed";
40 static const Evas_Smart_Cb_Description _smart_callbacks[] = {
42 {SIG_SMART_LOCATION_CHANGED, ""},
46 EVAS_SMART_SUBCLASS_NEW
47 (ELM_HOVER_SMART_NAME, _elm_hover, Elm_Hover_Smart_Class,
48 Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks);
51 _parent_move_cb(void *data,
53 Evas_Object *obj __UNUSED__,
54 void *event_info __UNUSED__)
56 elm_layout_sizing_eval(data);
60 _parent_resize_cb(void *data,
62 Evas_Object *obj __UNUSED__,
63 void *event_info __UNUSED__)
65 elm_layout_sizing_eval(data);
69 _parent_show_cb(void *data __UNUSED__,
71 Evas_Object *obj __UNUSED__,
72 void *event_info __UNUSED__)
77 _parent_hide_cb(void *data,
79 Evas_Object *obj __UNUSED__,
80 void *event_info __UNUSED__)
82 evas_object_hide(data);
86 _parent_del_cb(void *data,
88 Evas_Object *obj __UNUSED__,
89 void *event_info __UNUSED__)
91 elm_hover_parent_set(data, NULL);
92 elm_layout_sizing_eval(data);
96 _elm_hover_parent_detach(Evas_Object *obj)
98 ELM_HOVER_DATA_GET(obj, sd);
102 evas_object_event_callback_del_full
103 (sd->parent, EVAS_CALLBACK_MOVE, _parent_move_cb, obj);
104 evas_object_event_callback_del_full
105 (sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
106 evas_object_event_callback_del_full
107 (sd->parent, EVAS_CALLBACK_SHOW, _parent_show_cb, obj);
108 evas_object_event_callback_del_full
109 (sd->parent, EVAS_CALLBACK_HIDE, _parent_hide_cb, obj);
110 evas_object_event_callback_del_full
111 (sd->parent, EVAS_CALLBACK_DEL, _parent_del_cb, obj);
116 _elm_hover_left_space_calc(Elm_Hover_Smart_Data *sd,
122 Evas_Coord x = 0, y = 0, w = 0, h = 0, x2 = 0, y2 = 0, w2 = 0, h2 = 0;
124 if (sd->parent) evas_object_geometry_get(sd->parent, &x, &y, &w, &h);
125 if (sd->target) evas_object_geometry_get(sd->target, &x2, &y2, &w2, &h2);
128 *spc_r = (x + w) - (x2 + w2);
129 if (*spc_l < 0) *spc_l = 0;
130 if (*spc_r < 0) *spc_r = 0;
133 *spc_b = (y + h) - (y2 + h2);
134 if (*spc_t < 0) *spc_t = 0;
135 if (*spc_b < 0) *spc_b = 0;
138 static Content_Info *
139 _elm_hover_smart_content_location_get(Elm_Hover_Smart_Data *sd,
145 Evas_Coord c_w = 0, c_h = 0, mid_w, mid_h;
148 evas_object_size_hint_min_get(sd->smt_sub->obj, &c_w, &c_h);
152 if (spc_l > spc_r) goto left;
154 max = MAX(spc_t, spc_r);
155 max = MAX(max, spc_b);
159 if (mid_w > spc_l) return _HOV_TOP_RIGHT;
166 if (mid_h > spc_t) return _HOV_BOTTOM_RIGHT;
167 else if (mid_h > spc_b)
168 return _HOV_TOP_RIGHT;
174 return _HOV_BOTTOM_RIGHT;
179 max = MAX(spc_t, spc_l);
180 max = MAX(max, spc_b);
184 if (mid_w > spc_r) return _HOV_TOP_LEFT;
191 if (mid_h > spc_t) return _HOV_BOTTOM_LEFT;
192 else if (mid_h > spc_b)
193 return _HOV_TOP_LEFT;
198 if (mid_h > spc_r) return _HOV_BOTTOM_LEFT;
204 _elm_hover_smt_sub_re_eval(Evas_Object *obj)
206 Evas_Coord spc_l, spc_r, spc_t, spc_b;
211 ELM_HOVER_DATA_GET(obj, sd);
213 if (!sd->smt_sub) return;
216 _elm_hover_left_space_calc(sd, &spc_l, &spc_t, &spc_r, &spc_b);
217 elm_layout_content_unset(obj, sd->smt_sub->swallow);
219 sub = sd->smt_sub->obj;
221 sd->smt_sub->obj = NULL;
224 _elm_hover_smart_content_location_get(sd, spc_l, spc_t, spc_r, spc_b);
226 sd->smt_sub->obj = sub;
228 if (sd->smt_sub != prev)
229 evas_object_smart_callback_call
230 (obj, SIG_SMART_LOCATION_CHANGED, (void *)sd->smt_sub->swallow);
232 if (elm_widget_mirrored_get(obj))
234 if (sd->smt_sub == _HOV_BOTTOM_LEFT) sd->smt_sub = _HOV_BOTTOM_RIGHT;
235 else if (sd->smt_sub == _HOV_BOTTOM_RIGHT)
236 sd->smt_sub = _HOV_BOTTOM_LEFT;
237 else if (sd->smt_sub == _HOV_RIGHT)
238 sd->smt_sub = _HOV_LEFT;
239 else if (sd->smt_sub == _HOV_LEFT)
240 sd->smt_sub = _HOV_RIGHT;
241 else if (sd->smt_sub == _HOV_TOP_RIGHT)
242 sd->smt_sub = _HOV_TOP_LEFT;
243 else if (sd->smt_sub == _HOV_TOP_LEFT)
244 sd->smt_sub = _HOV_TOP_RIGHT;
247 snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", sd->smt_sub->swallow);
248 elm_layout_content_set(obj, buf, sd->smt_sub->obj);
252 _hov_show_do(Evas_Object *obj)
254 ELM_HOVER_DATA_GET(obj, sd);
256 elm_layout_signal_emit(obj, "elm,action,show", "elm");
258 ELM_HOVER_PARTS_FOREACH
265 (buf, sizeof(buf), "elm,action,slot,%s,show",
266 sd->subs[i].swallow);
268 elm_layout_signal_emit(obj, buf, "elm");
274 _elm_hover_smart_theme(Evas_Object *obj)
276 ELM_HOVER_DATA_GET(obj, sd);
278 if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->theme(obj)) return EINA_FALSE;
280 if (sd->smt_sub) _elm_hover_smt_sub_re_eval(obj);
282 elm_layout_sizing_eval(obj);
284 if (evas_object_visible_get(obj)) _hov_show_do(obj);
290 _elm_hover_smart_sizing_eval(Evas_Object *obj)
292 Evas_Coord ofs_x, x = 0, y = 0, w = 0, h = 0, x2 = 0,
293 y2 = 0, w2 = 0, h2 = 0;
295 ELM_HOVER_DATA_GET(obj, sd);
297 if (sd->on_del) return;
299 if (sd->parent) evas_object_geometry_get(sd->parent, &x, &y, &w, &h);
300 evas_object_geometry_get(obj, &x2, &y2, &w2, &h2);
302 if (elm_widget_mirrored_get(obj)) ofs_x = w - (x2 - x) - w2;
305 evas_object_move(ELM_WIDGET_DATA(sd)->resize_obj, x, y);
306 evas_object_resize(ELM_WIDGET_DATA(sd)->resize_obj, w, h);
307 evas_object_size_hint_min_set(sd->offset, ofs_x, y2 - y);
308 evas_object_size_hint_min_set(sd->size, w2, h2);
312 _on_smt_sub_changed(void *data,
314 Evas_Object *obj __UNUSED__,
315 void *event_info __UNUSED__)
317 _elm_hover_smt_sub_re_eval(data);
321 _elm_hover_smart_sub_object_add(Evas_Object *obj,
324 ELM_HOVER_DATA_GET(obj, sd);
326 if (evas_object_data_get(sobj, "elm-parent") == obj)
329 if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->sub_object_add(obj, sobj))
332 if (sd->smt_sub && sd->smt_sub->obj == sobj)
333 evas_object_event_callback_add
334 (sobj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _on_smt_sub_changed, obj);
340 _elm_hover_smart_sub_object_del(Evas_Object *obj,
343 ELM_HOVER_DATA_GET(obj, sd);
345 if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->sub_object_del(obj, sobj))
348 if (sd->smt_sub && sd->smt_sub->obj == sobj)
350 evas_object_event_callback_del_full
351 (sd->smt_sub->obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
352 _on_smt_sub_changed, obj);
354 sd->smt_sub->obj = NULL;
359 ELM_HOVER_PARTS_FOREACH
361 if (sd->subs[i].obj == sobj)
363 sd->subs[i].obj = NULL;
373 _elm_hover_subs_del(Elm_Hover_Smart_Data *sd)
375 ELM_HOVER_PARTS_FOREACH
379 evas_object_del(sd->subs[i].obj);
380 sd->subs[i].obj = NULL;
386 _elm_hover_smart_content_set(Evas_Object *obj,
388 Evas_Object *content)
390 ELM_HOVER_CHECK(obj) EINA_FALSE;
391 ELM_HOVER_DATA_GET(obj, sd);
393 if (!swallow) return EINA_FALSE;
395 if (!strcmp(swallow, "smart"))
397 if (sd->smt_sub) /* already under 'smart' mode */
399 if (sd->smt_sub->obj != content)
401 evas_object_del(sd->smt_sub->obj);
402 sd->smt_sub = _HOV_LEFT;
403 sd->smt_sub->obj = content;
408 sd->smt_sub->obj = NULL;
411 else _elm_hover_smt_sub_re_eval(obj);
415 else /* switch from pristine spots to 'smart' */
417 _elm_hover_subs_del(sd);
418 sd->smt_sub = _HOV_LEFT;
419 sd->smt_sub->obj = content;
421 _elm_hover_smt_sub_re_eval(obj);
427 if (!ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_set
428 (obj, swallow, content))
431 if (strstr(swallow, "elm.swallow.slot."))
432 swallow += sizeof("elm.swallow.slot.");
434 ELM_HOVER_PARTS_FOREACH
436 if (!strcmp(swallow, sd->subs[i].swallow))
438 sd->subs[i].obj = content;
444 elm_layout_sizing_eval(obj);
449 _elm_hover_smart_content_get(const Evas_Object *obj,
452 ELM_HOVER_CHECK(obj) NULL;
454 ELM_HOVER_DATA_GET(obj, sd);
456 if (!swallow) return NULL;
458 if (!strcmp(swallow, "smart"))
459 return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_get
460 (obj, sd->smt_sub->swallow);
462 return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_get(obj, swallow);
466 _elm_hover_smart_content_unset(Evas_Object *obj,
469 ELM_HOVER_CHECK(obj) NULL;
471 ELM_HOVER_DATA_GET(obj, sd);
473 if (!swallow) return NULL;
475 if (!strcmp(swallow, "smart"))
476 return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_unset
477 (obj, sd->smt_sub->swallow);
479 return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_unset
486 _target_del_cb(void *data,
488 Evas_Object *obj __UNUSED__,
489 void *event_info __UNUSED__)
491 ELM_HOVER_DATA_GET(data, sd);
497 _target_move_cb(void *data,
499 Evas_Object *obj __UNUSED__,
500 void *event_info __UNUSED__)
502 elm_layout_sizing_eval(data);
503 _elm_hover_smt_sub_re_eval(data);
507 _hov_dismiss_cb(void *data,
508 Evas_Object *obj __UNUSED__,
509 const char *emission __UNUSED__,
510 const char *source __UNUSED__)
512 evas_object_hide(data);
513 evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
517 _elm_hover_smart_add(Evas_Object *obj)
521 EVAS_SMART_DATA_ALLOC(obj, Elm_Hover_Smart_Data);
523 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.add(obj);
525 for (i = 0; i < sizeof(priv->subs) / sizeof(priv->subs[0]); i++)
526 priv->subs[i].swallow = _content_aliases[i].alias;
528 elm_layout_theme_set(obj, "hover", "base", elm_widget_style_get(obj));
529 elm_layout_signal_callback_add
530 (obj, "elm,action,dismiss", "", _hov_dismiss_cb, obj);
532 priv->offset = evas_object_rectangle_add(evas_object_evas_get(obj));
533 evas_object_pass_events_set(priv->offset, EINA_TRUE);
534 evas_object_color_set(priv->offset, 0, 0, 0, 0);
536 priv->size = evas_object_rectangle_add(evas_object_evas_get(obj));
537 evas_object_pass_events_set(priv->size, EINA_TRUE);
538 evas_object_color_set(priv->size, 0, 0, 0, 0);
540 elm_layout_content_set(obj, "elm.swallow.offset", priv->offset);
541 elm_layout_content_set(obj, "elm.swallow.size", priv->size);
543 elm_widget_can_focus_set(obj, EINA_TRUE);
547 _elm_hover_smart_del(Evas_Object *obj)
549 ELM_HOVER_DATA_GET(obj, sd);
551 sd->on_del = EINA_TRUE;
553 if (evas_object_visible_get(obj))
554 evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
556 elm_hover_target_set(obj, NULL);
558 _elm_hover_parent_detach(obj);
561 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.del(obj);
565 _elm_hover_smart_move(Evas_Object *obj,
569 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.move(obj, x, y);
571 elm_layout_sizing_eval(obj);
575 _elm_hover_smart_resize(Evas_Object *obj,
579 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.resize(obj, w, h);
581 elm_layout_sizing_eval(obj);
585 _elm_hover_smart_show(Evas_Object *obj)
587 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.show(obj);
593 _elm_hover_smart_hide(Evas_Object *obj)
595 ELM_HOVER_DATA_GET(obj, sd);
597 ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.hide(obj);
599 elm_layout_signal_emit(obj, "elm,action,hide", "elm");
601 ELM_HOVER_PARTS_FOREACH
607 snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide",
608 sd->subs[i].swallow);
609 elm_layout_signal_emit(obj, buf, "elm");
615 _elm_hover_smart_parent_set(Evas_Object *obj,
618 elm_hover_parent_set(obj, parent);
620 elm_layout_sizing_eval(obj);
624 _elm_hover_smart_set_user(Elm_Hover_Smart_Class *sc)
626 ELM_WIDGET_CLASS(sc)->base.add = _elm_hover_smart_add;
627 ELM_WIDGET_CLASS(sc)->base.del = _elm_hover_smart_del;
628 ELM_WIDGET_CLASS(sc)->base.move = _elm_hover_smart_move;
629 ELM_WIDGET_CLASS(sc)->base.resize = _elm_hover_smart_resize;
630 ELM_WIDGET_CLASS(sc)->base.show = _elm_hover_smart_show;
631 ELM_WIDGET_CLASS(sc)->base.hide = _elm_hover_smart_hide;
633 ELM_WIDGET_CLASS(sc)->parent_set = _elm_hover_smart_parent_set;
634 ELM_WIDGET_CLASS(sc)->sub_object_add = _elm_hover_smart_sub_object_add;
635 ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_hover_smart_sub_object_del;
636 ELM_WIDGET_CLASS(sc)->theme = _elm_hover_smart_theme;
638 /* not a 'focus chain manager' */
639 ELM_WIDGET_CLASS(sc)->focus_next = NULL;
640 ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
642 ELM_CONTAINER_CLASS(sc)->content_set = _elm_hover_smart_content_set;
643 ELM_CONTAINER_CLASS(sc)->content_get = _elm_hover_smart_content_get;
644 ELM_CONTAINER_CLASS(sc)->content_unset = _elm_hover_smart_content_unset;
646 ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_hover_smart_sizing_eval;
648 ELM_LAYOUT_CLASS(sc)->content_aliases = _content_aliases;
651 EAPI const Elm_Hover_Smart_Class *
652 elm_hover_smart_class_get(void)
654 static Elm_Hover_Smart_Class _sc =
655 ELM_HOVER_SMART_CLASS_INIT_NAME_VERSION(ELM_HOVER_SMART_NAME);
656 static const Elm_Hover_Smart_Class *class = NULL;
657 Evas_Smart_Class *esc = (Evas_Smart_Class *)&_sc;
662 _elm_hover_smart_set(&_sc);
663 esc->callbacks = _smart_callbacks;
670 elm_hover_add(Evas_Object *parent)
674 EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
676 obj = elm_widget_add(_elm_hover_smart_class_new(), parent);
677 if (!obj) return NULL;
679 if (!elm_widget_sub_object_add(parent, obj))
680 ERR("could not add %p as sub object of %p", obj, parent);
686 elm_hover_target_set(Evas_Object *obj,
689 ELM_HOVER_CHECK(obj);
690 ELM_HOVER_DATA_GET(obj, sd);
694 evas_object_event_callback_del_full
695 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
696 evas_object_event_callback_del_full
697 (sd->target, EVAS_CALLBACK_MOVE, _target_move_cb, obj);
698 elm_widget_hover_object_set(sd->target, NULL);
704 evas_object_event_callback_add
705 (sd->target, EVAS_CALLBACK_DEL, _target_del_cb, obj);
706 evas_object_event_callback_add
707 (sd->target, EVAS_CALLBACK_MOVE, _target_move_cb, obj);
708 elm_widget_hover_object_set(target, obj);
709 elm_layout_sizing_eval(obj);
714 elm_hover_parent_set(Evas_Object *obj,
717 ELM_HOVER_CHECK(obj);
718 ELM_HOVER_DATA_GET(obj, sd);
720 _elm_hover_parent_detach(obj);
725 evas_object_event_callback_add
726 (sd->parent, EVAS_CALLBACK_MOVE, _parent_move_cb, obj);
727 evas_object_event_callback_add
728 (sd->parent, EVAS_CALLBACK_RESIZE, _parent_resize_cb, obj);
729 evas_object_event_callback_add
730 (sd->parent, EVAS_CALLBACK_SHOW, _parent_show_cb, obj);
731 evas_object_event_callback_add
732 (sd->parent, EVAS_CALLBACK_HIDE, _parent_hide_cb, obj);
733 evas_object_event_callback_add
734 (sd->parent, EVAS_CALLBACK_DEL, _parent_del_cb, obj);
737 elm_layout_sizing_eval(obj);
741 elm_hover_target_get(const Evas_Object *obj)
743 ELM_HOVER_CHECK(obj) NULL;
744 ELM_HOVER_DATA_GET(obj, sd);
750 elm_hover_parent_get(const Evas_Object *obj)
752 ELM_HOVER_CHECK(obj) NULL;
753 ELM_HOVER_DATA_GET(obj, sd);
759 elm_hover_best_content_location_get(const Evas_Object *obj,
760 Elm_Hover_Axis pref_axis)
762 Evas_Coord spc_l, spc_r, spc_t, spc_b;
764 ELM_HOVER_CHECK(obj) NULL;
765 ELM_HOVER_DATA_GET(obj, sd);
767 _elm_hover_left_space_calc(sd, &spc_l, &spc_t, &spc_r, &spc_b);
769 if (pref_axis == ELM_HOVER_AXIS_HORIZONTAL)
771 if (spc_l < spc_r) return (_HOV_RIGHT)->swallow;
772 else return (_HOV_LEFT)->swallow;
774 else if (pref_axis == ELM_HOVER_AXIS_VERTICAL)
776 if (spc_t < spc_b) return (_HOV_BOTTOM)->swallow;
777 else return (_HOV_TOP)->swallow;
782 if (spc_t > spc_r) return (_HOV_TOP)->swallow;
783 else if (spc_b > spc_r)
784 return (_HOV_BOTTOM)->swallow;
786 return (_HOV_RIGHT)->swallow;
789 if (spc_t > spc_r) return (_HOV_TOP)->swallow;
790 else if (spc_b > spc_r)
791 return (_HOV_BOTTOM)->swallow;
793 return (_HOV_LEFT)->swallow;
797 elm_hover_dismiss(Evas_Object *obj)
799 ELM_HOVER_CHECK(obj);
801 elm_layout_signal_emit(obj, "elm,action,dismiss", "");