From bf75608df0025d49ea0f52326a402825fcc55d06 Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Fri, 12 Dec 2003 18:18:49 +0000
Subject: menu delay and mode

---
 src/FbTk/Menu.cc      | 125 +++++++++++++++++++++++++++++++++++++++-----------
 src/FbTk/Menu.hh      |  10 +++-
 src/FbTk/MenuTheme.cc |   5 +-
 src/FbTk/MenuTheme.hh |  22 ++++++++-
 src/Screen.cc         |  38 ++++++++++++++-
 src/Screen.hh         |   5 +-
 6 files changed, 170 insertions(+), 35 deletions(-)

diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index cb0d7bb..77ddd5d 100644
--- a/src/FbTk/Menu.cc
+++ b/src/FbTk/Menu.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Menu.cc,v 1.45 2003/12/10 23:33:15 fluxgen Exp $
+// $Id: Menu.cc,v 1.46 2003/12/12 18:18:49 fluxgen Exp $
 
 //use GNU extensions
 #ifndef	 _GNU_SOURCE
@@ -37,6 +37,7 @@
 #include "App.hh"
 #include "EventManager.hh"
 #include "Transparent.hh"
+#include "SimpleCommand.hh"
 
 #include <X11/Xatom.h>
 #include <X11/keysym.h>
@@ -65,6 +66,17 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl):
     m_themeobserver(*this), 
     m_need_update(true) {
 
+    // setup timers
+
+    RefCount<Command> show_cmd(new SimpleCommand<Menu>(*this, &Menu::openSubmenu));
+    m_submenu_timer.setCommand(show_cmd);
+    m_submenu_timer.fireOnce(true);
+
+
+    RefCount<Command> hide_cmd(new SimpleCommand<Menu>(*this, &Menu::closeMenu));
+    m_hide_timer.setCommand(hide_cmd);
+    m_hide_timer.fireOnce(true);
+
     // make sure we get updated when the theme is reloaded
     tm.addListener(m_themeobserver);
 
@@ -673,7 +685,7 @@ void Menu::drawSubmenu(unsigned int index) {
 			
         if (m_alignment == ALIGNBOTTOM &&
             (y + item->submenu()->height()) > ((shifted) ? menu.y_shift :
-                                                  menu.y) + height()) {
+                                               menu.y) + height()) {
             y = (((shifted) ? menu.y_shift : menu.y) +
                  height() - item->submenu()->height());
         }
@@ -864,23 +876,23 @@ void Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_
         }
         
     } else if (item->isToggleItem() && m_theme.unselectedPixmap().pixmap().drawable() != 0) {
-         // enable clip mask
-            XSetClipMask(FbTk::App::instance()->display(),
-                         gc,
-                         m_theme.unselectedPixmap().mask().drawable());
-            XSetClipOrigin(FbTk::App::instance()->display(),
-                           gc, sel_x, item_y);
-            // copy bullet pixmap to frame
-            m_frame_pm.copyArea(m_theme.unselectedPixmap().pixmap().drawable(),
-                                gc,
-                                0, 0,
-                                sel_x, item_y,
-                                m_theme.unselectedPixmap().width(),
-                                m_theme.unselectedPixmap().height());
-            // disable clip mask
-            XSetClipMask(FbTk::App::instance()->display(),
-                         gc,
-                         None);
+        // enable clip mask
+        XSetClipMask(FbTk::App::instance()->display(),
+                     gc,
+                     m_theme.unselectedPixmap().mask().drawable());
+        XSetClipOrigin(FbTk::App::instance()->display(),
+                       gc, sel_x, item_y);
+        // copy bullet pixmap to frame
+        m_frame_pm.copyArea(m_theme.unselectedPixmap().pixmap().drawable(),
+                            gc,
+                            0, 0,
+                            sel_x, item_y,
+                            m_theme.unselectedPixmap().width(),
+                            m_theme.unselectedPixmap().height());
+        // disable clip mask
+        XSetClipMask(FbTk::App::instance()->display(),
+                     gc,
+                     None);
     }
     
     if (dotext && text) {
@@ -1109,6 +1121,7 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) {
 
 
 void Menu::motionNotifyEvent(XMotionEvent &me) {
+    m_hide_timer.stop();
     if (me.window == menu.title && (me.state & Button1Mask)) {
         if (movable) {
             if (! moving) {
@@ -1128,7 +1141,7 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
                 menu.window.move(menu.x, menu.y);
 
                 // if (which_sub >= 0)
-                 //     drawSubmenu(which_sub);
+                //     drawSubmenu(which_sub);
             }
         }
     } else if ((! (me.state & Button1Mask)) && me.window == menu.frame &&
@@ -1139,21 +1152,28 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
 
         if ((i != which_press || sbl != which_sbl) &&
             (w < static_cast<int>(menuitems.size()) && w >= 0)) {
+
             if (which_press != -1 && which_sbl != -1) {
+
                 int p = which_sbl * menu.persub + which_press;
                 MenuItem *item = menuitems[p];
-
                 // don't redraw disabled items on enter/leave
-                if (item->isEnabled()) {
+                if (item != 0 && item->isEnabled()) {
+
                     drawItem(p, false, true, true);
+
                     if (item->submenu()) {
+
                         if (item->submenu()->isVisible() &&
-                            (! item->submenu()->isTorn())) {
-                            item->submenu()->internal_hide();
+                            !item->submenu()->isTorn()) {
                             which_sub = -1;
+                            // setup hide timer for submenu
+                            item->submenu()->startHide();
                         }
                     }
+
                 }
+
             }
 
             which_press = i;
@@ -1162,11 +1182,27 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
             MenuItem *itmp = menuitems[w];
 
             if (itmp->submenu()) {
-                if (!itmp->submenu()->isVisible())
-                    drawSubmenu(w);
-            } else
+
+                drawItem(w, true);
+
+                if (theme().menuMode() == MenuTheme::DELAY_OPEN) {
+                    cerr<<"menuMode DELAY_OPEN"<<endl;
+                    // setup show menu timer
+                    stopHide();
+
+                    timeval timeout;
+                    timeout.tv_sec = 0;
+                    timeout.tv_usec = theme().delayOpen();
+                    m_submenu_timer.setTimeout(timeout);
+                    m_submenu_timer.start();
+
+                }
+
+            } else {
+                m_submenu_timer.stop();
                 if (itmp->isEnabled())
                     drawItem(w, true, true, true);
+            }
         }
     }
 }
@@ -1347,4 +1383,39 @@ void Menu::renderTransFrame() {
     menu.frame.updateTransparent();
 }
 
+void Menu::openSubmenu() {
+    if (!isVisible() || which_press < 0 || which_press >= menuitems.size() ||
+        which_sbl < 0 || which_sbl >= menuitems.size())
+        return;
+
+    int item = which_sbl * menu.persub + which_press;
+    if (item < 0 || item >= menuitems.size())
+        return;
+
+    stopHide(); 
+
+    if (menuitems[item]->submenu() != 0 && !menuitems[item]->submenu()->isVisible())
+        drawSubmenu(item);
+
+}
+
+void Menu::closeMenu() {
+    if (isVisible() &&
+        !isTorn()) {
+        internal_hide();
+    }    
+}
+
+void Menu::startHide() {
+    timeval timeout;
+    timeout.tv_sec = 0;
+    timeout.tv_usec = theme().delayClose();
+    m_hide_timer.setTimeout(timeout);
+    m_hide_timer.start(); 
+}
+
+void Menu::stopHide() {
+    m_hide_timer.stop();
+}
+
 }; // end namespace FbTk
diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh
index 9a3f425..ec75477 100644
--- a/src/FbTk/Menu.hh
+++ b/src/FbTk/Menu.hh
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Menu.hh,v 1.25 2003/12/10 23:08:06 fluxgen Exp $
+// $Id: Menu.hh,v 1.26 2003/12/12 18:18:49 fluxgen Exp $
 
 #ifndef	 FBTK_MENU_HH
 #define	 FBTK_MENU_HH
@@ -39,6 +39,7 @@
 #include "Observer.hh"
 #include "FbPixmap.hh"
 #include "MenuTheme.hh"
+#include "Timer.hh"
 
 namespace FbTk {
 
@@ -174,6 +175,11 @@ protected:
     inline const Menu *parent() const { return m_parent; }
 
 private: 
+    void openSubmenu();
+    void closeMenu();
+    void startHide();
+    void stopHide();
+
     void renderTransFrame();
 
     typedef std::vector<MenuItem *> Menuitems;
@@ -215,6 +221,8 @@ private:
     static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused
     FbPixmap m_frame_pm;
     bool m_need_update;
+    Timer m_submenu_timer;
+    Timer m_hide_timer;
 };
 
 }; // end namespace FbTk
diff --git a/src/FbTk/MenuTheme.cc b/src/FbTk/MenuTheme.cc
index 6159138..aea922f 100644
--- a/src/FbTk/MenuTheme.cc
+++ b/src/FbTk/MenuTheme.cc
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: MenuTheme.cc,v 1.11 2003/09/12 23:32:02 fluxgen Exp $
+// $Id: MenuTheme.cc,v 1.12 2003/12/12 18:18:49 fluxgen Exp $
 
 #include "MenuTheme.hh"
 
@@ -60,6 +60,9 @@ MenuTheme::MenuTheme(int screen_num):
     h_text_gc(RootWindow(m_display, screen_num)),
     d_text_gc(RootWindow(m_display, screen_num)),
     hilite_gc(RootWindow(m_display, screen_num)),
+    m_menumode(DELAY_OPEN),
+    m_delayopen(0), // no delay as default
+    m_delayclose(0), // no delay as default
     m_alpha(255) { 
 
     // set default values
diff --git a/src/FbTk/MenuTheme.hh b/src/FbTk/MenuTheme.hh
index 4e9deb3..07c29ad 100644
--- a/src/FbTk/MenuTheme.hh
+++ b/src/FbTk/MenuTheme.hh
@@ -19,7 +19,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: MenuTheme.hh,v 1.10 2003/11/28 22:53:10 fluxgen Exp $
+// $Id: MenuTheme.hh,v 1.11 2003/12/12 18:18:49 fluxgen Exp $
 
 #ifndef FBTK_MENUTHEME_HH
 #define FBTK_MENUTHEME_HH
@@ -37,6 +37,11 @@ namespace FbTk {
 
 class MenuTheme:public FbTk::Theme {
 public:
+    //!! TODO
+    // this isn't actually used with a theme item
+    // see setMenuMode() for more info
+    enum MenuMode {CLICK_OPEN, DELAY_OPEN};
+
     enum BulletType { EMPTY, SQUARE, TRIANGLE, DIAMOND};
     MenuTheme(int screen_num);
     virtual ~MenuTheme();
@@ -102,7 +107,16 @@ public:
 
     inline unsigned char alpha() const { return m_alpha; }
     void setAlpha(unsigned char alpha) { m_alpha = alpha; }
-
+    // this isn't actually a theme item
+    // but we'll let it be here for now, until there's a better way to
+    // get resources into menu
+    void setMenuMode(MenuMode mode) { m_menumode = mode; }
+    MenuMode menuMode() const { return m_menumode; }
+    void setDelayOpen(int usec) { m_delayopen = usec; }
+    void setDelayClose(int usec) { m_delayclose = usec; }
+    int delayOpen() const { return m_delayopen; }
+    int delayClose() const { return m_delayclose; }
+    
     const FbTk::Color &borderColor() const { return *m_border_color; }
     FbTk::Subject &themeChangeSig() { return m_theme_change_sig; }
     /// attach observer
@@ -126,6 +140,10 @@ private:
     FbTk::Subject m_theme_change_sig;
 
     unsigned char m_alpha;
+    MenuMode m_menumode;
+    unsigned int m_delayopen; ///< in usec
+    unsigned int m_delayclose; ///< in usec
+    
 };
 
 }; // end namespace FbTk
diff --git a/src/Screen.cc b/src/Screen.cc
index c95b96b..ba5e0d5 100644
--- a/src/Screen.cc
+++ b/src/Screen.cc
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Screen.cc,v 1.247 2003/12/10 23:08:03 fluxgen Exp $
+// $Id: Screen.cc,v 1.248 2003/12/12 18:18:12 fluxgen Exp $
 
 
 #include "Screen.hh"
@@ -154,7 +154,31 @@ private:
 
 }; // End anonymous namespace
 
+template <>
+void FbTk::Resource<FbTk::MenuTheme::MenuMode>::setDefaultValue() {
+    *(*this) = FbTk::MenuTheme::DELAY_OPEN;
+}
+
+template <>
+string FbTk::Resource<FbTk::MenuTheme::MenuMode>::getString() {
+    switch (*(*this)) {
+    case FbTk::MenuTheme::DELAY_OPEN:
+        return string("Delay");
+    case FbTk::MenuTheme::CLICK_OPEN:
+        return string("Click");
+    }
+    return string("Delay");
+}
 
+template <>
+void FbTk::Resource<FbTk::MenuTheme::MenuMode>::setFromString(const char *str) {
+    if (strcasecmp(str, "Delay") == 0)
+        *(*this) = FbTk::MenuTheme::DELAY_OPEN;
+    else if (strcasecmp(str, "Click") == 0)
+        *(*this) = FbTk::MenuTheme::CLICK_OPEN;
+    else
+        setDefaultValue();
+}
 
 namespace {
 
@@ -222,7 +246,10 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm,
     focus_model(rm, Fluxbox::CLICKTOFOCUS, scrname+".focusModel", altscrname+".FocusModel"),
     workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"),
     edge_snap_threshold(rm, 0, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"),
-    menu_alpha(rm, 255, scrname+".menuAlpha", altscrname+".MenuAlpha") {
+    menu_alpha(rm, 255, scrname+".menuAlpha", altscrname+".MenuAlpha"),
+    menu_delay(rm, 0, scrname + ".menuDelay", altscrname+".MenuDelay"),
+    menu_delay_close(rm, 0, scrname + ".menuDelayClose", altscrname+".MenuDelayClose"),
+    menu_mode(rm, FbTk::MenuTheme::DELAY_OPEN, scrname+".menuMode", altscrname+".MenuMode") {
 
 };
 
@@ -307,6 +334,9 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
 
 
     m_menutheme->setAlpha(*resource.menu_alpha);
+    m_menutheme->setMenuMode(*resource.menu_mode);
+    m_menutheme->setDelayOpen(*resource.menu_delay);
+    m_menutheme->setDelayClose(*resource.menu_delay_close);
 
     imageControl().setDither(*resource.image_dither);
 
@@ -570,6 +600,10 @@ FbTk::Menu *BScreen::createMenu(const std::string &label) {
 
 void BScreen::reconfigure() {
     m_menutheme->setAlpha(*resource.menu_alpha);
+    m_menutheme->setMenuMode(*resource.menu_mode);
+    m_menutheme->setDelayOpen(*resource.menu_delay);
+    m_menutheme->setDelayClose(*resource.menu_delay_close);
+
     Fluxbox::instance()->loadRootCommand(*this);
 
     // setup windowtheme, toolbartheme for antialias
diff --git a/src/Screen.hh b/src/Screen.hh
index df836db..c73dead 100644
--- a/src/Screen.hh
+++ b/src/Screen.hh
@@ -22,7 +22,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
-// $Id: Screen.hh,v 1.126 2003/12/10 23:08:03 fluxgen Exp $
+// $Id: Screen.hh,v 1.127 2003/12/12 18:18:12 fluxgen Exp $
 
 #ifndef	 SCREEN_HH
 #define	 SCREEN_HH
@@ -430,7 +430,8 @@ private:
         FbTk::Resource<std::string> resizemode;
         FbTk::Resource<Fluxbox::FocusModel> focus_model;
         bool ordered_dither;
-        FbTk::Resource<int> workspaces, edge_snap_threshold, menu_alpha;
+        FbTk::Resource<int> workspaces, edge_snap_threshold, menu_alpha, menu_delay, menu_delay_close;
+        FbTk::Resource<FbTk::MenuTheme::MenuMode> menu_mode;
 
         int placement_policy, row_direction, col_direction;
 
-- 
cgit v0.11.2