From 4a3be045b28edac4953be9f195640654f8b5a1a1 Mon Sep 17 00:00:00 2001
From: Matteo Galiazzo <matteo@maltesenarrazioni.it>
Date: Mon, 5 May 2008 05:05:52 -0700
Subject: add tooltips for iconbar buttons when title is too long to fit

---
 ChangeLog              |   3 ++
 src/FbTk/Button.cc     |  14 ++++++-
 src/FbTk/Button.hh     |   2 +
 src/FbTk/TextButton.cc |  23 +++++++++--
 src/FbTk/TextButton.hh |   2 +
 src/IconButton.cc      |  17 +++++++-
 src/IconButton.hh      |   2 +
 src/Makefile.am        |   1 +
 src/OSDWindow.hh       |   2 +-
 src/Screen.cc          |  14 +++++++
 src/Screen.hh          |   9 +++-
 src/TooltipWindow.cc   | 109 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/TooltipWindow.hh   |  53 ++++++++++++++++++++++++
 13 files changed, 241 insertions(+), 10 deletions(-)
 create mode 100644 src/TooltipWindow.cc
 create mode 100644 src/TooltipWindow.hh

diff --git a/ChangeLog b/ChangeLog
index 1876d6a..b243eb8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
  (Format: Year/Month/Day)
 Changes for 1.0.1:
+*08/05/05:
+   * Add tooltips for iconbar buttons (thanks Matteo Galiazzo)
+     TooltipWindow.cc/hh
 *08/05/02:
    * Minor changes for fluxbox-generate_menu (thanks skiidoo)
      util/fluxbox-generate_menu.in
diff --git a/src/FbTk/Button.cc b/src/FbTk/Button.cc
index 0284fea..9edbe5c 100644
--- a/src/FbTk/Button.cc
+++ b/src/FbTk/Button.cc
@@ -30,7 +30,8 @@ namespace FbTk {
 Button::Button(int screen_num, int x, int y,
                unsigned int width, unsigned int height):
     FbWindow(screen_num, x, y, width, height,
-             ExposureMask | ButtonPressMask | ButtonReleaseMask),
+             ExposureMask | ButtonPressMask | EnterWindowMask |
+             LeaveWindowMask | ButtonReleaseMask),
     m_background_pm(0),
     m_pressed_pm(0),
     m_pressed_color(),
@@ -45,7 +46,8 @@ Button::Button(int screen_num, int x, int y,
 Button::Button(const FbWindow &parent, int x, int y, 
                unsigned int width, unsigned int height):
     FbWindow(parent, x, y, width, height,
-             ExposureMask | ButtonPressMask | ButtonReleaseMask),
+             ExposureMask | ButtonPressMask | ButtonReleaseMask |
+             EnterWindowMask | LeaveWindowMask),
     m_background_pm(0),
     m_pressed_pm(0),
     m_pressed_color(),
@@ -90,6 +92,14 @@ void Button::setBackgroundPixmap(Pixmap pm) {
     FbTk::FbWindow::setBackgroundPixmap(pm);
 }
 
+
+void Button::enterNotifyEvent(XCrossingEvent &ce){
+		
+}
+void Button::leaveNotifyEvent(XCrossingEvent &ce){
+		
+}
+
 void Button::buttonPressEvent(XButtonEvent &event) {
     bool update = false;
     if (m_pressed_pm != 0) {
diff --git a/src/FbTk/Button.hh b/src/FbTk/Button.hh
index 99d8ee9..1f65799 100644
--- a/src/FbTk/Button.hh
+++ b/src/FbTk/Button.hh
@@ -61,6 +61,8 @@ public:
     //@{
     virtual void buttonPressEvent(XButtonEvent &event);
     virtual void buttonReleaseEvent(XButtonEvent &event);
+    virtual void enterNotifyEvent(XCrossingEvent &ce);    
+    virtual void leaveNotifyEvent(XCrossingEvent &ce);    
     virtual void exposeEvent(XExposeEvent &event);
     //@}
 
diff --git a/src/FbTk/TextButton.cc b/src/FbTk/TextButton.cc
index 561fe21..f259d89 100644
--- a/src/FbTk/TextButton.cc
+++ b/src/FbTk/TextButton.cc
@@ -158,11 +158,9 @@ void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) {
     translateSize(m_orientation, textw, texth);
 
     int align_x = FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding,
-                                    bevel(),
-                                    justify(),
-                                    font(),
+                                    bevel(), justify(), font(),
                                     text().data(), text().size(),
-                                    textlen); // return new text lne
+                                    textlen); // return new text len
 
     // center text by default
     int center_pos = texth/2 + font().ascent()/2 - 1;
@@ -183,6 +181,23 @@ void TextButton::drawText(int x_offset, int y_offset, FbDrawable *drawable) {
                     textx, texty, m_orientation); // position
 }
 
+
+bool TextButton::textExceeds(int x_offset) {
+    
+    unsigned int textlen = text().size();
+    // do text alignment
+
+    unsigned int textw = width(), texth = height();
+    translateSize(m_orientation, textw, texth);
+
+    FbTk::doAlignment(textw - x_offset - m_left_padding - m_right_padding,
+                      bevel(), justify(), font(), text().data(), text().size(),
+                      textlen); // return new text len
+
+    return text().size()>textlen;
+    
+}
+
 void TextButton::exposeEvent(XExposeEvent &event) {
     clearArea(event.x, event.y, event.width, event.height, false);
 }
diff --git a/src/FbTk/TextButton.hh b/src/FbTk/TextButton.hh
index eb48e61..22cda82 100644
--- a/src/FbTk/TextButton.hh
+++ b/src/FbTk/TextButton.hh
@@ -80,6 +80,8 @@ public:
 
 protected:
     virtual void drawText(int x_offset, int y_offset, FbDrawable *drawable_override);
+    // return true if the text will be truncated
+    bool textExceeds(int x_offset);
 
 private:
     FbTk::Font *m_font;
diff --git a/src/IconButton.cc b/src/IconButton.cc
index 09791c8..6b8118e 100644
--- a/src/IconButton.cc
+++ b/src/IconButton.cc
@@ -52,7 +52,8 @@ IconButton::IconButton(const FbTk::FbWindow &parent,
     FbTk::TextButton(parent, focused_theme->text().font(), win.title()),
     m_win(win),
     m_icon_window(*this, 1, 1, 1, 1,
-                  ExposureMask | ButtonPressMask | ButtonReleaseMask),
+                  ExposureMask |EnterWindowMask | LeaveWindowMask |
+                  ButtonPressMask | ButtonReleaseMask),
     m_use_pixmap(true),
     m_theme(win, focused_theme, unfocused_theme),
     m_pm(win.screen().imageControl()) {
@@ -79,6 +80,20 @@ void IconButton::exposeEvent(XExposeEvent &event) {
         FbTk::TextButton::exposeEvent(event);
 }
 
+void IconButton::enterNotifyEvent(XCrossingEvent &ev) {
+
+   int xoffset = 1;
+   if (m_icon_pixmap.drawable() != 0)
+       xoffset = m_icon_window.x() + m_icon_window.width() + 1;
+    
+    if (FbTk::TextButton::textExceeds(xoffset))
+        m_win.screen().showTooltip(m_win.title());
+}
+
+void IconButton::leaveNotifyEvent(XCrossingEvent &ev) {
+    m_win.screen().hideTooltip();
+}
+
 void IconButton::moveResize(int x, int y,
                             unsigned int width, unsigned int height) {
 
diff --git a/src/IconButton.hh b/src/IconButton.hh
index b80a29b..bb41b8b 100644
--- a/src/IconButton.hh
+++ b/src/IconButton.hh
@@ -45,6 +45,8 @@ public:
     virtual ~IconButton();
 
     void exposeEvent(XExposeEvent &event);
+    void enterNotifyEvent(XCrossingEvent &ce);
+    void leaveNotifyEvent(XCrossingEvent &ce);
     void clear();
     void clearArea(int x, int y,
                    unsigned int width, unsigned int height,
diff --git a/src/Makefile.am b/src/Makefile.am
index 0fc5a7a..337b99c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -106,6 +106,7 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
 	RootTheme.hh RootTheme.cc \
 	FbRootWindow.hh FbRootWindow.cc \
 	OSDWindow.hh OSDWindow.cc \
+	TooltipWindow.hh TooltipWindow.cc \
 	Screen.cc Screen.hh ScreenResources.cc \
 	Slit.cc Slit.hh SlitTheme.hh SlitTheme.cc SlitClient.hh SlitClient.cc \
 	WinButton.hh WinButton.cc \
diff --git a/src/OSDWindow.hh b/src/OSDWindow.hh
index 3fd5c42..e11a531 100644
--- a/src/OSDWindow.hh
+++ b/src/OSDWindow.hh
@@ -47,7 +47,7 @@ public:
 
     bool isVisible() const { return m_visible; }
 
-private:
+protected:
     void show();
 
     BScreen &m_screen;
diff --git a/src/Screen.cc b/src/Screen.cc
index 7950b83..f817e6b 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -290,6 +290,7 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm,
     menu_delay(rm, 0, scrname + ".menuDelay", altscrname+".MenuDelay"),
     menu_delay_close(rm, 0, scrname + ".menuDelayClose", altscrname+".MenuDelayClose"),
     tab_width(rm, 64, scrname + ".tab.width", altscrname+".Tab.Width"),
+    tooltip_delay(rm, 500, scrname + ".tooltipDelay", altscrname+".TooltipDelay"),
     menu_mode(rm, FbTk::MenuTheme::DELAY_OPEN, scrname+".menuMode", altscrname+".MenuMode"),
 
     gc_line_width(rm, 1, scrname+".overlay.lineWidth", altscrname+".Overlay.LineWidth"),
@@ -343,6 +344,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
     m_root_window(scrn),
     m_geom_window(m_root_window, *this, *m_focused_windowtheme),
     m_pos_window(m_root_window, *this, *m_focused_windowtheme),
+    m_tooltip_window(m_root_window, *this, *m_focused_windowtheme),
     m_dummy_window(scrn, -1, -1, 1, 1, 0, true, false, CopyFromParent,
                    InputOnly),
     resource(rm, screenname, altscreenname),
@@ -484,6 +486,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
 
     renderGeomWindow();
     renderPosWindow();
+    m_tooltip_window.setDelay(*resource.tooltip_delay);
 
     // setup workspaces and workspace menu
     int nr_ws = *resource.workspaces;
@@ -1849,6 +1852,17 @@ void BScreen::showGeometry(int gx, int gy) {
 }
 
 
+void BScreen::showTooltip(const std::string &text) {
+    if (*resource.tooltip_delay >= 0)
+        m_tooltip_window.showText(text);
+}
+
+void BScreen::hideTooltip() {
+    if (*resource.tooltip_delay >= 0)
+        m_tooltip_window.hide();
+}
+
+
 void BScreen::hideGeometry() {
     m_geom_window.hide();
 }
diff --git a/src/Screen.hh b/src/Screen.hh
index d42fea0..cf8bf1f 100644
--- a/src/Screen.hh
+++ b/src/Screen.hh
@@ -30,7 +30,7 @@
 #include "RootTheme.hh"
 #include "WinButtonTheme.hh"
 #include "FbWinFrameTheme.hh"
-#include "OSDWindow.hh"
+#include "TooltipWindow.hh"
 
 #include "FbTk/MenuTheme.hh"
 #include "FbTk/EventHandler.hh"
@@ -389,6 +389,9 @@ public:
     /// show geomentry with "width x height"-text, not size of window
     void showGeometry(int width, int height);
     void hideGeometry();
+    
+    void showTooltip(const std::string &text);
+    void hideTooltip();
 
     void setLayer(FbTk::XLayerItem &item, int layernum);
     // remove? no, items are never removed from their layer until they die
@@ -536,6 +539,7 @@ private:
 
     FbRootWindow m_root_window;
     OSDWindow m_geom_window, m_pos_window;
+    TooltipWindow m_tooltip_window;
     FbTk::FbWindow m_dummy_window;
 
     struct ScreenResource {
@@ -554,7 +558,8 @@ private:
         FbTk::Resource<FollowModel> follow_model, user_follow_model;
         bool ordered_dither;
         FbTk::Resource<int> workspaces, edge_snap_threshold, focused_alpha,
-            unfocused_alpha, menu_alpha, menu_delay, menu_delay_close, tab_width;
+            unfocused_alpha, menu_alpha, menu_delay, menu_delay_close,
+            tab_width, tooltip_delay;
         FbTk::Resource<FbTk::MenuTheme::MenuMode> menu_mode;
 
         FbTk::Resource<int> gc_line_width;
diff --git a/src/TooltipWindow.cc b/src/TooltipWindow.cc
new file mode 100644
index 0000000..025cc68
--- /dev/null
+++ b/src/TooltipWindow.cc
@@ -0,0 +1,109 @@
+// TooltipWindow.hh
+// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+
+#include "TooltipWindow.hh"
+#include "Screen.hh"
+#include "FbWinFrameTheme.hh"
+
+
+TooltipWindow::TooltipWindow(const FbTk::FbWindow &parent, BScreen &screen,
+                             FbTk::ThemeProxy<FbWinFrameTheme> &theme):
+    OSDWindow(parent, screen, theme),
+    delay(-1) {
+
+    FbTk::RefCount<FbTk::Command<void> > raisecmd(new FbTk::SimpleCommand<TooltipWindow>(*this, &TooltipWindow::raiseTooltip));
+    timer.setCommand(raisecmd);
+    timer.fireOnce(true);
+
+}
+
+void TooltipWindow::showText(const std::string &text) {
+
+    lastText = text.c_str();
+    if (delay == 0)
+        raiseTooltip();
+    else
+        timer.start();
+
+}
+
+void TooltipWindow::raiseTooltip() {
+
+    if (lastText.size() == 0)
+        return;
+
+    resize(lastText);
+    reconfigTheme();
+    int h = m_theme->font().height() + m_theme->bevelWidth() * 2;
+    int w = m_theme->font().textWidth(lastText, lastText.size()) + m_theme->bevelWidth() * 2;
+
+    Window root_ret; // not used
+    Window window_ret; // not used
+    int rx = 0, ry = 0;
+    int wx, wy; // not used
+    unsigned int mask; // not used
+
+    XQueryPointer(display(), m_screen.rootWindow().window(),
+                  &root_ret, &window_ret, &rx, &ry, &wx, &wy, &mask);
+
+    // mouse position
+    int mx = rx;
+    int my = ry;
+
+    // center the mouse horizontally
+    rx -= w/2;
+    int yoffset = 10;
+    if (ry >= yoffset + h)
+        ry -= yoffset + h;
+    else
+        ry += yoffset;
+
+    // check that we are not out of screen
+    int outOfBound = rx + w - m_screen.width(); 
+    if (outOfBound > 0)
+        rx -= outOfBound;
+    if (rx < 0)
+        rx = 0;
+
+    moveResize(rx,ry,w, h);
+
+    show();
+    clear();
+    m_theme->font().drawText(*this, m_screen.screenNumber(),
+                             m_theme->iconbarTheme().text().textGC(), lastText,
+                             lastText.size(), m_theme->bevelWidth(),
+                             m_theme->bevelWidth() + m_theme->font().ascent());
+}
+
+
+void TooltipWindow::show() {
+    if (m_visible)
+        return;
+    m_visible = true;
+    raise();
+    FbTk::FbWindow::show();
+}
+
+void TooltipWindow::hide() {
+    timer.stop();
+    OSDWindow::hide();
+}
diff --git a/src/TooltipWindow.hh b/src/TooltipWindow.hh
new file mode 100644
index 0000000..03abc1d
--- /dev/null
+++ b/src/TooltipWindow.hh
@@ -0,0 +1,53 @@
+// TooltipWindow.hh
+// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.#ifndef TOOLTIPWINDOW_HH_
+#ifndef TOOLTIPWINDOW_HH_
+#define TOOLTIPWINDOW_HH_
+
+#include "OSDWindow.hh"
+#include "FbTk/Command.hh"
+#include "FbTk/RefCount.hh"
+#include "FbTk/Timer.hh"
+#include "FbTk/SimpleCommand.hh"
+
+
+class TooltipWindow : public OSDWindow  {
+public:
+    TooltipWindow(const FbTk::FbWindow &parent, BScreen &screen,
+                  FbTk::ThemeProxy<FbWinFrameTheme> &theme);
+
+    void showText(const std::string &text);
+    void setDelay(int iDelay) { 
+        delay = iDelay; 
+        timer.setTimeout(delay);
+    }
+    void hide() ;    
+
+private:
+    void raiseTooltip();
+    void show();    
+    int delay;
+    std::string lastText;
+    FbTk::Timer timer;
+};
+
+
+
+#endif /*TOOLTIPWINDOW_HH_*/
-- 
cgit v0.11.2