[access] call a callback function with information
[framework/uifw/elementary.git] / src / lib / elm_hover.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3 #include "elm_widget_hover.h"
4
5 EAPI const char ELM_HOVER_SMART_NAME[] = "elm_hover";
6
7 #ifndef MAX
8 # define MAX(a, b) (((a) > (b)) ? (a) : (b))
9 #endif
10
11 #define ELM_HOVER_PARTS_FOREACH unsigned int i; \
12   for (i = 0; i < sizeof(sd->subs) / sizeof(sd->subs[0]); i++)
13
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]))
23
24 const Elm_Layout_Part_Alias_Description _content_aliases[] =
25 {
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"},
35    {NULL, NULL}
36 };
37
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[] = {
41    {SIG_CLICKED, ""},
42    {SIG_SMART_LOCATION_CHANGED, ""},
43    {NULL, NULL}
44 };
45
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);
49
50 static void
51 _parent_move_cb(void *data,
52                 Evas *e __UNUSED__,
53                 Evas_Object *obj __UNUSED__,
54                 void *event_info __UNUSED__)
55 {
56    elm_layout_sizing_eval(data);
57 }
58
59 static void
60 _parent_resize_cb(void *data,
61                   Evas *e __UNUSED__,
62                   Evas_Object *obj __UNUSED__,
63                   void *event_info __UNUSED__)
64 {
65    elm_layout_sizing_eval(data);
66 }
67
68 static void
69 _parent_show_cb(void *data __UNUSED__,
70                 Evas *e __UNUSED__,
71                 Evas_Object *obj __UNUSED__,
72                 void *event_info __UNUSED__)
73 {
74 }
75
76 static void
77 _parent_hide_cb(void *data,
78                 Evas *e __UNUSED__,
79                 Evas_Object *obj __UNUSED__,
80                 void *event_info __UNUSED__)
81 {
82    evas_object_hide(data);
83 }
84
85 static void
86 _parent_del_cb(void *data,
87                Evas *e __UNUSED__,
88                Evas_Object *obj __UNUSED__,
89                void *event_info __UNUSED__)
90 {
91    elm_hover_parent_set(data, NULL);
92    elm_layout_sizing_eval(data);
93 }
94
95 static void
96 _elm_hover_parent_detach(Evas_Object *obj)
97 {
98    ELM_HOVER_DATA_GET(obj, sd);
99
100    if (sd->parent)
101      {
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);
112      }
113 }
114
115 static void
116 _elm_hover_left_space_calc(Elm_Hover_Smart_Data *sd,
117                            Evas_Coord *spc_l,
118                            Evas_Coord *spc_t,
119                            Evas_Coord *spc_r,
120                            Evas_Coord *spc_b)
121 {
122    Evas_Coord x = 0, y = 0, w = 0, h = 0, x2 = 0, y2 = 0, w2 = 0, h2 = 0;
123
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);
126
127    *spc_l = x2 - x;
128    *spc_r = (x + w) - (x2 + w2);
129    if (*spc_l < 0) *spc_l = 0;
130    if (*spc_r < 0) *spc_r = 0;
131
132    *spc_t = y2 - y;
133    *spc_b = (y + h) - (y2 + h2);
134    if (*spc_t < 0) *spc_t = 0;
135    if (*spc_b < 0) *spc_b = 0;
136 }
137
138 static Content_Info *
139 _elm_hover_smart_content_location_get(Elm_Hover_Smart_Data *sd,
140                                       Evas_Coord spc_l,
141                                       Evas_Coord spc_t,
142                                       Evas_Coord spc_r,
143                                       Evas_Coord spc_b)
144 {
145    Evas_Coord c_w = 0, c_h = 0, mid_w, mid_h;
146    int max;
147
148    evas_object_size_hint_min_get(sd->smt_sub->obj, &c_w, &c_h);
149    mid_w = c_w / 2;
150    mid_h = c_h / 2;
151
152    if (spc_l > spc_r) goto left;
153
154    max = MAX(spc_t, spc_r);
155    max = MAX(max, spc_b);
156
157    if (max == spc_t)
158      {
159         if (mid_w > spc_l) return _HOV_TOP_RIGHT;
160
161         return _HOV_TOP;
162      }
163
164    if (max == spc_r)
165      {
166         if (mid_h > spc_t) return _HOV_BOTTOM_RIGHT;
167         else if (mid_h > spc_b)
168           return _HOV_TOP_RIGHT;
169
170         return _HOV_RIGHT;
171      }
172
173    if (mid_h > spc_l)
174      return _HOV_BOTTOM_RIGHT;
175
176    return _HOV_BOTTOM;
177
178 left:
179    max = MAX(spc_t, spc_l);
180    max = MAX(max, spc_b);
181
182    if (max == spc_t)
183      {
184         if (mid_w > spc_r) return _HOV_TOP_LEFT;
185
186         return _HOV_TOP;
187      }
188
189    if (max == spc_l)
190      {
191         if (mid_h > spc_t) return _HOV_BOTTOM_LEFT;
192         else if (mid_h > spc_b)
193           return _HOV_TOP_LEFT;
194
195         return _HOV_LEFT;
196      }
197
198    if (mid_h > spc_r) return _HOV_BOTTOM_LEFT;
199
200    return _HOV_BOTTOM;
201 }
202
203 static void
204 _elm_hover_smt_sub_re_eval(Evas_Object *obj)
205 {
206    Evas_Coord spc_l, spc_r, spc_t, spc_b;
207    Content_Info *prev;
208    Evas_Object *sub;
209    char buf[1024];
210
211    ELM_HOVER_DATA_GET(obj, sd);
212
213    if (!sd->smt_sub) return;
214    prev = sd->smt_sub;
215
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);
218
219    sub = sd->smt_sub->obj;
220
221    sd->smt_sub->obj = NULL;
222
223    sd->smt_sub =
224      _elm_hover_smart_content_location_get(sd, spc_l, spc_t, spc_r, spc_b);
225
226    sd->smt_sub->obj = sub;
227
228    if (sd->smt_sub != prev)
229      evas_object_smart_callback_call
230        (obj, SIG_SMART_LOCATION_CHANGED, (void *)sd->smt_sub->swallow);
231
232    if (elm_widget_mirrored_get(obj))
233      {
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;
245      }
246
247    snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", sd->smt_sub->swallow);
248    elm_layout_content_set(obj, buf, sd->smt_sub->obj);
249 }
250
251 static void
252 _hov_show_do(Evas_Object *obj)
253 {
254    ELM_HOVER_DATA_GET(obj, sd);
255
256    elm_layout_signal_emit(obj, "elm,action,show", "elm");
257
258    ELM_HOVER_PARTS_FOREACH
259    {
260       char buf[1024];
261
262       if (sd->subs[i].obj)
263         {
264            snprintf
265              (buf, sizeof(buf), "elm,action,slot,%s,show",
266              sd->subs[i].swallow);
267
268            elm_layout_signal_emit(obj, buf, "elm");
269         }
270    }
271 }
272
273 static Eina_Bool
274 _elm_hover_smart_theme(Evas_Object *obj)
275 {
276    ELM_HOVER_DATA_GET(obj, sd);
277
278    if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->theme(obj)) return EINA_FALSE;
279
280    if (sd->smt_sub) _elm_hover_smt_sub_re_eval(obj);
281
282    elm_layout_sizing_eval(obj);
283
284    if (evas_object_visible_get(obj)) _hov_show_do(obj);
285
286    return EINA_TRUE;
287 }
288
289 static void
290 _elm_hover_smart_sizing_eval(Evas_Object *obj)
291 {
292    Evas_Coord ofs_x, x = 0, y = 0, w = 0, h = 0, x2 = 0,
293               y2 = 0, w2 = 0, h2 = 0;
294
295    ELM_HOVER_DATA_GET(obj, sd);
296
297    if (sd->on_del) return;
298
299    if (sd->parent) evas_object_geometry_get(sd->parent, &x, &y, &w, &h);
300    evas_object_geometry_get(obj, &x2, &y2, &w2, &h2);
301
302    if (elm_widget_mirrored_get(obj)) ofs_x = w - (x2 - x) - w2;
303    else ofs_x = x2 - x;
304
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);
309 }
310
311 static void
312 _on_smt_sub_changed(void *data,
313                     Evas *e __UNUSED__,
314                     Evas_Object *obj __UNUSED__,
315                     void *event_info __UNUSED__)
316 {
317    _elm_hover_smt_sub_re_eval(data);
318 }
319
320 static Eina_Bool
321 _elm_hover_smart_sub_object_add(Evas_Object *obj,
322                                 Evas_Object *sobj)
323 {
324    ELM_HOVER_DATA_GET(obj, sd);
325
326    if (evas_object_data_get(sobj, "elm-parent") == obj)
327      return EINA_TRUE;
328
329    if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->sub_object_add(obj, sobj))
330      return EINA_FALSE;
331
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);
335
336    return EINA_TRUE;
337 }
338
339 static Eina_Bool
340 _elm_hover_smart_sub_object_del(Evas_Object *obj,
341                                 Evas_Object *sobj)
342 {
343    ELM_HOVER_DATA_GET(obj, sd);
344
345    if (!ELM_WIDGET_CLASS(_elm_hover_parent_sc)->sub_object_del(obj, sobj))
346      return EINA_FALSE;
347
348    if (sd->smt_sub && sd->smt_sub->obj == sobj)
349      {
350         evas_object_event_callback_del_full
351           (sd->smt_sub->obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
352           _on_smt_sub_changed, obj);
353
354         sd->smt_sub->obj = NULL;
355         sd->smt_sub = NULL;
356      }
357    else
358      {
359         ELM_HOVER_PARTS_FOREACH
360         {
361            if (sd->subs[i].obj == sobj)
362              {
363                 sd->subs[i].obj = NULL;
364                 break;
365              }
366         }
367      }
368
369    return EINA_TRUE;
370 }
371
372 static void
373 _elm_hover_subs_del(Elm_Hover_Smart_Data *sd)
374 {
375    ELM_HOVER_PARTS_FOREACH
376    {
377       if (sd->subs[i].obj)
378         {
379            evas_object_del(sd->subs[i].obj);
380            sd->subs[i].obj = NULL;
381         }
382    }
383 }
384
385 static Eina_Bool
386 _elm_hover_smart_content_set(Evas_Object *obj,
387                              const char *swallow,
388                              Evas_Object *content)
389 {
390    ELM_HOVER_CHECK(obj) EINA_FALSE;
391    ELM_HOVER_DATA_GET(obj, sd);
392
393    if (!swallow) return EINA_FALSE;
394
395    if (!strcmp(swallow, "smart"))
396      {
397         if (sd->smt_sub)     /* already under 'smart' mode */
398           {
399              if (sd->smt_sub->obj != content)
400                {
401                   evas_object_del(sd->smt_sub->obj);
402                   sd->smt_sub = _HOV_LEFT;
403                   sd->smt_sub->obj = content;
404                }
405
406              if (!content)
407                {
408                   sd->smt_sub->obj = NULL;
409                   sd->smt_sub = NULL;
410                }
411              else _elm_hover_smt_sub_re_eval(obj);
412
413              goto end;
414           }
415         else     /* switch from pristine spots to 'smart' */
416           {
417              _elm_hover_subs_del(sd);
418              sd->smt_sub = _HOV_LEFT;
419              sd->smt_sub->obj = content;
420
421              _elm_hover_smt_sub_re_eval(obj);
422
423              goto end;
424           }
425      }
426
427    if (!ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_set
428          (obj, swallow, content))
429      return EINA_FALSE;
430
431    if (strstr(swallow, "elm.swallow.slot."))
432      swallow += sizeof("elm.swallow.slot.");
433
434    ELM_HOVER_PARTS_FOREACH
435    {
436       if (!strcmp(swallow, sd->subs[i].swallow))
437         {
438            sd->subs[i].obj = content;
439            break;
440         }
441    }
442
443 end:
444    elm_layout_sizing_eval(obj);
445    return EINA_TRUE;
446 }
447
448 static Evas_Object *
449 _elm_hover_smart_content_get(const Evas_Object *obj,
450                              const char *swallow)
451 {
452    ELM_HOVER_CHECK(obj) NULL;
453
454    ELM_HOVER_DATA_GET(obj, sd);
455
456    if (!swallow) return NULL;
457
458    if (!strcmp(swallow, "smart"))
459      return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_get
460               (obj, sd->smt_sub->swallow);
461
462    return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_get(obj, swallow);
463 }
464
465 static Evas_Object *
466 _elm_hover_smart_content_unset(Evas_Object *obj,
467                                const char *swallow)
468 {
469    ELM_HOVER_CHECK(obj) NULL;
470
471    ELM_HOVER_DATA_GET(obj, sd);
472
473    if (!swallow) return NULL;
474
475    if (!strcmp(swallow, "smart"))
476      return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_unset
477               (obj, sd->smt_sub->swallow);
478
479    return ELM_CONTAINER_CLASS(_elm_hover_parent_sc)->content_unset
480             (obj, swallow);
481
482    return NULL;
483 }
484
485 static void
486 _target_del_cb(void *data,
487                Evas *e __UNUSED__,
488                Evas_Object *obj __UNUSED__,
489                void *event_info __UNUSED__)
490 {
491    ELM_HOVER_DATA_GET(data, sd);
492
493    sd->target = NULL;
494 }
495
496 static void
497 _target_move_cb(void *data,
498                 Evas *e __UNUSED__,
499                 Evas_Object *obj __UNUSED__,
500                 void *event_info __UNUSED__)
501 {
502    elm_layout_sizing_eval(data);
503    _elm_hover_smt_sub_re_eval(data);
504 }
505
506 static void
507 _hov_dismiss_cb(void *data,
508                 Evas_Object *obj __UNUSED__,
509                 const char *emission __UNUSED__,
510                 const char *source __UNUSED__)
511 {
512    evas_object_hide(data);
513    evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
514 }
515
516 static void
517 _elm_hover_smart_add(Evas_Object *obj)
518 {
519    unsigned int i;
520
521    EVAS_SMART_DATA_ALLOC(obj, Elm_Hover_Smart_Data);
522
523    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.add(obj);
524
525    for (i = 0; i < sizeof(priv->subs) / sizeof(priv->subs[0]); i++)
526      priv->subs[i].swallow = _content_aliases[i].alias;
527
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);
531
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);
535
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);
539
540    elm_layout_content_set(obj, "elm.swallow.offset", priv->offset);
541    elm_layout_content_set(obj, "elm.swallow.size", priv->size);
542
543    elm_widget_can_focus_set(obj, EINA_TRUE);
544 }
545
546 static void
547 _elm_hover_smart_del(Evas_Object *obj)
548 {
549    ELM_HOVER_DATA_GET(obj, sd);
550
551    sd->on_del = EINA_TRUE;
552
553    if (evas_object_visible_get(obj))
554      evas_object_smart_callback_call(obj, SIG_CLICKED, NULL);
555
556    elm_hover_target_set(obj, NULL);
557
558    _elm_hover_parent_detach(obj);
559    sd->parent = NULL;
560
561    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.del(obj);
562 }
563
564 static void
565 _elm_hover_smart_move(Evas_Object *obj,
566                       Evas_Coord x,
567                       Evas_Coord y)
568 {
569    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.move(obj, x, y);
570
571    elm_layout_sizing_eval(obj);
572 }
573
574 static void
575 _elm_hover_smart_resize(Evas_Object *obj,
576                         Evas_Coord w,
577                         Evas_Coord h)
578 {
579    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.resize(obj, w, h);
580
581    elm_layout_sizing_eval(obj);
582 }
583
584 static void
585 _elm_hover_smart_show(Evas_Object *obj)
586 {
587    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.show(obj);
588
589    _hov_show_do(obj);
590 }
591
592 static void
593 _elm_hover_smart_hide(Evas_Object *obj)
594 {
595    ELM_HOVER_DATA_GET(obj, sd);
596
597    ELM_WIDGET_CLASS(_elm_hover_parent_sc)->base.hide(obj);
598
599    elm_layout_signal_emit(obj, "elm,action,hide", "elm");
600
601    ELM_HOVER_PARTS_FOREACH
602    {
603       char buf[1024];
604
605       if (sd->subs[i].obj)
606         {
607            snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide",
608                     sd->subs[i].swallow);
609            elm_layout_signal_emit(obj, buf, "elm");
610         }
611    }
612 }
613
614 static void
615 _elm_hover_smart_parent_set(Evas_Object *obj,
616                             Evas_Object *parent)
617 {
618    elm_hover_parent_set(obj, parent);
619
620    elm_layout_sizing_eval(obj);
621 }
622
623 static void
624 _elm_hover_smart_set_user(Elm_Hover_Smart_Class *sc)
625 {
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;
632
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;
637
638    /* not a 'focus chain manager' */
639    ELM_WIDGET_CLASS(sc)->focus_next = NULL;
640    ELM_WIDGET_CLASS(sc)->focus_direction = NULL;
641
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;
645
646    ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_hover_smart_sizing_eval;
647
648    ELM_LAYOUT_CLASS(sc)->content_aliases = _content_aliases;
649 }
650
651 EAPI const Elm_Hover_Smart_Class *
652 elm_hover_smart_class_get(void)
653 {
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;
658
659    if (class)
660      return class;
661
662    _elm_hover_smart_set(&_sc);
663    esc->callbacks = _smart_callbacks;
664    class = &_sc;
665
666    return class;
667 }
668
669 EAPI Evas_Object *
670 elm_hover_add(Evas_Object *parent)
671 {
672    Evas_Object *obj;
673
674    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
675
676    obj = elm_widget_add(_elm_hover_smart_class_new(), parent);
677    if (!obj) return NULL;
678
679    if (!elm_widget_sub_object_add(parent, obj))
680      ERR("could not add %p as sub object of %p", obj, parent);
681
682    return obj;
683 }
684
685 EAPI void
686 elm_hover_target_set(Evas_Object *obj,
687                      Evas_Object *target)
688 {
689    ELM_HOVER_CHECK(obj);
690    ELM_HOVER_DATA_GET(obj, sd);
691
692    if (sd->target)
693      {
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);
699      }
700
701    sd->target = target;
702    if (sd->target)
703      {
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);
710      }
711 }
712
713 EAPI void
714 elm_hover_parent_set(Evas_Object *obj,
715                      Evas_Object *parent)
716 {
717    ELM_HOVER_CHECK(obj);
718    ELM_HOVER_DATA_GET(obj, sd);
719
720    _elm_hover_parent_detach(obj);
721
722    sd->parent = parent;
723    if (sd->parent)
724      {
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);
735      }
736
737    elm_layout_sizing_eval(obj);
738 }
739
740 EAPI Evas_Object *
741 elm_hover_target_get(const Evas_Object *obj)
742 {
743    ELM_HOVER_CHECK(obj) NULL;
744    ELM_HOVER_DATA_GET(obj, sd);
745
746    return sd->target;
747 }
748
749 EAPI Evas_Object *
750 elm_hover_parent_get(const Evas_Object *obj)
751 {
752    ELM_HOVER_CHECK(obj) NULL;
753    ELM_HOVER_DATA_GET(obj, sd);
754
755    return sd->parent;
756 }
757
758 EAPI const char *
759 elm_hover_best_content_location_get(const Evas_Object *obj,
760                                     Elm_Hover_Axis pref_axis)
761 {
762    Evas_Coord spc_l, spc_r, spc_t, spc_b;
763
764    ELM_HOVER_CHECK(obj) NULL;
765    ELM_HOVER_DATA_GET(obj, sd);
766
767    _elm_hover_left_space_calc(sd, &spc_l, &spc_t, &spc_r, &spc_b);
768
769    if (pref_axis == ELM_HOVER_AXIS_HORIZONTAL)
770      {
771         if (spc_l < spc_r) return (_HOV_RIGHT)->swallow;
772         else return (_HOV_LEFT)->swallow;
773      }
774    else if (pref_axis == ELM_HOVER_AXIS_VERTICAL)
775      {
776         if (spc_t < spc_b) return (_HOV_BOTTOM)->swallow;
777         else return (_HOV_TOP)->swallow;
778      }
779
780    if (spc_l < spc_r)
781      {
782         if (spc_t > spc_r) return (_HOV_TOP)->swallow;
783         else if (spc_b > spc_r)
784           return (_HOV_BOTTOM)->swallow;
785
786         return (_HOV_RIGHT)->swallow;
787      }
788
789    if (spc_t > spc_r) return (_HOV_TOP)->swallow;
790    else if (spc_b > spc_r)
791      return (_HOV_BOTTOM)->swallow;
792
793    return (_HOV_LEFT)->swallow;
794 }
795
796 EAPI void
797 elm_hover_dismiss(Evas_Object *obj)
798 {
799    ELM_HOVER_CHECK(obj);
800
801    elm_layout_signal_emit(obj, "elm,action,dismiss", "");
802 }