From 46a06cdb02084f52b927cdb9b97092765f532cee Mon Sep 17 00:00:00 2001
From: fluxgen <fluxgen>
Date: Sun, 13 Jun 2004 00:31:29 +0000
Subject: transparency improvements, added buffer for title window to reduce
 flickering and removed menu.bevel_w since its already in MenuTheme

---
 src/FbTk/Menu.cc | 225 ++++++++++++++++++++++++++++++++-----------------------
 src/FbTk/Menu.hh |  10 ++-
 2 files changed, 139 insertions(+), 96 deletions(-)

diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index f0e5c59..6f1c84e 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.62 2004/06/07 20:28:50 fluxgen Exp $
+// $Id: Menu.cc,v 1.63 2004/06/13 00:31:29 fluxgen Exp $
 
 //use GNU extensions
 #ifndef	 _GNU_SOURCE
@@ -132,16 +132,15 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl):
         menu.hilite_pixmap =
         menu.sel_pixmap = None;
 
-    menu.bevel_w = 2;
 
     menu.title_h = menu.item_w = menu.frame_h =
-        m_theme.titleFont().height() + menu.bevel_w * 2;
+        theme().titleFont().height() + theme().bevelWidth() * 2;
 
     menu.sublevels =
         menu.persub =
         menu.minsub = 0;
 
-    menu.item_h = m_theme.frameFont().height() + menu.bevel_w;
+    menu.item_h = theme().frameFont().height() + theme().bevelWidth();
 
     long event_mask = ButtonPressMask | ButtonReleaseMask | 
         ButtonMotionMask | KeyPressMask | ExposureMask | FocusChangeMask;
@@ -389,27 +388,28 @@ void Menu::enableTitle() {
 
 void Menu::update(int active_index) {
 
-    if (menu.bevel_w > 10) // clamp to "normal" size
-        menu.bevel_w = 10;
+
     if (m_border_width > 20)
         m_border_width = 20;
 
     if (theme().titleHeight() != 0) 
-        menu.title_h = std::max(theme().titleHeight(), theme().titleFont().height() + menu.bevel_w*2);
+        menu.title_h = std::max(theme().titleHeight(), 
+                                theme().titleFont().height() + theme().bevelWidth());
     else
-        menu.title_h = theme().titleFont().height() + menu.bevel_w*2;
+        menu.title_h = theme().titleFont().height() + theme().bevelWidth()*2;
 
     if (theme().itemHeight() != 0)
-        menu.item_h = std::max(theme().itemHeight(), theme().frameFont().height() + menu.bevel_w);
+        menu.item_h = std::max(theme().itemHeight(), 
+                               theme().frameFont().height() + theme().bevelWidth());
     else
-        menu.item_h = theme().frameFont().height() + menu.bevel_w;
+        menu.item_h = theme().frameFont().height() +theme().bevelWidth();
 
 
     if (title_vis) {
         menu.item_w = theme().titleFont().textWidth(menu.label.c_str(),
                                                     menu.label.size());
 		
-        menu.item_w += (menu.bevel_w * 2);
+        menu.item_w += (theme().bevelWidth() * 2);
     }	else
         menu.item_w = 1;
 
@@ -463,16 +463,53 @@ void Menu::update(int active_index) {
         const FbTk::Texture &tex = theme().titleTexture();
         if (!tex.usePixmap()) {
             menu.title_pixmap = None;
-            menu.title.setBackgroundColor(tex.color());
         } else {
             menu.title_pixmap =
                 m_image_ctrl.renderImage(width(), menu.title_h, tex);
-            menu.title.setBackgroundPixmap(menu.title_pixmap);
         }
 
         if (tmp) 
             m_image_ctrl.removeImage(tmp);
 
+        // if new size of title doesn't match our
+        // buffer pixmap -> resize buffer pixmap
+        if (m_title_pm.width() != width() || 
+            m_title_pm.height() != menu.title_h) {
+            m_title_pm = FbPixmap(menu.title.window(),
+                                  width(), menu.title_h,
+                                  menu.title.depth());
+            m_real_title_pm = FbPixmap(menu.title.window(),
+                                       width(), menu.title_h,
+                                       menu.title.depth());
+            // set pixmap that we have as real face to the user
+            menu.title.setBackgroundPixmap(m_real_title_pm.drawable());
+            menu.title.setBufferPixmap(m_real_title_pm.drawable());
+            //!! TODO: error checking?
+            GContext def_gc(menu.title);
+            if (menu.title_pixmap == 0) {
+                def_gc.setForeground(theme().titleTexture().color());
+                m_title_pm.fillRectangle(def_gc.gc(),
+                                         0, 0,
+                                         m_title_pm.width(), m_title_pm.height());
+                m_real_title_pm.fillRectangle(def_gc.gc(),
+                                              0, 0,
+                                              m_title_pm.width(), m_title_pm.height());
+            } else {
+                m_title_pm.copyArea(menu.title_pixmap, 
+                                    def_gc.gc(),
+                                    0, 0,
+                                    0, 0,
+                                    m_title_pm.width(), m_title_pm.height());
+
+                m_real_title_pm.copyArea(menu.title_pixmap, 
+                                         def_gc.gc(),
+                                         0, 0,
+                                         0, 0,
+                                         m_title_pm.width(), m_title_pm.height());
+
+            }
+            
+        }
     }
 
     tmp = menu.frame_pixmap;
@@ -544,9 +581,11 @@ void Menu::update(int active_index) {
 
             // TODO: fill only that part of the menuframe with the
             // pixmap/color, that has actually NO buttons on it
+            // ??? did I made this comment ? (fluxgen)
+            // if so, what am I talking about?
             GContext def_gc(menu.frame);
             if (menu.frame_pixmap == 0) {
-                def_gc.setForeground(m_theme.frameTexture().color());
+                def_gc.setForeground(theme().frameTexture().color());
                 m_frame_pm.fillRectangle(def_gc.gc(),
                                          0, 0,
                                          width(), menu.frame_h);
@@ -590,11 +629,11 @@ void Menu::update(int active_index) {
                          false); // render transparent
         }
 
-        if (m_parent)
-            m_parent->drawSubmenu(m_parent->which_sub);
+        //        if (m_parent)
+        //            m_parent->drawSubmenu(m_parent->which_sub);
         /*
-        renderTransp(0, active_index*menu.item_h,
-                     width(), menu.item_h);       
+          renderTransp(0, active_index*menu.item_h,
+          width(), menu.item_h);       
         */
 
     }
@@ -631,6 +670,10 @@ void Menu::show() {
 
 
 void Menu::hide() {
+
+    if (!isVisible())
+        return;
+
     if ((! torn) && hide_tree && m_parent && m_parent->isVisible()) {
         Menu *p = m_parent;
 
@@ -652,12 +695,15 @@ void Menu::grabInputFocus() {
 
 
 void Menu::clearWindow() {
-    menu.window.clear();
     redrawTitle();
+ 
+    if (alpha() < 255) {
+        renderTransp(0, 0,
+                     menu.frame.width(), menu.frame.height());
+        update();
+    }
 
-    renderTransp(0, 0,
-                 m_real_frame_pm.width(), m_real_frame_pm.height());       
-
+    menu.title.clear();
     menu.frame.clear();
 }
 
@@ -682,32 +728,38 @@ void Menu::internal_hide() {
 
 
 void Menu::move(int x, int y) {
-
     menu.window.move(x, y);
 
+    if (!isVisible())
+        return;
+
     if (which_sub != -1)
         drawSubmenu(which_sub);
 
-    redrawTitle();
-    if (!(m_parent && m_parent->moving) && !torn) {
-        
-        renderTransp(0, 0, 
-                     m_real_frame_pm.width(), m_real_frame_pm.height());
-    } else if (!moving) {
-        renderTransp(0, 0, 
+    if (alpha() < 255) {
+        redrawTitle();
+        menu.title.clear();
+        renderTransp(0, 0,
                      m_real_frame_pm.width(), m_real_frame_pm.height());
+        for (size_t i=0; i < menuitems.size(); ++i) {
+            drawItem(i, false, // highlight
+                     true, // clear
+                     false); // transparent
+        }
+
     }
+
 }
 
 
 void Menu::redrawTitle() {
     const char *text = menu.label.c_str();
 
-    const FbTk::Font &font = m_theme.titleFont();
-    int dx = menu.bevel_w, len = menu.label.size();
-    unsigned int l = font.textWidth(text, len) + menu.bevel_w*2;
+    const FbTk::Font &font = theme().titleFont();
+    int dx = theme().bevelWidth(), len = menu.label.size();
+    unsigned int l = font.textWidth(text, len) + theme().bevelWidth()*2;
 
-    switch (m_theme.titleFontJustify()) {
+    switch (theme().titleFontJustify()) {
     case FbTk::RIGHT:
         dx += width() - l;
         break;
@@ -722,14 +774,20 @@ void Menu::redrawTitle() {
     if (menu.title.alpha() != alpha())
         menu.title.setAlpha(alpha());
 
-    menu.title.clear();
+    FbTk::GContext def_gc(menu.title);
+
+    m_real_title_pm.copyArea(m_title_pm.drawable(),
+                             def_gc.gc(),
+                             0, 0,
+                             0, 0,
+                             m_title_pm.width(), m_title_pm.height());
+
     menu.title.updateTransparent();
-    font.drawText(menu.title.window(), // drawable
+    font.drawText(m_real_title_pm.drawable(), // drawable
                   screenNumber(),
-                  m_theme.titleTextGC().gc(), // graphic context
+                  theme().titleTextGC().gc(), // graphic context
                   text, len,  // text string with lenght
-                  dx, font.ascent() + menu.bevel_w);  // position
-
+                  dx, font.ascent() + theme().bevelWidth());  // position
 }
 
 
@@ -789,6 +847,9 @@ void Menu::drawSubmenu(unsigned int index) {
                 menu.window.borderWidth() * 2;
         }
 			
+        item->submenu()->moving = moving;
+        which_sub = index;
+
         if (new_y < 0)
             new_y = 0;
 
@@ -801,8 +862,7 @@ void Menu::drawSubmenu(unsigned int index) {
             item->submenu()->raise();
         }
 			
-        item->submenu()->moving = moving;
-        which_sub = index;
+
     } else
         which_sub = -1;
 
@@ -837,13 +897,13 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
     unsigned int half_w = menu.item_h / 2, quarter_w = menu.item_h / 4;
 
     GC gc =
-        ((highlight || item->isSelected()) ? m_theme.hiliteTextGC().gc() :
-         m_theme.frameTextGC().gc());
+        ((highlight || item->isSelected()) ? theme().hiliteTextGC().gc() :
+         theme().frameTextGC().gc());
 	
     sel_x = item_x;
 	
-    if (m_theme.bulletPos() == FbTk::RIGHT)
-        sel_x += (menu.item_w - menu.item_h - menu.bevel_w);
+    if (theme().bulletPos() == FbTk::RIGHT)
+        sel_x += (menu.item_w - menu.item_h - theme().bevelWidth());
 	
     sel_x += quarter_w;
     sel_y = item_y + quarter_w;
@@ -851,7 +911,7 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
     if (clear) {
         GContext def_gc(menu.frame);
         if (menu.frame_pixmap == 0) {
-            def_gc.setForeground(m_theme.frameTexture().color());
+            def_gc.setForeground(theme().frameTexture().color());
             m_frame_pm.fillRectangle(def_gc.gc(), item_x, item_y, menu.item_w, menu.item_h);
 
         } else {
@@ -878,11 +938,11 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
     if (highlight && (menu.hilite_pixmap != ParentRelative)) {
         if (menu.hilite_pixmap) {
             m_frame_pm.copyArea(menu.hilite_pixmap,
-                                m_theme.hiliteGC().gc(), hoff_x, hoff_y,
+                                theme().hiliteGC().gc(), hoff_x, hoff_y,
                                 hilite_x, hilite_y,
                                 hilite_w, hilite_h);
         } else {            
-            m_frame_pm.fillRectangle(m_theme.hiliteGC().gc(),
+            m_frame_pm.fillRectangle(theme().hiliteGC().gc(),
                                      hilite_x, hilite_y, hilite_w, hilite_h);
         }
         
@@ -890,20 +950,20 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
 	
     
     if (item->isToggleItem() && item->isSelected()) {
-        if (m_theme.selectedPixmap().pixmap().drawable()) {
+        if (theme().selectedPixmap().pixmap().drawable()) {
             // enable clip mask
             XSetClipMask(FbTk::App::instance()->display(),
                          gc,
-                         m_theme.selectedPixmap().mask().drawable());
+                         theme().selectedPixmap().mask().drawable());
             XSetClipOrigin(FbTk::App::instance()->display(),
                            gc, sel_x, item_y);
             // copy bullet pixmap to frame
-            m_frame_pm.copyArea(m_theme.selectedPixmap().pixmap().drawable(),
+            m_frame_pm.copyArea(theme().selectedPixmap().pixmap().drawable(),
                                 gc,
                                 0, 0,
                                 sel_x, item_y,
-                                m_theme.selectedPixmap().width(),
-                                m_theme.selectedPixmap().height());
+                                theme().selectedPixmap().width(),
+                                theme().selectedPixmap().height());
             // disable clip mask
             XSetClipMask(FbTk::App::instance()->display(),
                          gc,
@@ -911,12 +971,12 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
         } else {
             if (menu.sel_pixmap) {
                 m_frame_pm.copyArea(highlight ? menu.frame_pixmap : menu.sel_pixmap,
-                                    m_theme.hiliteGC().gc(), 
+                                    theme().hiliteGC().gc(), 
                                     0, 0,                                 
                                     sel_x, sel_y,
                                     half_w, half_w);
             } else {
-                m_frame_pm.fillRectangle(m_theme.hiliteGC().gc(),
+                m_frame_pm.fillRectangle(theme().hiliteGC().gc(),
                                          sel_x, sel_y, half_w, half_w);
             }
         }
@@ -927,7 +987,7 @@ int Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_t
         renderTransp(item_x, item_y,
                      width(), menu.item_h); 
 
-    item->draw(m_real_frame_pm, m_theme, highlight, 
+    item->draw(m_real_frame_pm, theme(), highlight, 
                item_x, item_y, 
                menu.item_w, menu.item_h);
 
@@ -1033,21 +1093,7 @@ void Menu::buttonReleaseEvent(XButtonEvent &re) {
     if (re.window == menu.title) {
         if (moving) {
             moving = false;
-			
-            if (which_sub >= 0)
-                drawSubmenu(which_sub);
-            if (alpha() < 255) {
-                //m_need_update = true;
-                //                update();
-                renderTransp(0, 0,
-                             m_real_frame_pm.width(), m_real_frame_pm.height());
-                for (size_t i=0; i < menuitems.size(); ++i) {
-                    drawItem(i, false, // highlight
-                             true, // clear
-                             false); // transparent
-                             
-                }
-            }
+            move(x(), y());
         }
 
         if (re.x >= 0 && re.x <= (signed) width() &&
@@ -1170,7 +1216,9 @@ void Menu::motionNotifyEvent(XMotionEvent &me) {
 
 void Menu::exposeEvent(XExposeEvent &ee) {
     if (ee.window == menu.title) {
-        redrawTitle();
+        if (alpha() < 255)
+            redrawTitle();
+        menu.title.clearArea(ee.x, ee.y, ee.width, ee.height);
     } else if (ee.window == menu.frame) {
 
         if (moving) {
@@ -1185,7 +1233,7 @@ void Menu::exposeEvent(XExposeEvent &ee) {
         // Simon was here :-) I think this all makes much more sense when
         // we rename sbl to "start_col", sbl_d to "end_col", ditto id -> row
         // a "sublevel" is basically a column in a multi-column menu (e.g. placement)
-
+        
         if (menu.item_w == 0)
             menu.item_w = 1;
         if (menu.item_h == 0)
@@ -1213,18 +1261,12 @@ void Menu::exposeEvent(XExposeEvent &ee) {
                                          (which_sub == static_cast<signed>(index)), // highlight
                                          false, // clear
                                          true), max_y); // render trans
-                                //                                         ee.x, ee.y, ee.width, ee.height), max_y);
                 }
             }
         }
-          
+        
         menu.frame.clearArea(ee.x, ee.y, ee.width, ee.height);
-        /*
-        menu.frame.updateTransparent(start_column * menu.item_w,
-                                     start_row    * menu.item_h,
-                                     (end_column-start_column+1) * menu.item_w,
-                                     (end_row-start_row+1)       * menu.item_h);
-        */
+
     }
 }
 
@@ -1345,24 +1387,18 @@ void Menu::reconfigure() {
 
     m_need_update = true; // redraw items
 
-    menu.bevel_w = theme().bevelWidth();
     m_border_width = theme().borderWidth();
 
-    if (menu.bevel_w > 10) // clamp to "normal" size
-        menu.bevel_w = 10;
-
     if (m_border_width > 20) // clamp to normal size
         m_border_width = 20;
     if (m_border_width < 0)
         m_border_width = 0;
 
     menu.title.setAlpha(alpha());
-    menu.window.setBackgroundColor(m_theme.borderColor());
-    menu.title.setBackgroundColor(m_theme.borderColor());    
 
-    menu.window.setBorderColor(m_theme.borderColor());
-    menu.title.setBorderColor(m_theme.borderColor());
-    menu.frame.setBorderColor(m_theme.borderColor());
+    menu.window.setBorderColor(theme().borderColor());
+    menu.title.setBorderColor(theme().borderColor());
+    menu.frame.setBorderColor(theme().borderColor());
 
     menu.window.setBorderWidth(m_border_width);
     menu.title.setBorderWidth(m_border_width);
@@ -1415,14 +1451,20 @@ void Menu::update(FbTk::Subject *subj) {
     reconfigure();
 }
 
+                  
 void Menu::renderTransp(int x, int y,
                         unsigned int width, unsigned int height) {
+    // no need to render transparent unless visible
+    if (!isVisible())
+        return;
+
     GContext def_gc(menu.frame);
     m_real_frame_pm.copyArea(m_frame_pm.drawable(),
                              def_gc.gc(),
                              x, y,
                              x, y,
                              width, height);
+
     if (m_transp.get() == 0)
         return;
 
@@ -1433,7 +1475,6 @@ void Menu::renderTransp(int x, int y,
         m_transp->setSource(root, screenNumber());
 
 
-
     if (m_transp->dest() != m_real_frame_pm.drawable())
         m_transp->setDest(m_real_frame_pm.drawable(), screenNumber());
 
@@ -1461,7 +1502,7 @@ void Menu::renderTransp(int x, int y,
                      width, height);
         
 #endif // HAVE_XRENDER
-
+    
 }
 
 }; // end namespace FbTk
diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh
index 0bf828d..6227c07 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.33 2004/06/10 11:38:26 fluxgen Exp $
+// $Id: Menu.hh,v 1.34 2004/06/13 00:31:29 fluxgen Exp $
 
 #ifndef	 FBTK_MENU_HH
 #define	 FBTK_MENU_HH
@@ -205,13 +205,15 @@ private:
         std::string label;
         int x_move, y_move, x_shift, y_shift, sublevels, persub, minsub,
             grab_x, grab_y;
-        unsigned int title_h, frame_h, item_w, item_h, bevel_w,
-            bevel_h;
+        unsigned int title_h, frame_h, item_w, item_h, bevel_w;
     } menu;
 
     Drawable m_root_pm;
     static Menu *s_focused; ///< holds current input focused menu, so one can determine if a menu is focused
-    FbPixmap m_frame_pm, m_real_frame_pm;
+    FbPixmap m_frame_pm,  ///< buffer pixmap
+        m_real_frame_pm; ///< buffer pixmap (this one is shown to the user)
+    FbPixmap m_title_pm, ///< buffer pixmap to avoid flicker
+        m_real_title_pm; ///< buffer pixmap (this one is shown to the user)
     std::auto_ptr<Transparent> m_transp;
     bool m_need_update;
     Timer m_submenu_timer;
-- 
cgit v0.11.2