Tooltips are now uber cool!
authorGustavo Sverzut Barbieri <barbieri@gmail.com>
Sun, 12 Sep 2010 17:24:45 +0000 (17:24 +0000)
committerGustavo Sverzut Barbieri <barbieri@gmail.com>
Sun, 12 Sep 2010 17:24:45 +0000 (17:24 +0000)
I always wished tooltips would be less boring, and so we have them all
fancy and nice :-)

 * tooltip theme can request a timeout before hiding. This means we
   can fade out the tooltips nicely.

 * tooltip theme get enough information to track its origin. The
   current theme will show a small tip where it was created, and
   dynamically follows it. The graphics kinda suck, but I tried to
   achieve a cartoon-like buble using Inkscape.

 * label style is set to "tooltip". I'm providing a default with
   dark-gray text and 8 as size.

SVN revision: 52166

12 files changed:
data/themes/Makefile.am
data/themes/default.edc
data/themes/tooltip-base.png [new file with mode: 0644]
data/themes/tooltip-corner-bottom-left-tip.png [new file with mode: 0644]
data/themes/tooltip-corner-bottom-right-tip.png [new file with mode: 0644]
data/themes/tooltip-corner-top-left-tip.png [new file with mode: 0644]
data/themes/tooltip-corner-top-right-tip.png [new file with mode: 0644]
data/themes/tooltip-edge-bottom-tip.png [new file with mode: 0644]
data/themes/tooltip-edge-left-tip.png [new file with mode: 0644]
data/themes/tooltip-edge-right-tip.png [new file with mode: 0644]
data/themes/tooltip-edge-top-tip.png [new file with mode: 0644]
src/lib/els_tooltip.c

index 4f8309a..1855fcd 100644 (file)
@@ -189,7 +189,17 @@ emo-wtf.png \
 map_item.png \
 map_item_2.png \
 shadow.png \
-black.png
+black.png \
+tooltip-corner-top-left-tip.png \
+tooltip-base.png \
+tooltip-corner-bottom-left-tip.png \
+tooltip-edge-top-tip.png \
+tooltip-corner-bottom-right-tip.png \
+tooltip-edge-left-tip.png \
+tooltip-edge-bottom-tip.png \
+tooltip-edge-right-tip.png \
+tooltip-corner-top-right-tip.png
+
 
 default.edj: Makefile $(EXTRA_DIST)
        $(EDJE_CC) $(EDJE_FLAGS) \
index da4e5c0..f28fe54 100644 (file)
@@ -4425,74 +4425,482 @@ collections {
    }
 
 ///////////////////////////////////////////////////////////////////////////////
+   group { name: "elm/label/base/tooltip";
+      styles {
+         style { name: "tooltip_style";
+            base: "font=Sans font_size=8 color=#666 wrap=word";
+            tag:  "br" "\n";
+            tag:  "hilight" "+ font=Sans:style=Bold";
+            tag:  "b" "+ font=Sans:style=Bold";
+            tag:  "tab" "\t";
+         }
+      }
+      parts {
+         part { name: "elm.text";
+            type: TEXTBLOCK;
+            mouse_events: 0;
+            scale: 1;
+            description { state: "default" 0.0;
+               text {
+                  style: "tooltip_style";
+                  min: 1 1;
+               }
+            }
+         }
+      }
+   }
+
    group { name: "elm/tooltip/base/default";
-       //this group is a design similar to the inwin group
+       min: 30 30;
        data {
-       item: "pad_x" "5";
-       item: "pad_y" "5";
-       item: "pad_border_x" "10";
-       item: "pad_border_y" "10";
+           item: "pad_x" "20";
+           item: "pad_y" "20";
+           item: "pad_border_x" "10";
+           item: "pad_border_y" "10";
+           item: "hide_timeout" "0.35"; /**< tooltip is hidden after this amount, keep in sync with hide animations */
        }
        images {
-           image: "shad_circ.png" COMP;
-           image: "bt_dis_base.png" COMP;
-           image: "bt_dis_hilight.png" COMP;
+           image: "tooltip-base.png" COMP;
+           image: "tooltip-corner-top-left-tip.png" COMP;
+           image: "tooltip-corner-top-right-tip.png" COMP;
+           image: "tooltip-corner-bottom-left-tip.png" COMP;
+           image: "tooltip-corner-bottom-right-tip.png" COMP;
+           image: "tooltip-edge-left-tip.png" COMP;
+           image: "tooltip-edge-right-tip.png" COMP;
+           image: "tooltip-edge-bottom-tip.png" COMP;
+           image: "tooltip-edge-top-tip.png" COMP;
+       }
+       script {
+          hide_corners() {
+             set_state(PART:"corner-top-left", "default", 0.0);
+             set_state(PART:"corner-top-right", "default", 0.0);
+             set_state(PART:"corner-bottom-left", "default", 0.0);
+             set_state(PART:"corner-bottom-right", "default", 0.0);
+          }
+          hide_edges() {
+             set_state(PART:"clipper-edge-left", "default", 0.0);
+             set_state(PART:"clipper-edge-right", "default", 0.0);
+             set_state(PART:"clipper-edge-top", "default", 0.0);
+             set_state(PART:"clipper-edge-bottom", "default", 0.0);
+          }
+
+          show_corner_top_left() {
+             set_state(PART:"corner-top-left", "visible", 0.0);
+
+             set_state(PART:"corner-top-right", "default", 0.0);
+             set_state(PART:"corner-bottom-left", "default", 0.0);
+             set_state(PART:"corner-bottom-right", "default", 0.0);
+             hide_edges();
+          }
+          show_corner_top_right() {
+             set_state(PART:"corner-top-right", "visible", 0.0);
+
+             set_state(PART:"corner-top-left", "default", 0.0);
+             set_state(PART:"corner-bottom-left", "default", 0.0);
+             set_state(PART:"corner-bottom-right", "default", 0.0);
+             hide_edges();
+          }
+
+          show_corner_bottom_left() {
+             set_state(PART:"corner-bottom-left", "visible", 0.0);
+
+             set_state(PART:"corner-bottom-right", "default", 0.0);
+             set_state(PART:"corner-top-left", "default", 0.0);
+             set_state(PART:"corner-top-right", "default", 0.0);
+             hide_edges();
+          }
+          show_corner_bottom_right() {
+             set_state(PART:"corner-bottom-right", "visible", 0.0);
+
+             set_state(PART:"corner-bottom-left", "default", 0.0);
+             set_state(PART:"corner-top-left", "default", 0.0);
+             set_state(PART:"corner-top-right", "default", 0.0);
+             hide_edges();
+          }
+
+          show_edge_left(Float:val) {
+             set_state(PART:"clipper-edge-left", "visible", 0.0);
+             set_drag(PART:"edge-drag-left", 0.0, val);
+
+             set_state(PART:"clipper-edge-right", "default", 0.0);
+             set_state(PART:"clipper-edge-top", "default", 0.0);
+             set_state(PART:"clipper-edge-bottom", "default", 0.0);
+             hide_corners();
+          }
+          show_edge_right(Float:val) {
+             set_state(PART:"clipper-edge-right", "visible", 0.0);
+             set_drag(PART:"edge-drag-right", 0.0, val);
+
+             set_state(PART:"clipper-edge-left", "default", 0.0);
+             set_state(PART:"clipper-edge-top", "default", 0.0);
+             set_state(PART:"clipper-edge-bottom", "default", 0.0);
+             hide_corners();
+          }
+
+          show_edge_top(Float:val) {
+             set_state(PART:"clipper-edge-top", "visible", 0.0);
+             set_drag(PART:"edge-drag-top", val, 0.0);
+
+             set_state(PART:"clipper-edge-bottom", "default", 0.0);
+             set_state(PART:"clipper-edge-left", "default", 0.0);
+             set_state(PART:"clipper-edge-right", "default", 0.0);
+             hide_corners();
+          }
+          show_edge_bottom(Float:val) {
+             set_state(PART:"clipper-edge-bottom", "visible", 0.0);
+             set_drag(PART:"edge-drag-bottom", val, 0.0);
+
+             set_state(PART:"clipper-edge-top", "default", 0.0);
+             set_state(PART:"clipper-edge-left", "default", 0.0);
+             set_state(PART:"clipper-edge-right", "default", 0.0);
+             hide_corners();
+          }
+
+          public message(Msg_Type:type, id, ...) {
+             if ((type == MSG_FLOAT_SET) && (id == 1)) {
+                new Float:x, Float:y;
+
+                x = getfarg(2);
+                y = getfarg(3);
+
+                if (x < 0.0)
+                  {
+                     if (y < 0.0)      show_corner_top_left();
+                     else if (y > 1.0) show_corner_bottom_left();
+                     else              show_edge_left(y);
+                  }
+                else if (x > 1.0)
+                  {
+                     if (y < 0.0)      show_corner_top_right();
+                     else if (y > 1.0) show_corner_bottom_right();
+                     else              show_edge_right(y);
+                  }
+                else
+                  {
+                     if (y < 0.0)      show_edge_top(x);
+                     else if (y > 1.0) show_edge_bottom(x);
+                     else
+                       {
+                          hide_corners();
+                          hide_edges();
+                       }
+                  }
+             }
+          }
        }
        parts {
-           part { name: "base";
+           part { name: "clipper";
                type: RECT;
-               mouse_events: 0;
-               repeat_events: 1;
                description { state: "default" 0.0;
-                   color: 0 0 0 64;
-                   rel1.offset: 10 10;
-                   rel2.offset: -10 -10;
-                   rel1.relative: 0.0 0.0;
-                   rel2.relative: 1.0 1.0;
-               }
-           }
-           part { name: "shad";
-               mouse_events:  0;
-               description { state: "default" 0.0;
-                   image.normal: "shad_circ.png";
+                   color: 255 255 255 0;
                    rel1.to: "elm.swallow.content";
                    rel1.offset: -64 -64;
                    rel2.to: "elm.swallow.content";
                    rel2.offset: 63 63;
-                   fill.smooth: 0;
+               }
+               description { state: "visible" 0.0;
+                   inherit: "default" 0.0;
+                   color: 255 255 255 255;
                }
            }
            part { name: "pop";
-               mouse_events: 1;
+               mouse_events: 0;
+               clip_to: "clipper";
                description { state: "default" 0.0;
-                   rel1.to: "elm.swallow.content";
-                   rel1.offset: -5 -5;
-                   rel2.to: "elm.swallow.content";
-                   rel2.offset: 4 4;
+                   min: 30 30;
+                   rel1 {
+                       to: "elm.swallow.content";
+                       offset: -15 -15;
+                   }
+                   rel2 {
+                       to: "elm.swallow.content";
+                       offset: 14 14;
+                   }
                    image {
-                       normal: "bt_dis_base.png";
-                       border: 4 4 4 4;
+                       normal: "tooltip-base.png";
+                       border: 14 14 14 14;
                    }
                    image.middle: SOLID;
                }
            }
-           part { name: "popover";
-               mouse_events: 0;
+
+#define TT_CORNER(name_, rx, ry, ax, ay, ox, oy)                        \
+           part { name: "corner-"name_;                                 \
+              type: IMAGE;                                              \
+              mouse_events: 0;                                          \
+              clip_to: "clipper";                                       \
+              description { state: "default" 0.0;                       \
+                 color: 255 255 255 0;                                  \
+                 visible: 0;                                            \
+                 min: 14 14;                                            \
+                 max: 14 14;                                            \
+                 align: ax ay;                                          \
+                 fixed: 1 1;                                            \
+                 rel1 {                                                 \
+                    relative: rx ry;                                    \
+                    offset: ox oy;                                      \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 rel2 {                                                 \
+                    relative: rx ry;                                    \
+                    offset: ox oy;                                      \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 image.normal: "tooltip-corner-"name_"-tip.png";        \
+              }                                                         \
+              description { state: "visible" 0.0;                       \
+                 inherit: "default" 0.0;                                \
+                 color: 255 255 255 255;                                \
+                 visible: 1;                                            \
+              }                                                         \
+           }
+           TT_CORNER("top-left", 0, 0, 1, 1, 4, 4);
+           TT_CORNER("top-right", 1, 0, 0, 1, -5, 4);
+           TT_CORNER("bottom-left", 0, 1, 1, 0, 4, -5);
+           TT_CORNER("bottom-right", 1, 1, 0, 0, -5, -5);
+#undef TT_CORNER
+
+#define TT_EDGE_VERT(name_, rx, ax, ox)                                 \
+           part { name: "clipper-edge-"name_;                           \
+              type: RECT;                                               \
+              clip_to: "clipper";                                       \
+              description { state: "default" 0.0;                       \
+                 color: 255 255 255 0;                                  \
+                 visible: 0;                                            \
+                 min: 14 14;                                            \
+                 align: ax 0.5;                                         \
+                 fixed: 1 1;                                            \
+                 rel1 {                                                 \
+                    relative: rx 0.0;                                   \
+                    offset: ox 0;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 rel2 {                                                 \
+                    relative: rx 1.0;                                   \
+                    offset: ox 0;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+              }                                                         \
+              description { state: "visible" 0.0;                       \
+                 inherit: "default" 0.0;                                \
+                 color: 255 255 255 255;                                \
+                 visible: 1;                                            \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-area-"name_;                              \
+              type: RECT;                                               \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              description { state: "default" 0.0;                       \
+                 color: 0 0 0 0;                                        \
+                 min: 14 14;                                            \
+                 align: ax 0.5;                                         \
+                 fixed: 1 1;                                            \
+                 rel1 {                                                 \
+                    relative: rx 0.0;                                   \
+                    offset: ox 0;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 rel2 {                                                 \
+                    relative: rx 1.0;                                   \
+                    offset: ox 0;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-drag-"name_;                              \
+              type: RECT;                                               \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              dragable {                                                \
+                  x: 0 0 0;                                             \
+                  y: 1 1 0;                                             \
+                  confine: "edge-area-"name_;                           \
+              }                                                         \
+              description { state: "default" 0.0;                       \
+                 color: 0 0 0 0;                                        \
+                 min: 14 14;                                            \
+                 rel1.to: "edge-area-"name_;                            \
+                 rel2.to: "edge-area-"name_;                            \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-img-"name_;                               \
+              type: IMAGE;                                              \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              description { state: "default" 0.0;                       \
+                 min: 14 14;                                            \
+                 max: 14 14;                                            \
+                 align: ax 0.5;                                         \
+                 fixed: 1 1;                                            \
+                 rel1.to: "edge-drag-"name_;                            \
+                 rel2.to: "edge-drag-"name_;                            \
+                 image.normal: "tooltip-edge-"name_"-tip.png";          \
+              }                                                         \
+           }
+           TT_EDGE_VERT("left", 0, 1, -2);
+           TT_EDGE_VERT("right", 1, 0, 1);
+#undef TT_EDGE_VERT
+
+#define TT_EDGE_HORIZ(name_, ry, ay, oy)                                \
+           part { name: "clipper-edge-"name_;                           \
+              type: RECT;                                               \
+              clip_to: "clipper";                                       \
+              description { state: "default" 0.0;                       \
+                 color: 255 255 255 0;                                  \
+                 visible: 0;                                            \
+                 min: 14 14;                                            \
+                 align: 0.5 ay;                                         \
+                 fixed: 1 1;                                            \
+                 rel1 {                                                 \
+                    relative: 0.0 ry;                                   \
+                    offset: 0 oy;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 rel2 {                                                 \
+                    relative: 1.0 ry;                                   \
+                    offset: 0 oy;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+              }                                                         \
+              description { state: "visible" 0.0;                       \
+                 inherit: "default" 0.0;                                \
+                 color: 255 255 255 255;                                \
+                 visible: 1;                                            \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-area-"name_;                              \
+              type: RECT;                                               \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              description { state: "default" 0.0;                       \
+                 color: 0 0 0 0;                                        \
+                 min: 14 14;                                            \
+                 align: 0.5 ay;                                         \
+                 fixed: 1 1;                                            \
+                 rel1 {                                                 \
+                    relative: 0.0 ry;                                   \
+                    offset: 0 oy;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+                 rel2 {                                                 \
+                    relative: 1.0 ry;                                   \
+                    offset: 0 oy;                                       \
+                    to: "elm.swallow.content";                          \
+                 }                                                      \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-drag-"name_;                              \
+              type: RECT;                                               \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              dragable {                                                \
+                  x: 1 1 0;                                             \
+                  y: 0 0 0;                                             \
+                  confine: "edge-area-"name_;                           \
+              }                                                         \
+              description { state: "default" 0.0;                       \
+                 color: 0 0 0 0;                                        \
+                 min: 14 14;                                            \
+                 rel1.to: "edge-area-"name_;                            \
+                 rel2.to: "edge-area-"name_;                            \
+              }                                                         \
+           }                                                            \
+           part { name: "edge-img-"name_;                               \
+              type: IMAGE;                                              \
+              mouse_events: 0;                                          \
+              clip_to: "clipper-edge-"name_;                            \
+              description { state: "default" 0.0;                       \
+                 min: 14 14;                                            \
+                 max: 14 14;                                            \
+                 align: 0.5 ay;                                         \
+                 fixed: 1 1;                                            \
+                 rel1.to: "edge-drag-"name_;                            \
+                 rel2.to: "edge-drag-"name_;                            \
+                 image.normal: "tooltip-edge-"name_"-tip.png";          \
+              }                                                         \
+           }
+           TT_EDGE_HORIZ("top", 0, 1, -2);
+           TT_EDGE_HORIZ("bottom", 1, 0, 1);
+#undef TT_EDGE_HORIZ
+
+           part { name: "clipper_content";
+               type: RECT;
                description { state: "default" 0.0;
-                   rel1.to: "pop";
-                   rel2.to: "pop";
-                   rel2.relative: 1.0 0.5;
-                   image {
-                       normal: "bt_dis_hilight.png";
-                       border: 4 4 4 0;
-                   }
+                   color: 255 255 255 0;
+                   rel1.to: "elm.swallow.content";
+                   rel1.offset: -64 -64;
+                   rel2.to: "elm.swallow.content";
+                   rel2.offset: 63 63;
+               }
+               description { state: "visible" 0.0;
+                   inherit: "default" 0.0;
+                   color: 255 255 255 255;
                }
            }
            part { name: "elm.swallow.content";
                type: SWALLOW;
-               description { state: "default" 0.0;
-                   rel1.to: "base";
-                   rel2.to: "base";
+               clip_to: "clipper_content";
+               description { state: "default" 0.0; }
+           }
+           programs {
+               program {
+                   name: "show0";
+                   signal: "elm,action,show";
+                   source: "elm";
+                   action: ACTION_STOP;
+                   target: "hide0";
+                   target: "hide1";
+                   target: "hide2";
+                   target: "hide3";
+                   after: "show1";
+                   after: "show2";
+               }
+               program {
+                   name: "show1";
+                   action: STATE_SET "visible" 0.0;
+                   transition: LINEAR 0.15;
+                   target: "clipper";
+               }
+               program {
+                   name: "show2";
+                   in: 0.1 0.0;
+                   action: STATE_SET "visible" 0.0;
+                   transition: LINEAR 0.15;
+                   target: "clipper_content";
+               }
+
+               program {
+                   name: "hide0";
+                   signal: "elm,action,hide";
+                   source: "elm";
+                   action: ACTION_STOP;
+                   target: "show0";
+                   target: "show1";
+                   target: "show2";
+                   after: "hide1";
+                   after: "hide2";
+                   after: "hide3";
+               }
+               program {
+                   name: "hide1";
+                   script {
+                      hide_corners();
+                      hide_edges();
+                   }
+               }
+               program {
+                   name: "hide2";
+                   action: STATE_SET "default" 0.0;
+                   transition: LINEAR 0.1;
+                   target: "clipper_content";
+               }
+               program {
+                   name: "hide3";
+                   in: 0.1 0.0;
+                   action: STATE_SET "default" 0.0;
+                   transition: LINEAR 0.1;
+                   target: "clipper";
                }
            }
        }
diff --git a/data/themes/tooltip-base.png b/data/themes/tooltip-base.png
new file mode 100644 (file)
index 0000000..3ab8e0f
Binary files /dev/null and b/data/themes/tooltip-base.png differ
diff --git a/data/themes/tooltip-corner-bottom-left-tip.png b/data/themes/tooltip-corner-bottom-left-tip.png
new file mode 100644 (file)
index 0000000..f60787b
Binary files /dev/null and b/data/themes/tooltip-corner-bottom-left-tip.png differ
diff --git a/data/themes/tooltip-corner-bottom-right-tip.png b/data/themes/tooltip-corner-bottom-right-tip.png
new file mode 100644 (file)
index 0000000..4d715f3
Binary files /dev/null and b/data/themes/tooltip-corner-bottom-right-tip.png differ
diff --git a/data/themes/tooltip-corner-top-left-tip.png b/data/themes/tooltip-corner-top-left-tip.png
new file mode 100644 (file)
index 0000000..3f74c58
Binary files /dev/null and b/data/themes/tooltip-corner-top-left-tip.png differ
diff --git a/data/themes/tooltip-corner-top-right-tip.png b/data/themes/tooltip-corner-top-right-tip.png
new file mode 100644 (file)
index 0000000..c9dbaa2
Binary files /dev/null and b/data/themes/tooltip-corner-top-right-tip.png differ
diff --git a/data/themes/tooltip-edge-bottom-tip.png b/data/themes/tooltip-edge-bottom-tip.png
new file mode 100644 (file)
index 0000000..49fd2b0
Binary files /dev/null and b/data/themes/tooltip-edge-bottom-tip.png differ
diff --git a/data/themes/tooltip-edge-left-tip.png b/data/themes/tooltip-edge-left-tip.png
new file mode 100644 (file)
index 0000000..6cf071e
Binary files /dev/null and b/data/themes/tooltip-edge-left-tip.png differ
diff --git a/data/themes/tooltip-edge-right-tip.png b/data/themes/tooltip-edge-right-tip.png
new file mode 100644 (file)
index 0000000..cd541a6
Binary files /dev/null and b/data/themes/tooltip-edge-right-tip.png differ
diff --git a/data/themes/tooltip-edge-top-tip.png b/data/themes/tooltip-edge-top-tip.png
new file mode 100644 (file)
index 0000000..a341a21
Binary files /dev/null and b/data/themes/tooltip-edge-top-tip.png differ
index bfd5807..d538d3e 100644 (file)
@@ -39,11 +39,15 @@ struct _Elm_Tooltip
    Evas_Object             *owner;
    Evas_Object             *tooltip, *content;
    Ecore_Timer             *show_timer;
+   Ecore_Timer             *hide_timer;
    Ecore_Job               *reconfigure_job;
-   Ecore_Job               *hide_job;
    struct {
       Evas_Coord            x, y, bx, by;
    } pad;
+   struct {
+      double                x, y;
+   } rel_pos;
+   double                   hide_timeout; /* from theme */
    Eina_Bool                visible_lock:1;
    Eina_Bool                changed_style:1;
 };
@@ -51,8 +55,8 @@ struct _Elm_Tooltip
 static void _elm_tooltip_reconfigure(Elm_Tooltip *tt);
 static void _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt);
 static void _elm_tooltip_reconfigure_job_stop(Elm_Tooltip *tt);
-static void _elm_tooltip_hide_job_start(Elm_Tooltip *tt);
-static void _elm_tooltip_hide_job_stop(Elm_Tooltip *tt);
+static void _elm_tooltip_hide_anim_start(Elm_Tooltip *tt);
+static void _elm_tooltip_hide_anim_stop(Elm_Tooltip *tt);
 static void _elm_tooltip_show_timer_stop(Elm_Tooltip *tt);
 static void _elm_tooltip_hide(Elm_Tooltip *tt);
 
@@ -96,8 +100,11 @@ _elm_tooltip_obj_mouse_move_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj
 static void
 _elm_tooltip_show(Elm_Tooltip *tt)
 {
+   if ((tt->hide_timer) && (tt->tooltip))
+     edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
+
    _elm_tooltip_show_timer_stop(tt);
-   _elm_tooltip_hide_job_stop(tt);
+   _elm_tooltip_hide_anim_stop(tt);
 
    if (tt->tooltip) return;
    tt->tooltip = edje_object_add(tt->evas);
@@ -137,7 +144,7 @@ static void
 _elm_tooltip_hide(Elm_Tooltip *tt)
 {
    _elm_tooltip_show_timer_stop(tt);
-   _elm_tooltip_hide_job_stop(tt);
+   _elm_tooltip_hide_anim_stop(tt);
    _elm_tooltip_reconfigure_job_stop(tt);
 
    if (!tt->tooltip) return;
@@ -180,27 +187,30 @@ _elm_tooltip_reconfigure_job_start(Elm_Tooltip *tt)
      (_elm_tooltip_reconfigure_job, tt);
 }
 
-static void
-_elm_tooltip_hide_job(void *data)
+static Eina_Bool
+_elm_tooltip_hide_anim_cb(void *data)
 {
    Elm_Tooltip *tt = data;
-   tt->hide_job = NULL;
-   _elm_tooltip_hide(data);
+   tt->hide_timer = NULL;
+   _elm_tooltip_hide(tt);
+   return EINA_FALSE;
 }
 
 static void
-_elm_tooltip_hide_job_stop(Elm_Tooltip *tt)
+_elm_tooltip_hide_anim_start(Elm_Tooltip *tt)
 {
-   if (!tt->hide_job) return;
-   ecore_job_del(tt->hide_job);
-   tt->hide_job = NULL;
+   if (tt->hide_timer) return;
+   edje_object_signal_emit(tt->tooltip, "elm,action,hide", "elm");
+   tt->hide_timer = ecore_timer_add
+     (tt->hide_timeout, _elm_tooltip_hide_anim_cb, tt);
 }
 
 static void
-_elm_tooltip_hide_job_start(Elm_Tooltip *tt)
+_elm_tooltip_hide_anim_stop(Elm_Tooltip *tt)
 {
-   if (tt->hide_job) ecore_job_del(tt->hide_job);
-   tt->hide_job = ecore_job_add(_elm_tooltip_hide_job, tt);
+   if (!tt->hide_timer) return;
+   ecore_timer_del(tt->hide_timer);
+   tt->hide_timer = NULL;
 }
 
 static void
@@ -208,9 +218,12 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
 {
    Evas_Coord ox, oy, ow, oh, px, py, tx, ty, tw, th, cw, ch;
    Evas_Coord eminw, eminh, ominw, ominh;
+   double rel_x, rel_y;
+   Eina_Bool inside_owner;
 
    _elm_tooltip_reconfigure_job_stop(tt);
 
+   if (tt->hide_timer) return;
    if (!tt->tooltip) return;
    if (tt->changed_style)
      {
@@ -225,10 +238,14 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
              return;
           }
 
+        tt->rel_pos.x = 0;
+        tt->rel_pos.y = 0;
+
         tt->pad.x = 0;
         tt->pad.y = 0;
         tt->pad.bx = 0;
         tt->pad.by = 0;
+        tt->hide_timeout = 0.0;
 
         str = edje_object_data_get(tt->tooltip, "pad_x");
         if (str) tt->pad.x = atoi(str);
@@ -240,11 +257,20 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
         str = edje_object_data_get(tt->tooltip, "pad_border_y");
         if (str) tt->pad.by = atoi(str);
 
+        str = edje_object_data_get(tt->tooltip, "hide_timeout");
+        if (str)
+          {
+             tt->hide_timeout = atof(str);
+             if (tt->hide_timeout < 0.0) tt->hide_timeout = 0.0;
+          }
+
         evas_object_pass_events_set(tt->tooltip, EINA_TRUE);
         tt->changed_style = EINA_FALSE;
         if (tt->tooltip)
           edje_object_part_swallow
             (tt->tooltip, "elm.swallow.content", tt->content);
+
+        edje_object_signal_emit(tt->tooltip, "elm,action,show", "elm");
      }
 
    if (!tt->content)
@@ -276,6 +302,9 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
    if (ominw < eminw) ominw = eminw;
    if (ominh < eminh) ominh = eminh;
 
+   if (ominw < 1) ominw = 10; /* at least it is noticeable */
+   if (ominh < 1) ominh = 10; /* at least it is noticeable */
+
    edje_object_size_min_restricted_calc
      (tt->tooltip, &tw, &th, ominw, ominh);
 
@@ -284,7 +313,9 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
 
    evas_object_geometry_get(tt->owner, &ox, &oy, &ow, &oh);
 
-   if ((px >= ox) && (py >= oy) && (px <= ox + ow) && (py <= oy + oh))
+   inside_owner = ((px >= ox) && (py >= oy) &&
+                   (px <= ox + ow) && (py <= oy + oh));
+   if (inside_owner)
      {
         tx = px;
         ty = py;
@@ -314,6 +345,33 @@ _elm_tooltip_reconfigure(Elm_Tooltip *tt)
    evas_object_move(tt->tooltip, tx, ty);
    evas_object_resize(tt->tooltip, tw, th);
    evas_object_show(tt->tooltip);
+
+   if (inside_owner)
+     {
+        rel_x = (px - tx) / (double)tw;
+        rel_y = (py - ty) / (double)th;
+     }
+   else
+     {
+        rel_x = (ox + (ow / 2) - tx) / (double)tw;
+        rel_y = (oy + (oh / 2) - ty) / (double)th;
+     }
+
+#define FDIF(a, b) (fabs((a) - (b)) > 0.0001)
+   if (FDIF(rel_x, tt->rel_pos.x) || FDIF(rel_y, tt->rel_pos.y))
+     {
+        Edje_Message_Float_Set *msg;
+
+        msg = alloca(sizeof(Edje_Message_Float_Set) + sizeof(double));
+        msg->count = 2;
+        msg->val[0] = rel_x;
+        msg->val[1] = rel_y;
+        tt->rel_pos.x = rel_x;
+        tt->rel_pos.y = rel_y;
+
+        edje_object_message_send(tt->tooltip, EDJE_MESSAGE_FLOAT_SET, 1, msg);
+     }
+#undef FDIF
 }
 
 static void
@@ -338,7 +396,8 @@ _elm_tooltip_obj_mouse_in_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj _
 {
    Elm_Tooltip *tt = data;
 
-   _elm_tooltip_hide_job_stop(tt);
+   _elm_tooltip_hide_anim_stop(tt);
+
    if ((tt->show_timer) || (tt->tooltip)) return;
 
    tt->show_timer = ecore_timer_add
@@ -348,7 +407,17 @@ _elm_tooltip_obj_mouse_in_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj _
 static void
 _elm_tooltip_obj_mouse_out_cb(void *data, Evas *e  __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info  __UNUSED__)
 {
-   _elm_tooltip_hide_job_start(data);
+   Elm_Tooltip *tt = data;
+
+   if (tt->visible_lock) return;
+
+   if (!tt->tooltip)
+     {
+        _elm_tooltip_show_timer_stop(tt);
+        return;
+     }
+
+   _elm_tooltip_hide_anim_start(tt);
 }
 
 static void
@@ -363,6 +432,7 @@ _elm_tooltip_label_create(void *data, Evas_Object *obj)
    Evas_Object *label = elm_label_add(obj);
    if (!label)
      return NULL;
+   elm_object_style_set(label, "tooltip");
    elm_label_label_set(label, data);
    return label;
 }
@@ -431,7 +501,7 @@ elm_object_tooltip_hide(Evas_Object *obj)
 {
    ELM_TOOLTIP_GET_OR_RETURN(tt, obj);
    tt->visible_lock = EINA_FALSE;
-   _elm_tooltip_hide_job_start(tt);
+   _elm_tooltip_hide_anim_start(tt);
 }
 
 /**
@@ -535,11 +605,7 @@ elm_object_tooltip_content_cb_set(Evas_Object *obj, Elm_Tooltip_Content_Cb func,
    tt->data = data;
    tt->del_cb = del_cb;
 
-   if (!just_created)
-     {
-        _elm_tooltip_hide_job_stop(tt);
-        _elm_tooltip_reconfigure_job_start(tt);
-     }
+   if (!just_created) _elm_tooltip_reconfigure_job_start(tt);
    return;
 
  error: