61893c97afb9399f01acbb18184879e7a4095523
[framework/uifw/elementary.git] / src / lib / elm_hover.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5 typedef struct _Content_Info Content_Info;
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 = 0; \
12   for (i = 0; i < sizeof(wd->subs) / sizeof(wd->subs[0]); i++)
13
14 static const char *_directions[] = {
15   "left",
16   "top-left",
17   "top",
18   "top-right",
19   "right",
20   "bottom-right",
21   "bottom",
22   "bottom-left",
23   "middle"
24 };
25
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])
35
36 struct _Content_Info
37 {
38    const char *swallow;
39    Evas_Object *obj;
40 };
41
42 struct _Widget_Data
43 {
44    Evas_Object *hov, *cov;
45    Evas_Object *offset, *size;
46    Evas_Object *parent, *target;
47    Evas_Object *smt_sub;
48    Content_Info subs[sizeof(_directions)/sizeof(_directions[0])];
49 };
50
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);
67
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[] = {
71        {SIG_CLICKED, ""},
72        {SIG_SMART_LOCATION_CHANGED, ""},
73        {NULL, NULL}
74 };
75
76 static void
77 _del_pre_hook(Evas_Object *obj)
78 {
79    Widget_Data *wd = elm_widget_data_get(obj);
80    if (!wd)
81      return;
82
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);
91 }
92
93 static void
94 _del_hook(Evas_Object *obj)
95 {
96    Widget_Data *wd = elm_widget_data_get(obj);
97    if (!wd) return;
98    free(wd);
99 }
100
101 static void
102 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
103 {
104    Widget_Data *wd = elm_widget_data_get(obj);
105    if (!wd) return;
106    if (elm_widget_focus_get(obj))
107      {
108         edje_object_signal_emit(wd->cov, "elm,action,focus", "elm");
109         evas_object_focus_set(wd->cov, EINA_TRUE);
110      }
111    else
112      {
113         edje_object_signal_emit(wd->cov, "elm,action,unfocus", "elm");
114         evas_object_focus_set(wd->cov, EINA_FALSE);
115      }
116 }
117
118 static void
119 _mirrored_set(Evas_Object *obj, Eina_Bool rtl)
120 {
121    Widget_Data *wd = elm_widget_data_get(obj);
122    if (!wd) return;
123    edje_object_mirrored_set(wd->cov, rtl);
124 }
125
126 static void
127 _theme_hook(Evas_Object *obj)
128 {
129    Widget_Data *wd = elm_widget_data_get(obj);
130    if (!wd) return;
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) *
136                          _elm_config->scale);
137
138    if (wd->smt_sub)
139      _elm_hover_sub_obj_placement_eval(obj);
140    else
141      _reval_content(obj);
142    _sizing_eval(obj);
143    if (evas_object_visible_get(wd->cov)) _hov_show_do(obj);
144 }
145
146 static void
147 _signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
148 {
149    Widget_Data *wd;
150
151    wd = elm_widget_data_get(obj);
152    if (!wd)
153      return;
154
155    edje_object_signal_emit(wd->cov, emission, source);
156 }
157
158 static void
159 _signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
160 {
161    Widget_Data *wd;
162
163    wd = elm_widget_data_get(obj);
164    if (!wd)
165      return;
166
167    edje_object_signal_callback_add(wd->hov, emission, source, func_cb, data);
168 }
169
170 static void
171 _signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
172 {
173    Widget_Data *wd;
174
175    wd = elm_widget_data_get(obj);
176
177    edje_object_signal_callback_del_full(wd->hov, emission, source, func_cb,
178                                         data);
179 }
180
181 static void
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)
183 {
184    Evas_Coord x = 0, y = 0, w = 0, h = 0, x2 = 0, y2 = 0, w2 = 0, h2 = 0;
185
186    if (wd->parent)
187      evas_object_geometry_get(wd->parent, &x, &y, &w, &h);
188    if (wd->target)
189      evas_object_geometry_get(wd->target, &x2, &y2, &w2, &h2);
190
191    *spc_l = x2 - x;
192    *spc_r = (x + w) - (x2 + w2);
193    if (*spc_l < 0)
194      *spc_l = 0;
195    if (*spc_r < 0)
196      *spc_r = 0;
197
198    *spc_t = y2 - y;
199    *spc_b = (y + h) - (y2 + h2);
200    if (*spc_t < 0)
201      *spc_t = 0;
202    if (*spc_b < 0)
203      *spc_b = 0;
204 }
205
206 static void
207 _sizing_eval(Evas_Object *obj)
208 {
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;
211    if (!wd) return;
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);
214
215    if (elm_widget_mirrored_get(obj))
216      ofs_x = w - (x2 - x) - w2;
217    else
218      ofs_x = x2 - x;
219
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);
226 }
227
228 static void
229 _reval_content(Evas_Object *obj)
230 {
231    Widget_Data *wd = elm_widget_data_get(obj);
232    if (!wd)
233      return;
234
235    ELM_HOVER_PARTS_FOREACH
236      {
237         char buf[1024];
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);
240      }
241 }
242
243 static const char *
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)
245 {
246    Evas_Coord c_w = 0, c_h = 0, mid_w, mid_h;
247    int max;
248
249    evas_object_size_hint_min_get(wd->smt_sub, &c_w, &c_h);
250    mid_w = c_w / 2;
251    mid_h = c_h / 2;
252
253    if (spc_l > spc_r)
254      goto left;
255
256    max = MAX(spc_t, spc_r);
257    max = MAX(max, spc_b);
258
259    if (max == spc_t)
260      {
261         if (mid_w > spc_l)
262           return _HOV_TOP_RIGHT;
263
264         return _HOV_TOP;
265      }
266
267    if (max == spc_r)
268      {
269         if (mid_h > spc_t)
270           return _HOV_BOTTOM_RIGHT;
271         else if (mid_h > spc_b)
272           return _HOV_TOP_RIGHT;
273
274         return _HOV_RIGHT;
275      }
276
277    if (mid_h > spc_l)
278      return _HOV_BOTTOM_RIGHT;
279
280    return _HOV_BOTTOM;
281
282 left:
283    max = MAX(spc_t, spc_l);
284    max = MAX(max, spc_b);
285
286    if (max == spc_t)
287      {
288         if (mid_w > spc_r)
289           return _HOV_TOP_LEFT;
290
291         return _HOV_TOP;
292      }
293
294    if (max == spc_l)
295      {
296         if (mid_h > spc_t)
297           return _HOV_BOTTOM_LEFT;
298         else if (mid_h > spc_b)
299           return _HOV_TOP_LEFT;
300
301         return _HOV_LEFT;
302      }
303
304    if (mid_h > spc_r)
305      return _HOV_BOTTOM_LEFT;
306
307    return _HOV_BOTTOM;
308 }
309
310 static void
311 _sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
312 {
313    Widget_Data *wd;
314    Evas_Object *sub;
315
316    sub = event_info;
317    wd = elm_widget_data_get(obj);
318    if (!wd)
319      return;
320
321    if (wd->smt_sub)
322      {
323         if (wd->smt_sub == sub)
324           wd->smt_sub = NULL;
325      }
326    else
327      {
328         ELM_HOVER_PARTS_FOREACH
329           {
330              if (wd->subs[i].obj == sub)
331                {
332                   wd->subs[i].obj = NULL;
333                   break;
334                }
335           }
336      }
337 }
338
339 static void
340 _hov_show_do(Evas_Object *obj)
341 {
342    Widget_Data *wd = elm_widget_data_get(obj);
343    if (!wd)
344      return;
345
346    if (wd->cov)
347      {
348         evas_object_show(wd->cov);
349         edje_object_signal_emit(wd->cov, "elm,action,show", "elm");
350      }
351
352    ELM_HOVER_PARTS_FOREACH
353      {
354         char buf[1024];
355
356         if (wd->subs[i].obj)
357           {
358              snprintf(buf, sizeof(buf), "elm,action,slot,%s,show",
359                       wd->subs[i].swallow);
360              edje_object_signal_emit(wd->cov, buf, "elm");
361           }
362      }
363 }
364
365 static void
366 _hov_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
367 {
368    _sizing_eval(data);
369 }
370
371 static void
372 _hov_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
373 {
374    _sizing_eval(data);
375 }
376
377 static void
378 _hov_show(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
379 {
380    _hov_show_do(data);
381 }
382
383 static void
384 _hov_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
385 {
386    Widget_Data *wd = elm_widget_data_get(data);
387    if (!wd) return;
388    if (wd->cov)
389      {
390         edje_object_signal_emit(wd->cov, "elm,action,hide", "elm");
391         evas_object_hide(wd->cov);
392      }
393
394    ELM_HOVER_PARTS_FOREACH
395      {
396         char buf[1024];
397
398         if (wd->subs[i].obj)
399           {
400              snprintf(buf, sizeof(buf), "elm,action,slot,%s,hide",
401                       wd->subs[i].swallow);
402              edje_object_signal_emit(wd->cov, buf, "elm");
403           }
404      }
405 }
406
407 static void
408 _target_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
409 {
410    Widget_Data *wd = elm_widget_data_get(data);
411    if (!wd) return;
412    wd->target = NULL;
413 }
414
415 static void
416 _target_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
417 {
418    Widget_Data *wd = elm_widget_data_get(data);
419    if (!wd)
420      return;
421
422    _sizing_eval(data);
423    _elm_hover_sub_obj_placement_eval(data);
424 }
425
426 static void
427 _signal_dismiss(void *data, Evas_Object *obj __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
428 {
429    Widget_Data *wd = elm_widget_data_get(data);
430    if (!wd) return;
431    evas_object_hide(data);
432    evas_object_smart_callback_call(data, SIG_CLICKED, NULL);
433 }
434
435 static void
436 _parent_move(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
437 {
438    _sizing_eval(data);
439 }
440
441 static void
442 _parent_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
443 {
444    _sizing_eval(data);
445 }
446
447 static void
448 _parent_show(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
449 {
450 }
451
452 static void
453 _parent_hide(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
454 {
455    Widget_Data *wd = elm_widget_data_get(data);
456    if (!wd) return;
457    evas_object_hide(wd->cov);
458 }
459
460 static void
461 _parent_del(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
462 {
463    Widget_Data *wd = elm_widget_data_get(data);
464    if (!wd) return;
465    elm_hover_parent_set(data, NULL);
466    _sizing_eval(data);
467 }
468
469 EAPI Evas_Object *
470 elm_hover_add(Evas_Object *parent)
471 {
472    Evas_Object *obj;
473    Evas *e;
474    Widget_Data *wd;
475
476    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
477
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);
490
491    ELM_HOVER_PARTS_FOREACH
492       wd->subs[i].swallow = _directions[i];
493
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);
502
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);
508
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);
513
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);
518
519    edje_object_part_swallow(wd->cov, "elm.swallow.offset", wd->offset);
520    edje_object_part_swallow(wd->cov, "elm.swallow.size", wd->size);
521
522    evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
523
524    elm_hover_parent_set(obj, parent);
525    evas_object_smart_callbacks_descriptions_set(obj, _signals);
526
527    _mirrored_set(obj, elm_widget_mirrored_get(obj));
528    _sizing_eval(obj);
529    return obj;
530 }
531
532 EAPI void
533 elm_hover_target_set(Evas_Object *obj, Evas_Object *target)
534 {
535    ELM_CHECK_WIDTYPE(obj, widtype);
536    Widget_Data *wd = elm_widget_data_get(obj);
537
538    if (wd->target)
539      {
540         evas_object_event_callback_del_full(wd->target, EVAS_CALLBACK_DEL,
541                                             _target_del, obj);
542         evas_object_event_callback_del_full(wd->target, EVAS_CALLBACK_MOVE,
543                                             _target_move, obj);
544      }
545    wd->target = target;
546    if (wd->target)
547      {
548         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_DEL,
549                                        _target_del, obj);
550         evas_object_event_callback_add(wd->target, EVAS_CALLBACK_MOVE,
551                                        _target_move, obj);
552         elm_widget_hover_object_set(target, obj);
553         _sizing_eval(obj);
554      }
555 }
556
557
558 EAPI void
559 elm_hover_parent_set(Evas_Object *obj, Evas_Object *parent)
560 {
561    ELM_CHECK_WIDTYPE(obj, widtype);
562    Widget_Data *wd = elm_widget_data_get(obj);
563    if (!wd) return;
564    if (wd->parent)
565      {
566         evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_MOVE,
567                                             _parent_move, obj);
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,
571                                             _parent_show, obj);
572         evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_HIDE,
573                                             _parent_hide, obj);
574         evas_object_event_callback_del_full(wd->parent, EVAS_CALLBACK_DEL,
575                                             _parent_del, obj);
576      }
577    wd->parent = parent;
578    if (wd->parent)
579      {
580         evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_MOVE,
581                                        _parent_move, obj);
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,
585                                        _parent_show, obj);
586         evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_HIDE,
587                                        _parent_hide, obj);
588         evas_object_event_callback_add(wd->parent, EVAS_CALLBACK_DEL,
589                                        _parent_del, obj);
590         //      elm_widget_sub_object_add(parent, obj);
591      }
592    _sizing_eval(obj);
593 }
594
595 EAPI Evas_Object *
596 elm_hover_target_get(const Evas_Object *obj)
597 {
598    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
599    Widget_Data *wd = elm_widget_data_get(obj);
600    if (!wd) return NULL;
601
602    return wd->target;
603 }
604
605 EAPI Evas_Object *
606 elm_hover_parent_get(const Evas_Object *obj)
607 {
608    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
609    Widget_Data *wd = elm_widget_data_get(obj);
610    if (!wd) return NULL;
611
612    return wd->parent;
613 }
614
615 static void
616 _elm_hover_subs_del(Widget_Data *wd)
617 {
618    ELM_HOVER_PARTS_FOREACH
619      {
620         if (wd->subs[i].obj)
621           {
622              evas_object_del(wd->subs[i].obj);
623              wd->subs[i].obj = NULL;
624           }
625      }
626 }
627
628 static void
629 _elm_hover_sub_obj_placement_eval(Evas_Object *obj)
630 {
631    Evas_Coord spc_l, spc_r, spc_t, spc_b;
632    const char *smart_dir;
633    Widget_Data *wd;
634    char buf[1024];
635
636    wd = elm_widget_data_get(obj);
637    if (!wd->smt_sub)
638      return;
639
640    _elm_hover_left_space_calc(wd, &spc_l, &spc_t, &spc_r, &spc_b);
641
642    edje_object_part_unswallow(wd->cov, wd->smt_sub);
643
644    smart_dir = _elm_hover_smart_content_location_get(wd, spc_l, spc_t, spc_r,
645                                                      spc_b);
646    evas_object_smart_callback_call(obj, SIG_SMART_LOCATION_CHANGED,
647                                    (void *)smart_dir);
648
649    if (elm_widget_mirrored_get(obj))
650      {
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;
663      }
664    snprintf(buf, sizeof(buf), "elm.swallow.slot.%s", smart_dir);
665    edje_object_part_swallow(wd->cov, buf, wd->smt_sub);
666 }
667
668 static void
669 _elm_hover_sub_obj_placement_eval_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
670 {
671    _elm_hover_sub_obj_placement_eval(data);
672 }
673
674 EAPI void
675 elm_hover_content_set(Evas_Object *obj, const char *swallow, Evas_Object *content)
676 {
677    ELM_CHECK_WIDTYPE(obj, widtype);
678
679    Widget_Data *wd;
680
681    wd = elm_widget_data_get(obj);
682    if (!wd)
683      return;
684
685    if (!strcmp(swallow, "smart"))
686      {
687         if (wd->smt_sub != content)
688           {
689              _elm_hover_subs_del(wd);
690              wd->smt_sub = content;
691           }
692
693         if (content)
694           {
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,
699                                             obj);
700
701              _elm_hover_sub_obj_placement_eval(obj);
702           }
703
704         goto end;
705      }
706
707    if (wd->smt_sub)
708      {
709         evas_object_del(wd->smt_sub);
710         wd->smt_sub = NULL;
711      }
712
713    ELM_HOVER_PARTS_FOREACH
714      {
715         if (!strcmp(swallow, wd->subs[i].swallow))
716           {
717              if (content == wd->subs[i].obj)
718                return;
719              evas_object_del(wd->subs[i].obj);
720              wd->subs[i].obj = NULL;
721
722              if (content)
723                {
724                   char buf[1024];
725
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;
730                }
731              break;
732           }
733      }
734
735 end:
736    _sizing_eval(obj);
737 }
738
739 EAPI Evas_Object *
740 elm_hover_content_get(const Evas_Object *obj, const char *swallow)
741 {
742    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
743
744    Widget_Data *wd;
745
746    wd = elm_widget_data_get(obj);
747    if (!wd)
748      return NULL;
749
750    if (!strcmp(swallow, "smart"))
751      return wd->smt_sub;
752
753    ELM_HOVER_PARTS_FOREACH
754       if (!strcmp(swallow, wd->subs[i].swallow))
755         return wd->subs[i].obj;
756
757    return NULL;
758 }
759
760 static void
761 _elm_hover_sub_obj_unparent(Evas_Object *obj)
762 {
763    Widget_Data *wd;
764
765    wd = elm_widget_data_get(obj);
766
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,
771                                        obj);
772    edje_object_part_unswallow(wd->cov, wd->smt_sub);
773    wd->smt_sub = NULL;
774 }
775
776 EAPI Evas_Object *
777 elm_hover_content_unset(Evas_Object *obj, const char *swallow)
778 {
779    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
780
781    Widget_Data *wd;
782
783    wd = elm_widget_data_get(obj);
784    if (!wd)
785      return NULL;
786
787    if (!strcmp(swallow, "smart"))
788      {
789         Evas_Object *content;
790
791         if (!wd->smt_sub)
792           return NULL;
793
794         content = wd->smt_sub;
795         _elm_hover_sub_obj_unparent(obj);
796         return content;
797      }
798
799    ELM_HOVER_PARTS_FOREACH
800      {
801         if (!strcmp(swallow, wd->subs[i].swallow))
802           {
803              Evas_Object *content;
804
805              if (!wd->subs[i].obj)
806                return NULL;
807
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;
812
813              return content;
814           }
815      }
816
817    return NULL;
818 }
819
820 EAPI const char *
821 elm_hover_best_content_location_get(const Evas_Object *obj, Elm_Hover_Axis pref_axis)
822 {
823    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
824
825    Evas_Coord spc_l, spc_r, spc_t, spc_b;
826    Widget_Data *wd;
827
828    wd = elm_widget_data_get(obj);
829    if (!wd)
830      return NULL;
831
832    _elm_hover_left_space_calc(wd, &spc_l, &spc_t, &spc_r, &spc_b);
833
834    if (pref_axis == ELM_HOVER_AXIS_HORIZONTAL)
835      {
836         if (spc_l < spc_r) return _HOV_RIGHT;
837         else return _HOV_LEFT;
838      }
839    else if (pref_axis == ELM_HOVER_AXIS_VERTICAL)
840      {
841         if (spc_t < spc_b) return _HOV_BOTTOM;
842         else return _HOV_TOP;
843      }
844
845    if (spc_l < spc_r)
846      {
847         if (spc_t > spc_r) return _HOV_TOP;
848         else if (spc_b > spc_r) return _HOV_BOTTOM;
849         return _HOV_RIGHT;
850      }
851    if (spc_t > spc_r) return _HOV_TOP;
852    else if (spc_b > spc_r) return _HOV_BOTTOM;
853    return _HOV_LEFT;
854 }
855
856 EAPI void
857 elm_hover_dismiss(Evas_Object *obj)
858 {
859    Widget_Data *wd;
860    ELM_CHECK_WIDTYPE(obj, widtype);
861    wd = elm_widget_data_get(obj);
862    if (!wd) return;
863
864    edje_object_signal_emit(wd->cov, "elm,action,dismiss", "");
865 }