[elc_naviframe]: As hide signal was sent twice, control bar was hidden
[framework/uifw/elementary.git] / src / lib / els_tooltip.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 static const char _tooltip_key[] = "_elm_tooltip";
5
6 #define ELM_TOOLTIP_GET_OR_RETURN(tt, obj, ...)         \
7   Elm_Tooltip *tt;                                      \
8   do                                                    \
9     {                                                   \
10        if (!(obj))                                      \
11          {                                              \
12             CRITICAL("Null pointer: " #obj);            \
13             return __VA_ARGS__;                         \
14          }                                              \
15        tt = evas_object_data_get((obj), _tooltip_key);  \
16        if (!tt)                                         \
17          {                                              \
18             ERR("Object does not have tooltip: " #obj); \
19             return __VA_ARGS__;                         \
20          }                                              \
21     }                                                   \
22   while (0)
23
24 struct _Elm_Tooltip
25 {
26    Elm_Tooltip_Content_Cb   func;
27    Evas_Smart_Cb            del_cb;
28    const void              *data;
29    const char              *style;
30    Evas                    *evas, *tt_evas;
31    Evas_Object             *eventarea, *owner;
32    Evas_Object             *tooltip, *content;
33    Evas_Object             *tt_win;
34    Ecore_Timer             *show_timer;
35    Ecore_Timer             *hide_timer;
36    Ecore_Job               *reconfigure_job;
37    struct {
38       Evas_Coord            x, y, bx, by;
39    } pad;
40    struct {
41       double                x, y;
42    } rel_pos;
43    double                   hide_timeout; /* from theme */
44    Eina_Bool                visible_lock:1;
45    Eina_Bool                changed_style:1;
46    Eina_Bool                free_size : 1;
47 };
48
49 static void _elm_tooltip_reconfigure(Elm_Tooltip *tt);
50 static void _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt);
51 static void _elm_tooltip_reconfigure_job_stop(Elm_Tooltip *tt);
52 static void _elm_tooltip_hide_anim_start(Elm_Tooltip *tt);
53 static void _elm_tooltip_hide_anim_stop(Elm_Tooltip *tt);
54 static void _elm_tooltip_show_timer_stop(Elm_Tooltip *tt);
55 static void _elm_tooltip_hide(Elm_Tooltip *tt);
56 static void _elm_tooltip_data_clean(Elm_Tooltip *tt);
57
58 static void
59 _elm_tooltip_content_changed_hints_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
60 {
61    _elm_tooltip_reconfigure_job_start(data);
62 }
63
64 static void
65 _elm_tooltip_content_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
66 {
67    Elm_Tooltip *tt = data;
68    tt->content = NULL;
69    tt->visible_lock = EINA_FALSE;
70    if (tt->tooltip) _elm_tooltip_hide(tt);
71 }
72
73 static void
74 _elm_tooltip_obj_move_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
75 {
76    Elm_Tooltip *tt = data;
77    _elm_tooltip_reconfigure_job_start(tt);
78 }
79
80 static void
81 _elm_tooltip_obj_resize_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
82 {
83    Elm_Tooltip *tt = data;
84    _elm_tooltip_reconfigure_job_start(tt);
85 }
86
87 static void
88 _elm_tooltip_obj_mouse_move_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
89 {
90    Elm_Tooltip *tt = data;
91    _elm_tooltip_reconfigure_job_start(tt);
92 }
93
94 static void
95 _elm_tooltip_show(Elm_Tooltip *tt)
96 {
97    _elm_tooltip_show_timer_stop(tt);
98    _elm_tooltip_hide_anim_stop(tt);
99
100    if (tt->tooltip)
101      {
102         _elm_tooltip_reconfigure_job_start(tt);
103         return;
104      }
105    if (tt->free_size)
106      {
107         tt->tt_win = elm_win_add(NULL, "tooltip", ELM_WIN_BASIC);
108         elm_win_borderless_set(tt->tt_win, EINA_TRUE);
109         elm_win_override_set(tt->tt_win, EINA_TRUE);
110         tt->tt_evas = evas_object_evas_get(tt->tt_win);
111         tt->tooltip = edje_object_add(tt->tt_evas);
112         evas_object_move(tt->tooltip, 0, 0);
113         elm_win_resize_object_add(tt->tt_win, tt->tooltip);
114 #ifdef HAVE_ELEMENTARY_X
115         ecore_x_window_shape_input_rectangle_set(elm_win_xwindow_get(tt->tt_win), 0, 0, 0, 0);
116 #endif
117         evas_object_show(tt->tt_win);
118      }
119    else
120       tt->tooltip = edje_object_add(tt->evas);
121    if (!tt->tooltip) return;
122
123    evas_object_layer_set(tt->tt_win ?: tt->tooltip, ELM_OBJECT_LAYER_TOOLTIP);
124
125    evas_object_event_callback_add
126      (tt->eventarea, EVAS_CALLBACK_MOVE, _elm_tooltip_obj_move_cb, tt);
127    evas_object_event_callback_add
128      (tt->eventarea, EVAS_CALLBACK_RESIZE, _elm_tooltip_obj_resize_cb, tt);
129    evas_object_event_callback_add
130      (tt->eventarea, EVAS_CALLBACK_MOUSE_MOVE, _elm_tooltip_obj_mouse_move_cb, tt);
131
132    tt->changed_style = EINA_TRUE;
133    _elm_tooltip_reconfigure_job_start(tt);
134 }
135
136 static void
137 _elm_tooltip_content_del(Elm_Tooltip *tt)
138 {
139    if (!tt->content) return;
140
141    evas_object_event_callback_del_full
142      (tt->content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
143       _elm_tooltip_content_changed_hints_cb, tt);
144    evas_object_event_callback_del_full
145      (tt->content, EVAS_CALLBACK_DEL,
146       _elm_tooltip_content_del_cb, tt);
147    evas_object_hide(tt->content);
148    evas_object_del(tt->content);
149    tt->content = NULL;
150 }
151
152
153 static void
154 _elm_tooltip_hide(Elm_Tooltip *tt)
155 {
156    Evas_Object *del;
157    _elm_tooltip_show_timer_stop(tt);
158    _elm_tooltip_hide_anim_stop(tt);
159    _elm_tooltip_reconfigure_job_stop(tt);
160
161    if (!tt->tooltip) return;
162    if (tt->visible_lock) return;
163
164    _elm_tooltip_content_del(tt);
165
166    evas_object_event_callback_del_full
167      (tt->eventarea, EVAS_CALLBACK_MOVE, _elm_tooltip_obj_move_cb, tt);
168    evas_object_event_callback_del_full
169      (tt->eventarea, EVAS_CALLBACK_RESIZE, _elm_tooltip_obj_resize_cb, tt);
170    evas_object_event_callback_del_full
171      (tt->eventarea, EVAS_CALLBACK_MOUSE_MOVE, _elm_tooltip_obj_mouse_move_cb, tt);
172
173    del = tt->tt_win ?: tt->tooltip;
174
175    tt->tt_win = NULL;
176    tt->tt_evas = NULL;
177    tt->tooltip = NULL;
178    evas_object_del(del);
179 }
180
181 static void
182 _elm_tooltip_reconfigure_job(void *data)
183 {
184    Elm_Tooltip *tt = data;
185    tt->reconfigure_job = NULL;
186    _elm_tooltip_reconfigure(data);
187 }
188
189 static void
190 _elm_tooltip_reconfigure_job_stop(Elm_Tooltip *tt)
191 {
192    if (!tt->reconfigure_job) return;
193    ecore_job_del(tt->reconfigure_job);
194    tt->reconfigure_job = NULL;
195 }
196
197 static void
198 _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt)
199 {
200    if (tt->reconfigure_job) ecore_job_del(tt->reconfigure_job);
201    tt->reconfigure_job = ecore_job_add(_elm_tooltip_reconfigure_job, tt);
202 }
203
204 static Eina_Bool
205 _elm_tooltip_hide_anim_cb(void *data)
206 {
207    Elm_Tooltip *tt = data;
208    tt->hide_timer = NULL;
209    _elm_tooltip_hide(tt);
210    return EINA_FALSE;
211 }
212
213 static void
214 _elm_tooltip_hide_anim_start(Elm_Tooltip *tt)
215 {
216    double extra = 0;
217    if (tt->hide_timer) return;
218    /* hide slightly faster when in window mode to look less stupid */
219    if ((tt->hide_timeout > 0) && tt->tt_win) extra = 0.1;
220    edje_object_signal_emit(tt->tooltip, "elm,action,hide", "elm");
221    tt->hide_timer = ecore_timer_add
222      (tt->hide_timeout - extra, _elm_tooltip_hide_anim_cb, tt);
223 }
224
225 static void
226 _elm_tooltip_hide_anim_stop(Elm_Tooltip *tt)
227 {
228    if (!tt->hide_timer) return;
229    if (tt->tooltip)
230      edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
231    ecore_timer_del(tt->hide_timer);
232    tt->hide_timer = NULL;
233 }
234
235 static void
236 _elm_tooltip_reconfigure(Elm_Tooltip *tt)
237 {
238    Evas_Coord ox, oy, ow, oh, px, py, tx, ty, tw, th, cw = 0, ch = 0;
239    Evas_Coord eminw, eminh, ominw, ominh;
240    double rel_x, rel_y;
241    Eina_Bool inside_eventarea;
242 #ifdef HAVE_ELEMENTARY_X
243    Ecore_X_Window xwin = 0;
244 #endif
245
246    _elm_tooltip_reconfigure_job_stop(tt);
247
248    if (tt->hide_timer) return;
249    if (!tt->tooltip) return;
250    if (tt->changed_style)
251      {
252         const char *style = tt->style ? tt->style : "default";
253         const char *str;
254         if (!_elm_theme_object_set(tt->tt_win ? NULL : tt->owner, tt->tooltip, "tooltip", "base", style))
255           {
256              ERR("Could not apply the theme to the tooltip! style=%s", style);
257              if (tt->tt_win) evas_object_del(tt->tt_win);
258              else evas_object_del(tt->tooltip);
259              tt->tt_win = NULL;
260              tt->tt_evas = NULL;
261              tt->tooltip = NULL;
262              return;
263           }
264
265         tt->rel_pos.x = 0;
266         tt->rel_pos.y = 0;
267
268         tt->pad.x = 0;
269         tt->pad.y = 0;
270         tt->pad.bx = 0;
271         tt->pad.by = 0;
272         tt->hide_timeout = 0.0;
273
274         str = edje_object_data_get(tt->tooltip, "transparent");
275         if (tt->tt_win)
276           {  /* FIXME: hardcoded here is bad */
277              if (str && (!strcmp(str, "enabled")))
278                {
279                   elm_win_alpha_set(tt->tt_win, EINA_TRUE);
280                   elm_win_transparent_set(tt->tt_win, EINA_TRUE);
281                }
282              else
283                {
284                   elm_win_alpha_set(tt->tt_win, EINA_FALSE);
285                   elm_win_transparent_set(tt->tt_win, EINA_FALSE);
286                }
287           }
288
289         str = edje_object_data_get(tt->tooltip, "pad_x");
290         if (str) tt->pad.x = atoi(str);
291         str = edje_object_data_get(tt->tooltip, "pad_y");
292         if (str) tt->pad.y = atoi(str);
293
294         str = edje_object_data_get(tt->tooltip, "pad_border_x");
295         if (str) tt->pad.bx = atoi(str);
296         str = edje_object_data_get(tt->tooltip, "pad_border_y");
297         if (str) tt->pad.by = atoi(str);
298
299         str = edje_object_data_get(tt->tooltip, "hide_timeout");
300         if (str)
301           {
302              tt->hide_timeout = atof(str);
303              if (tt->hide_timeout < 0.0) tt->hide_timeout = 0.0;
304           }
305
306         evas_object_pass_events_set(tt->tooltip, EINA_TRUE);
307         tt->changed_style = EINA_FALSE;
308         if (tt->tooltip)
309           edje_object_part_swallow(tt->tooltip, "elm.swallow.content",
310                                    tt->content);
311
312         edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
313      }
314
315    if (!tt->content)
316      {
317         tt->content = tt->func((void *)tt->data, tt->owner, tt->tt_win ? : tt->owner);
318         if (!tt->content)
319           {
320              WRN("could not create tooltip content!");
321              if (tt->tt_win) evas_object_del(tt->tt_win);
322              else evas_object_del(tt->tooltip);
323
324              tt->tt_win = NULL;
325              tt->tt_evas = NULL;
326              tt->tooltip = NULL;
327              return;
328           }
329         evas_object_show(tt->content);
330         evas_object_layer_set(tt->content, ELM_OBJECT_LAYER_TOOLTIP);
331         evas_object_pass_events_set(tt->content, EINA_TRUE);
332         edje_object_part_swallow
333           (tt->tooltip, "elm.swallow.content", tt->content);
334         evas_object_event_callback_add(tt->content, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
335            _elm_tooltip_content_changed_hints_cb, tt);
336         evas_object_event_callback_add(tt->content, EVAS_CALLBACK_DEL,
337            _elm_tooltip_content_del_cb, tt);
338
339      }
340
341    evas_object_size_hint_min_get(tt->content, &ominw, &ominh);
342    edje_object_size_min_get(tt->tooltip, &eminw, &eminh);
343
344    if (eminw && (ominw < eminw)) ominw = eminw;
345    if (eminw && (ominh < eminh)) ominh = eminh;
346
347    if (ominw < 1) ominw = 10; /* at least it is noticeable */
348    if (ominh < 1) ominh = 10; /* at least it is noticeable */
349
350    edje_object_size_min_restricted_calc(tt->tooltip, &tw, &th, ominw, ominh);
351
352    if (tt->tt_win)
353      elm_win_screen_size_get(elm_object_top_widget_get(tt->owner), &cw, &ch, NULL, NULL);
354    if (!cw)
355      evas_output_size_get(tt->tt_evas ?: tt->evas, &cw, &ch);
356
357    evas_object_geometry_get(tt->eventarea, &ox, &oy, &ow, &oh);
358
359    if (tt->tt_win)
360      {
361         int x, y;
362 #ifdef HAVE_ELEMENTARY_X
363         ecore_x_pointer_xy_get(xwin, &px, &py);
364 #endif
365         elm_win_screen_position_get(elm_object_top_widget_get(tt->owner), &x, &y);
366         ox += x;
367         oy += y;
368      }
369    else
370      evas_pointer_canvas_xy_get(tt->evas, &px, &py);
371
372    inside_eventarea = ((px >= ox) && (py >= oy) &&
373                        (px <= ox + ow) && (py <= oy + oh));
374    if (inside_eventarea)
375      {
376         tx = px - tw;
377         ty = py - th;
378      }
379    else
380      {
381         tx = ox + (ow / 2) - (tw / 2);
382         if (0 > (th - oy - oh)) ty = oy + th;
383         else ty = oy - oh;
384      }
385
386    if (tx < 0)
387      {
388         if (abs((tx + 2 * tw) - cw) < abs(tx))
389           tx += tw;
390      }
391    else if ((tx > px) && (px > tx))
392      {
393         if (tx + tw < cw)
394           tx += tw;
395      }
396    if (ty < 0)
397      {
398         if (abs((ty + 2 * th) - ch) < abs(ty))
399           ty += th;
400      }
401    else if ((ty > py) && (py > ty))
402      {
403         if (ty + th < ch)
404           ty += th;
405      }
406    if (inside_eventarea)
407      {
408         if ((tx == px) && ((tx + tw + tt->pad.x < cw) || (tx + tw > cw))) tx += tt->pad.x;
409         else if ((tx - tt->pad.x > 0) || (tx < 0)) tx -= tt->pad.x;
410         if ((ty == py) && ((ty + th + tt->pad.y < ch) || (ty + th > ch))) ty += tt->pad.y;
411         else if ((ty - tt->pad.y > 0) || (ty < 0)) ty -= tt->pad.y;
412      }
413    if (tt->pad.bx * 2 + tw < cw)
414      {
415         if (tx < tt->pad.bx) tx = tt->pad.bx;
416         else if ((tx >= tw) && (tx + tt->pad.bx <= cw)) tx += tt->pad.bx;
417         else if (tx - tt->pad.bx >= 0) tx -= tt->pad.bx;
418      }
419    else if (tx < 0) tx -= tt->pad.bx;
420    else if (tx > cw) tx += tt->pad.bx;
421
422    if (tt->pad.by * 2 + th < ch)
423      {
424         if (ty < tt->pad.by) ty = tt->pad.by;
425         else if ((ty >= th) && (ty + tt->pad.by <= ch)) ty += tt->pad.by;
426         else if (ty - tt->pad.by >= 0) ty -= tt->pad.by;
427      }
428    else if (ty < 0) ty -= tt->pad.by;
429    else if (ty > ch) ty += tt->pad.by;
430
431    evas_object_move(tt->tt_win ? : tt->tooltip, tx, ty);
432    evas_object_resize(tt->tt_win ? : tt->tooltip, tw, th);
433    evas_object_show(tt->tooltip);
434
435    if (inside_eventarea)
436      {
437         rel_x = (px - tx) / (double)tw;
438         rel_y = (py - ty) / (double)th;
439      }
440    else
441      {
442         rel_x = (ox + (ow / 2) - tx) / (double)tw;
443         rel_y = (oy + (oh / 2) - ty) / (double)th;
444      }
445
446 #define FDIF(a, b) (fabs((a) - (b)) > 0.0001)
447    if ((FDIF(rel_x, tt->rel_pos.x)) || (FDIF(rel_y, tt->rel_pos.y)))
448      {
449         Edje_Message_Float_Set *msg;
450
451         msg = alloca(sizeof(Edje_Message_Float_Set) + sizeof(double));
452         msg->count = 2;
453         msg->val[0] = rel_x;
454         msg->val[1] = rel_y;
455         tt->rel_pos.x = rel_x;
456         tt->rel_pos.y = rel_y;
457
458         edje_object_message_send(tt->tooltip, EDJE_MESSAGE_FLOAT_SET, 1, msg);
459      }
460 #undef FDIF
461 }
462
463 static void
464 _elm_tooltip_show_timer_stop(Elm_Tooltip *tt)
465 {
466    if (!tt->show_timer) return;
467    ecore_timer_del(tt->show_timer);
468    tt->show_timer = NULL;
469 }
470
471 static Eina_Bool
472 _elm_tooltip_timer_show_cb(void *data)
473 {
474    Elm_Tooltip *tt = data;
475    tt->show_timer = NULL;
476    _elm_tooltip_show(tt);
477    return ECORE_CALLBACK_CANCEL;
478 }
479
480 static void
481 _elm_tooltip_obj_mouse_in_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
482 {
483    Elm_Tooltip *tt = data;
484
485    _elm_tooltip_hide_anim_stop(tt);
486
487    if ((tt->show_timer) || (tt->tooltip)) return;
488
489    tt->show_timer = ecore_timer_add
490      (_elm_config->tooltip_delay, _elm_tooltip_timer_show_cb, tt);
491 }
492
493 static void
494 _elm_tooltip_obj_mouse_out_cb(Elm_Tooltip *tt, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, Evas_Event_Mouse_Out *event __UNUSED__)
495 {
496    if (tt->visible_lock) return;
497
498    if (!tt->tooltip)
499      {
500         _elm_tooltip_show_timer_stop(tt);
501         return;
502      }
503    _elm_tooltip_hide_anim_start(tt);
504 }
505
506 static void _elm_tooltip_obj_free_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj, void *event_info  __UNUSED__);
507
508 static void
509 _elm_tooltip_unset(Elm_Tooltip *tt)
510 {
511    tt->visible_lock = EINA_FALSE;
512    _elm_tooltip_hide(tt);
513    _elm_tooltip_data_clean(tt);
514
515    if (tt->eventarea)
516      {
517         evas_object_event_callback_del_full
518           (tt->eventarea, EVAS_CALLBACK_MOUSE_IN,
519            _elm_tooltip_obj_mouse_in_cb, tt);
520         evas_object_event_callback_del_full
521           (tt->eventarea, EVAS_CALLBACK_MOUSE_OUT,
522            (Evas_Object_Event_Cb)_elm_tooltip_obj_mouse_out_cb, tt);
523         evas_object_event_callback_del_full
524           (tt->eventarea, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
525
526         evas_object_data_del(tt->eventarea, _tooltip_key);
527      }
528    if (tt->owner)
529      {
530         evas_object_event_callback_del_full
531           (tt->owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
532         elm_widget_tooltip_del(tt->owner, tt);
533      }
534
535    eina_stringshare_del(tt->style);
536    free(tt);
537 }
538
539 static void
540 _elm_tooltip_obj_free_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj, void *event_info  __UNUSED__)
541 {
542    Elm_Tooltip *tt = data;
543    if (tt->eventarea == obj) tt->eventarea = NULL;
544    if (tt->owner == obj) tt->owner = NULL;
545    _elm_tooltip_unset(tt);
546 }
547
548 static Evas_Object *
549 _elm_tooltip_label_create(void *data, Evas_Object *obj __UNUSED__, Evas_Object *tooltip)
550 {
551    Evas_Object *label = elm_label_add(tooltip);
552    if (!label)
553      return NULL;
554    elm_object_style_set(label, "tooltip");
555    elm_object_text_set(label, data);
556    return label;
557 }
558
559 static Evas_Object *
560 _elm_tooltip_trans_label_create(void *data, Evas_Object *obj __UNUSED__, Evas_Object *tooltip)
561 {
562    Evas_Object *label = elm_label_add(tooltip);
563    const char **text = data;
564    if (!label)
565      return NULL;
566    elm_object_style_set(label, "tooltip");
567    elm_object_domain_translatable_text_set(label, text[0], text[1]);
568    return label;
569 }
570
571 static void
572 _elm_tooltip_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
573 {
574    eina_stringshare_del(data);
575 }
576
577 static void
578 _elm_tooltip_trans_label_del_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
579 {
580    const char **text = data;
581    eina_stringshare_del(text[0]);
582    eina_stringshare_del(text[1]);
583    free(text);
584 }
585
586 static void
587 _elm_tooltip_data_clean(Elm_Tooltip *tt)
588 {
589    if (tt->del_cb) tt->del_cb((void *)tt->data, tt->owner, NULL);
590
591    _elm_tooltip_content_del(tt);
592
593    tt->data = NULL;
594    tt->del_cb = NULL;
595 }
596
597 /**
598  * Notify tooltip should recalculate its theme.
599  * @internal
600  */
601 void
602 elm_tooltip_theme(Elm_Tooltip *tt)
603 {
604    if (!tt->tooltip) return;
605    tt->changed_style = EINA_TRUE;
606    _elm_tooltip_reconfigure_job_start(tt);
607 }
608
609
610 /**
611  * Set the content to be shown in the tooltip object for specific event area.
612  *
613  * Setup the tooltip to object. The object @a eventarea can have only
614  * one tooltip, so any previous tooltip data is removed. @p func(with
615  * @p data) will be called every time that need show the tooltip and
616  * it should return a valid Evas_Object. This object is then managed
617  * fully by tooltip system and is deleted when the tooltip is gone.
618  *
619  * This is an internal function that is used by objects with sub-items
620  * that want to provide different tooltips for each of them. The @a
621  * owner object should be an elm_widget and will be used to track
622  * theme changes and to feed @a func and @a del_cb. The @a eventarea
623  * may be any object and is the one that should be used later on with
624  * elm_object_tooltip apis, such as elm_object_tooltip_hide(),
625  * elm_object_tooltip_show() or elm_object_tooltip_unset().
626  *
627  * @param eventarea the object being attached a tooltip.
628  * @param owner the elm_widget that owns this object, will be used to
629  *        track theme changes and to be used in @a func or @a del_cb.
630  * @param func the function used to create the tooltip contents. The
631  *        @a Evas_Object parameters will receive @a owner as value.
632  * @param data what to provide to @a func as callback data/context.
633  * @param del_cb called when data is not needed anymore, either when
634  *        another callback replaces @p func, the tooltip is unset with
635  *        elm_object_tooltip_unset() or the owner object @a obj
636  *        dies. This callback receives as the first parameter the
637  *        given @a data, and @c event_info is NULL.
638  *
639  * @internal
640  * @ingroup Tooltips
641  */
642 void
643 elm_object_sub_tooltip_content_cb_set(Evas_Object *eventarea, Evas_Object *owner, Elm_Tooltip_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
644 {
645    Elm_Tooltip *tt = NULL;
646    Eina_Bool just_created;
647
648    EINA_SAFETY_ON_NULL_GOTO(owner, error);
649    EINA_SAFETY_ON_NULL_GOTO(eventarea, error);
650
651    if (!func)
652      {
653         elm_object_tooltip_unset(eventarea);
654         return;
655      }
656
657    tt = evas_object_data_get(eventarea, _tooltip_key);
658    if (tt)
659      {
660         if (tt->owner != owner)
661           {
662              if (tt->owner != eventarea)
663                evas_object_event_callback_del_full
664                  (tt->owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
665
666              elm_widget_tooltip_del(tt->owner, tt);
667
668              if (owner != eventarea)
669                evas_object_event_callback_add
670                  (owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
671
672              elm_widget_tooltip_add(tt->owner, tt);
673           }
674
675         if ((tt->func == func) && (tt->data == data) &&
676             (tt->del_cb == del_cb))
677           return;
678         _elm_tooltip_data_clean(tt);
679         just_created = EINA_FALSE;
680      }
681    else
682      {
683         tt = ELM_NEW(Elm_Tooltip);
684         if (!tt) goto error;
685
686         tt->owner = owner;
687         tt->eventarea = eventarea;
688         tt->evas = evas_object_evas_get(eventarea);
689         evas_object_data_set(eventarea, _tooltip_key, tt);
690
691         just_created = EINA_TRUE;
692
693         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_IN,
694            _elm_tooltip_obj_mouse_in_cb, tt);
695         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_MOUSE_OUT,
696            (Evas_Object_Event_Cb)_elm_tooltip_obj_mouse_out_cb, tt);
697         evas_object_event_callback_add(eventarea, EVAS_CALLBACK_FREE,
698            _elm_tooltip_obj_free_cb, tt);
699
700         if (owner != eventarea)
701           evas_object_event_callback_add
702             (owner, EVAS_CALLBACK_FREE, _elm_tooltip_obj_free_cb, tt);
703
704         elm_widget_tooltip_add(tt->owner, tt);
705      }
706
707    tt->func = func;
708    tt->data = data;
709    tt->del_cb = del_cb;
710
711    if (!just_created) _elm_tooltip_reconfigure_job_start(tt);
712    return;
713
714  error:
715    if (del_cb) del_cb((void *)data, owner, NULL);
716 }
717
718 /**
719  * Force show tooltip of object
720  *
721  * @param obj Target object
722  *
723  * Force show the tooltip and disable hide on mouse_out.
724  * If another content is set as tooltip, the visible tooltip will hididen and
725  * showed again with new content.
726  * This can force show more than one tooltip at a time.
727  *
728  * @ingroup Tooltips
729  */
730 EAPI void
731 elm_object_tooltip_show(Evas_Object *obj)
732 {
733    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
734    tt->visible_lock = EINA_TRUE;
735    _elm_tooltip_show(tt);
736 }
737
738 /**
739  * Force hide tooltip of object
740  *
741  * @param obj Target object
742  *
743  * Force hide the tooltip and (re)enable future mouse interations.
744  *
745  * @ingroup Tooltips
746  */
747 EAPI void
748 elm_object_tooltip_hide(Evas_Object *obj)
749 {
750    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
751    tt->visible_lock = EINA_FALSE;
752    _elm_tooltip_hide_anim_start(tt);
753 }
754
755 /**
756  * Set the text to be shown in the tooltip object
757  *
758  * @param obj Target object
759  * @param text The text to set in the content
760  *
761  * Setup the text as tooltip to object. The object can have only one tooltip,
762  * so any previous tooltip data is removed.
763  * This method call internaly the elm_tooltip_content_cb_set().
764  *
765  * @ingroup Tooltips
766  */
767 EAPI void
768 elm_object_tooltip_text_set(Evas_Object *obj, const char *text)
769 {
770    EINA_SAFETY_ON_NULL_RETURN(obj);
771    EINA_SAFETY_ON_NULL_RETURN(text);
772
773    text = eina_stringshare_add(text);
774    elm_object_tooltip_content_cb_set
775      (obj, _elm_tooltip_label_create, text, _elm_tooltip_label_del_cb);
776 }
777
778 /**
779  */
780 EAPI void
781 elm_object_tooltip_domain_translatable_text_set(Evas_Object *obj, const char *domain, const char *text)
782 {
783    const char **data;
784    EINA_SAFETY_ON_NULL_RETURN(obj);
785    EINA_SAFETY_ON_NULL_RETURN(text);
786
787    data = malloc(2 * sizeof(char *));
788    if (!data) return;
789    data[0] = eina_stringshare_add(domain);
790    data[1] = eina_stringshare_add(text);
791    elm_object_tooltip_content_cb_set
792      (obj, _elm_tooltip_trans_label_create, data,
793       _elm_tooltip_trans_label_del_cb);
794 }
795
796 /**
797  * Set the content to be shown in the tooltip object
798  *
799  * Setup the tooltip to object. The object can have only one tooltip,
800  * so any previous tooltip data is removed. @p func(with @p data) will
801  * be called every time that need show the tooltip and it should
802  * return a valid Evas_Object. This object is then managed fully by
803  * tooltip system and is deleted when the tooltip is gone.
804  *
805  * @param obj the object being attached a tooltip.
806  * @param func the function used to create the tooltip contents.
807  * @param data what to provide to @a func as callback data/context.
808  * @param del_cb called when data is not needed anymore, either when
809  *        another callback replaces @p func, the tooltip is unset with
810  *        elm_object_tooltip_unset() or the owner object @a obj
811  *        dies. This callback receives as the first parameter the
812  *        given @a data, and @c event_info is NULL.
813  *
814  * @ingroup Tooltips
815  */
816 EAPI void
817 elm_object_tooltip_content_cb_set(Evas_Object *obj, Elm_Tooltip_Content_Cb func, const void *data, Evas_Smart_Cb del_cb)
818 {
819    elm_object_sub_tooltip_content_cb_set(obj, obj, func, data, del_cb);
820 }
821
822 /**
823  * Unset tooltip from object
824  *
825  * @param obj Target object
826  *
827  * Remove tooltip from object. The callback provided as del_cb to
828  * elm_object_tooltip_content_cb_set() will be called to notify it is
829  * not used anymore.
830  *
831  * @see elm_object_tooltip_content_cb_set()
832  *
833  * @ingroup Tooltips
834  */
835 EAPI void
836 elm_object_tooltip_unset(Evas_Object *obj)
837 {
838    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
839    _elm_tooltip_unset(tt);
840 }
841
842 /**
843  * Sets a different style for this object tooltip.
844  *
845  * @note before you set a style you should define a tooltip with
846  *       elm_object_tooltip_content_cb_set() or
847  *       elm_object_tooltip_text_set().
848  *
849  * @param obj an object with tooltip already set.
850  * @param style the theme style to use (default, transparent, ...)
851  */
852 EAPI void
853 elm_object_tooltip_style_set(Evas_Object *obj, const char *style)
854 {
855    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
856    if (!eina_stringshare_replace(&tt->style, style)) return;
857    elm_tooltip_theme(tt);
858 }
859
860 /**
861  * Get the style for this object tooltip.
862  *
863  * @param obj an object with tooltip already set.
864  * @return style the theme style in use, defaults to "default". If the
865  *         object does not have a tooltip set, then NULL is returned.
866  */
867 EAPI const char *
868 elm_object_tooltip_style_get(const Evas_Object *obj)
869 {
870    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, NULL);
871    return tt->style ? tt->style : "default";
872 }
873
874 /**
875  * Get the configured tooltip delay
876  *
877  * This gets the globally configured tooltip delay in seconds
878  *
879  * @return The tooltip delay
880  * @ingroup Tooltips
881  */
882 EAPI double
883 elm_tooltip_delay_get(void)
884 {
885    return _elm_config->tooltip_delay;
886 }
887
888 /**
889  * Set the configured tooltip delay
890  *
891  * This sets the globally configured delay to tooltip
892  *
893  * @param delay The delay to show the tooltip
894  * @return EINA_TRUE if value is valid and setted
895  * @ingroup Tooltips
896  */
897 EAPI Eina_Bool
898 elm_tooltip_delay_set(double delay)
899 {
900    if (delay < 0.0) return EINA_FALSE;
901    _elm_config->tooltip_delay = delay;
902    return EINA_TRUE;
903 }
904
905 /**
906  * @brief Disable size restrictions on an object's tooltip
907  * @param obj The tooltip's anchor object
908  * @param disable If EINA_TRUE, size restrictions are disabled
909  * @return EINA_FALSE on failure, EINA_TRUE on success
910  *
911  * This function allows a tooltip to expand beyond its parant window's canvas.
912  * It will instead be limited only by the size of the display.
913  */
914 EAPI Eina_Bool
915 elm_tooltip_size_restrict_disable(Evas_Object *obj, Eina_Bool disable)
916 {
917    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, EINA_FALSE);
918    return tt->free_size = disable;
919 }
920
921 /**
922  * @brief Retrieve size restriction state of an object's tooltip
923  * @param obj The tooltip's anchor object
924  * @return If EINA_TRUE, size restrictions are disabled
925  *
926  * This function returns whether a tooltip is allowed to expand beyond
927  * its parant window's canvas.
928  * It will instead be limited only by the size of the display.
929  */
930 EAPI Eina_Bool
931 elm_tooltip_size_restrict_disabled_get(const Evas_Object *obj)
932 {
933    ELM_TOOLTIP_GET_OR_RETURN(tt, obj, EINA_FALSE);
934    return tt->free_size;
935 }