news download themes documentation links










Menu.cc

00001 // Menu.cc for FbTk - Fluxbox Toolkit 
00002 // Copyright (c) 2001 - 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00003 //
00004 // Basemenu.cc for blackbox - an X11 Window manager
00005 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
00006 //
00007 // Permission is hereby granted, free of charge, to any person obtaining a
00008 // copy of this software and associated documentation files (the "Software"),
00009 // to deal in the Software without restriction, including without limitation
00010 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 // and/or sell copies of the Software, and to permit persons to whom the
00012 // Software is furnished to do so, subject to the following conditions:
00013 //
00014 // The above copyright notice and this permission notice shall be included in
00015 // all copies or substantial portions of the Software.
00016 //
00017 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 // DEALINGS IN THE SOFTWARE.
00024 
00025 // $Id: Menu.cc,v 1.52 2004/01/08 22:07:00 fluxgen Exp $
00026 
00027 //use GNU extensions
00028 #ifndef  _GNU_SOURCE
00029 #define  _GNU_SOURCE
00030 #endif // _GNU_SOURCE
00031 
00032 #include "Menu.hh"
00033 
00034 #include "MenuItem.hh"
00035 #include "ImageControl.hh"
00036 #include "MenuTheme.hh"
00037 #include "App.hh"
00038 #include "EventManager.hh"
00039 #include "Transparent.hh"
00040 #include "SimpleCommand.hh"
00041 
00042 #include <X11/Xatom.h>
00043 #include <X11/keysym.h>
00044 
00045 #include <cstdio>
00046 #include <cstdlib>
00047 #include <cstring>
00048 #include <iostream>
00049 
00050 using namespace std;
00051 
00052 namespace FbTk {
00053 
00054 static Menu *shown = 0;
00055 
00056 Menu *Menu::s_focused = 0;
00057 
00058 Menu::Menu(MenuTheme &tm, ImageControl &imgctrl):
00059     m_theme(tm),
00060     m_parent(0),
00061     m_image_ctrl(imgctrl),
00062     m_screen_width(DisplayWidth(FbTk::App::instance()->display(), tm.screenNum())),
00063     m_screen_height(DisplayHeight(FbTk::App::instance()->display(), tm.screenNum())),
00064     m_alignment(ALIGNDONTCARE),
00065     m_border_width(0),
00066     m_need_update(true) {
00067 
00068     // setup timers
00069 
00070     RefCount<Command> show_cmd(new SimpleCommand<Menu>(*this, &Menu::openSubmenu));
00071     m_submenu_timer.setCommand(show_cmd);
00072     m_submenu_timer.fireOnce(true);
00073 
00074 
00075     RefCount<Command> hide_cmd(new SimpleCommand<Menu>(*this, &Menu::closeMenu));
00076     m_hide_timer.setCommand(hide_cmd);
00077     m_hide_timer.fireOnce(true);
00078 
00079     // make sure we get updated when the theme is reloaded
00080     tm.reconfigSig().attach(this);
00081 
00082     title_vis =
00083         movable =
00084         hide_tree = true;
00085 
00086     shifted =
00087         internal_menu =
00088         moving =
00089         torn =
00090         visible = false;
00091 
00092 
00093 
00094     menu.x_shift =
00095         menu.y_shift =
00096         menu.x_move =
00097         menu.y_move = 0;
00098 
00099     which_sub =
00100         which_press =
00101         which_sbl = -1;
00102 
00103     menu.frame_pixmap =
00104         menu.title_pixmap =
00105         menu.hilite_pixmap =
00106         menu.sel_pixmap = None;
00107 
00108     menu.bevel_w = 2;
00109 
00110     menu.title_h = menu.item_w = menu.frame_h =
00111         m_theme.titleFont().height() + menu.bevel_w * 2;
00112 
00113     menu.sublevels =
00114         menu.persub =
00115         menu.minsub = 0;
00116 
00117     menu.item_h = m_theme.frameFont().height() + menu.bevel_w;
00118 
00119     long event_mask = ButtonPressMask | ButtonReleaseMask | 
00120         ButtonMotionMask | KeyPressMask | ExposureMask | FocusChangeMask;
00121     // create menu window
00122     menu.window = FbTk::FbWindow(tm.screenNum(),
00123                                  0, 0, 10, 10,
00124                                  event_mask,
00125                                  true); // override redirect
00126 
00127     // strip focus change mask from attrib, since we should only use it with main window
00128     event_mask ^= FocusChangeMask;
00129 
00130     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00131     evm.add(*this, menu.window);
00132     
00133 
00134     event_mask |= EnterWindowMask | LeaveWindowMask;
00135     //create menu title
00136     menu.title = FbTk::FbWindow(menu.window,
00137                                 0, 0, width(), menu.title_h,
00138                                 event_mask);
00139                                 
00140     evm.add(*this, menu.title);
00141 
00142     event_mask |= PointerMotionMask;
00143     menu.frame = FbTk::FbWindow(menu.window,
00144                                 0, menu.title_h,
00145                                 width(), menu.frame_h ? menu.frame_h : 1, 
00146                                 event_mask);
00147     evm.add(*this, menu.frame);
00148     // update style 
00149     reconfigure();
00150 }
00151 
00152 Menu::~Menu() {
00153     menu.window.hide();
00154    
00155     if (shown && shown->window() == window())
00156         shown = 0;
00157 
00158     removeAll();
00159 
00160     if (menu.title_pixmap)
00161         m_image_ctrl.removeImage(menu.title_pixmap);
00162 
00163     if (menu.frame_pixmap)
00164         m_image_ctrl.removeImage(menu.frame_pixmap);
00165 
00166     if (menu.hilite_pixmap)
00167         m_image_ctrl.removeImage(menu.hilite_pixmap);
00168 
00169     if (menu.sel_pixmap)
00170         m_image_ctrl.removeImage(menu.sel_pixmap);
00171 
00172     FbTk::EventManager &evm = *FbTk::EventManager::instance();
00173     evm.remove(menu.title);
00174     evm.remove(menu.frame);
00175     evm.remove(menu.window);
00176     if (s_focused == this)
00177         s_focused = 0;
00178 }
00179 
00180 int Menu::insert(const char *label, RefCount<Command> &cmd, int pos) {
00181     return insert(new MenuItem(label, cmd), pos);
00182 }
00183 
00184 int Menu::insert(const char *label, int pos) {
00185     return insert(new MenuItem(label), pos);
00186 }
00187 
00188 int Menu::insert(const char *label, Menu *submenu, int pos) {
00189     submenu->m_parent = this;
00190     return insert(new MenuItem(label, submenu), pos);
00191 }
00192 
00193 int Menu::insert(MenuItem *item, int pos) {
00194     if (pos == -1) {
00195         menuitems.push_back(item);
00196     } else {
00197         menuitems.insert(menuitems.begin() + pos, item);
00198     }
00199     m_need_update = true; // we need to redraw the menu
00200     return menuitems.size();
00201 }
00202 
00203 int Menu::remove(unsigned int index) {
00204     if (index >= menuitems.size()) {
00205 #ifdef DEBUG
00206         std::cout << "Bad index (" << index << ") given to Menu::remove()"
00207                   << " -- should be between 0 and " << menuitems.size()
00208                   << " inclusive." << std::endl;
00209 #endif // DEBUG
00210         return -1;
00211     }
00212 
00213     Menuitems::iterator it = menuitems.begin() + index;
00214     MenuItem *item = (*it);
00215 
00216     if (item) {
00217         menuitems.erase(it);
00218         if ((! internal_menu) && (item->submenu())) {
00219             Menu *tmp = item->submenu();
00220             // if menu is interal we should just hide it instead
00221             // if destroying it
00222             if (! tmp->internal_menu) {
00223                 delete tmp;
00224             } else
00225                 tmp->internal_hide();
00226         }
00227         
00228         
00229         delete item;
00230     }
00231 
00232     if (static_cast<unsigned int>(which_sub) == index)
00233         which_sub = -1;
00234     else if (static_cast<unsigned int>(which_sub) > index)
00235         which_sub--;
00236     m_need_update = true; // we need to redraw the menu
00237     return menuitems.size();
00238 }
00239 
00240 void Menu::removeAll() {
00241     while (!menuitems.empty()) {
00242         remove(0);
00243     }
00244     m_need_update = true;
00245 }
00246 
00247 void Menu::raise() {
00248     menu.window.raise();
00249 }
00250 
00251 void Menu::lower() {
00252     menu.window.lower();
00253 }
00254 
00255 void Menu::nextItem() {
00256     if (which_press >= 0 && which_press == static_cast<signed>(menuitems.size() - 1))
00257         return;
00258 
00259     int old_which_press = which_press;
00260 
00261     if (old_which_press >= 0 && 
00262         old_which_press < static_cast<signed>(menuitems.size()) && 
00263         menuitems[old_which_press] != 0) {
00264         if (menuitems[old_which_press]->submenu()) {
00265             // we need to do this explicitly on the menu.window
00266             // since it might hide the parent if we use Menu::hide
00267             menuitems[old_which_press]->submenu()->menu.window.hide();
00268         }
00269         drawItem(old_which_press, false, true, true);
00270     }
00271 
00272     // restore old in case we changed which_press
00273     which_press = old_which_press;
00274     if (which_press < 0 || which_press >= static_cast<signed>(menuitems.size()))
00275         which_press = 0;
00276     else if (which_press > 0 && which_press < static_cast<signed>(menuitems.size() - 1))
00277         which_press++;
00278 
00279 
00280     if (menuitems[which_press] == 0)
00281         return;
00282 
00283     if (menuitems[which_press]->submenu())
00284         drawSubmenu(which_press);
00285     else
00286         drawItem(which_press, true, true, true);
00287 
00288 }
00289 
00290 void Menu::prevItem() {
00291 
00292     int old_which_press = which_press;
00293 
00294     if (old_which_press >= 0 && old_which_press < static_cast<signed>(menuitems.size())) {
00295         if (menuitems[old_which_press]->submenu()) {
00296             // we need to do this explicitly on the menu.window
00297             // since it might hide the parent if we use Menu::hide
00298             menuitems[old_which_press]->submenu()->menu.window.hide();            
00299         }
00300         drawItem(old_which_press, false, true, true);
00301     }
00302     // restore old in case we changed which_press
00303     which_press = old_which_press;
00304 
00305     if (which_press < 0 || which_press >= static_cast<signed>(menuitems.size()))
00306         which_press = 0;
00307     else if (which_press - 1 >= 0)
00308         which_press--;
00309 
00310     if (menuitems[which_press] != 0) {
00311         if (menuitems[which_press]->submenu())
00312             drawSubmenu(which_press);
00313         else
00314             drawItem(which_press, true, true, true);
00315     }
00316 
00317 }
00318 
00319 void Menu::enterSubmenu() {
00320     if (which_press < 0 || which_press >= static_cast<signed>(menuitems.size()))
00321         return;
00322 
00323     Menu *submenu = menuitems[which_press]->submenu();
00324     if (submenu == 0)
00325         return;
00326 
00327     submenu->grabInputFocus();
00328     submenu->which_press = -1; // so we land on 0 after nextItem()
00329     submenu->nextItem();
00330 }
00331 
00332 void Menu::enterParent() {
00333     if (which_press < 0 || which_press >= static_cast<signed>(menuitems.size()) || parent() == 0)
00334         return;
00335 
00336     Menu *submenu = menuitems[which_press]->submenu();
00337     if (submenu)
00338         submenu->menu.window.hide();
00339 
00340     drawItem(which_press, false, true, true);
00341     which_press = -1; // dont select any in this 
00342     // return focus to parent but keep this window open
00343     parent()->grabInputFocus();
00344 }
00345 
00346 void Menu::disableTitle() {
00347     setTitleVisibility(false);
00348 }
00349 
00350 void Menu::enableTitle() {
00351     setTitleVisibility(true);
00352 }
00353 
00354 void Menu::update(int active_index) {
00355 
00356     if (menu.bevel_w > 10) // clamp to "normal" size
00357         menu.bevel_w = 10;
00358     if (m_border_width > 20)
00359         m_border_width = 20;
00360 
00361     menu.item_h = m_theme.frameFont().height() + menu.bevel_w;
00362     menu.title_h = m_theme.titleFont().height() + menu.bevel_w*2;
00363 
00364     if (title_vis) {
00365         menu.item_w = m_theme.frameFont().textWidth(menu.label.c_str(), menu.label.size());
00366         
00367         menu.item_w += (menu.bevel_w * 2);
00368     }   else
00369         menu.item_w = 1;
00370 
00371     int ii = 0;
00372     Menuitems::iterator it = menuitems.begin();
00373     Menuitems::iterator it_end = menuitems.end();
00374     for (; it != it_end; ++it) {
00375         MenuItem *itmp = (*it);
00376 
00377         const char *s = itmp->label().c_str();
00378         int l = itmp->label().size();
00379 
00380         ii = m_theme.frameFont().textWidth(s, l);
00381             
00382 
00383         ii += (menu.bevel_w * 2) + (menu.item_h * 2);
00384 
00385         menu.item_w = ((menu.item_w < (unsigned int) ii) ? ii : menu.item_w);
00386     }
00387 
00388     if (menuitems.size()) {
00389         menu.sublevels = 1;
00390 
00391         while (menu.item_h * (menuitems.size() + 1) / menu.sublevels +
00392                menu.title_h + m_border_width > m_screen_height) {
00393             menu.sublevels++;
00394         }
00395 
00396         if (menu.sublevels < menu.minsub) 
00397             menu.sublevels = menu.minsub;
00398 
00399         menu.persub = menuitems.size() / menu.sublevels;
00400         if (menuitems.size() % menu.sublevels) menu.persub++;
00401     } else {
00402         menu.sublevels = 0;
00403         menu.persub = 0;
00404     }
00405 
00406     int itmp = (menu.item_h * menu.persub);
00407     menu.frame_h = itmp < 0 ? 0 : itmp;
00408 
00409     int new_width = (menu.sublevels * menu.item_w);
00410     int new_height = menu.frame_h;
00411 
00412     if (title_vis)
00413         new_height += menu.title_h + ((menu.frame_h>0)?menu.title.borderWidth():0);
00414 
00415 
00416     if (new_width < 1) 
00417         new_width = menu.item_w;
00418 
00419     if (new_height < 1)
00420         new_height = 1;
00421 
00422     menu.window.resize(new_width, new_height);
00423 
00424     Pixmap tmp;
00425     if (title_vis) {
00426         tmp = menu.title_pixmap;
00427         const FbTk::Texture &tex = m_theme.titleTexture();
00428         if (!tex.usePixmap()) {
00429             menu.title_pixmap = None;
00430             menu.title.setBackgroundColor(tex.color());
00431         } else {
00432             menu.title_pixmap =
00433                 m_image_ctrl.renderImage(width(), menu.title_h, tex);
00434             menu.title.setBackgroundPixmap(menu.title_pixmap);
00435         }
00436 
00437         if (tmp) 
00438             m_image_ctrl.removeImage(tmp);
00439 
00440     }
00441 
00442     tmp = menu.frame_pixmap;
00443     const FbTk::Texture &frame_tex = m_theme.frameTexture();
00444     if (!frame_tex.usePixmap()) {
00445         menu.frame_pixmap = None;
00446     } else {
00447         menu.frame_pixmap =
00448             m_image_ctrl.renderImage(width(), menu.frame_h, frame_tex);        
00449     }
00450 
00451     if (tmp)
00452         m_image_ctrl.removeImage(tmp);
00453 
00454     tmp = menu.hilite_pixmap;
00455     const FbTk::Texture &hilite_tex = m_theme.hiliteTexture();
00456     if (!hilite_tex.usePixmap()) {
00457         menu.hilite_pixmap = None;
00458     } else
00459         menu.hilite_pixmap =
00460             m_image_ctrl.renderImage(menu.item_w, menu.item_h, hilite_tex);
00461     if (tmp)
00462         m_image_ctrl.removeImage(tmp);
00463 
00464     tmp = menu.sel_pixmap;
00465     if (!hilite_tex.usePixmap()) {
00466         menu.sel_pixmap = None;
00467     } else {
00468         int hw = menu.item_h / 2;
00469         menu.sel_pixmap =
00470             m_image_ctrl.renderImage(hw, hw, hilite_tex);
00471     }
00472     if (tmp) 
00473         m_image_ctrl.removeImage(tmp);
00474 
00475 
00476 
00477     if (title_vis) {
00478         menu.title.moveResize(-menu.title.borderWidth(), -menu.title.borderWidth(), 
00479                               width() + menu.title.borderWidth(), menu.title_h);
00480     }
00481 
00482     menu.frame.moveResize(0, ((title_vis) ? menu.title.y() + menu.title.height() + 
00483                               menu.title.borderWidth()*2 : 0), 
00484                           menu.window.width(), menu.frame_h);
00485 
00486     // render pixmaps
00487     Display *disp = FbTk::App::instance()->display();
00488 
00489     XWindowAttributes attr;
00490 
00491     if (m_need_update && (m_frame_pm.width() != menu.frame.width() ||
00492                           m_frame_pm.height() != menu.frame.height() )){
00493         XGetWindowAttributes(disp, menu.frame.window(), &attr);
00494         m_frame_pm = FbTk::FbPixmap(menu.frame.window(),
00495                                     menu.frame.width(), menu.frame.height(),
00496                                     attr.depth);
00497 
00498         if (m_frame_pm.drawable() == 0) {
00499             cerr<<"FbTk::Menu: Warning: Failed to create pixmap ("<<
00500                 menu.frame.window()<<", "<<menu.frame.width()<<", "<<
00501                 menu.frame.height()<<
00502                 ", "<<attr.depth<<") !"<<endl;
00503         }
00504 
00505        
00506     }
00507 
00508     menu.frame.setBackgroundPixmap(m_frame_pm.drawable());
00509 
00510     clearWindow();
00511 
00512     if (title_vis && visible) 
00513         redrawTitle();
00514 
00515     if (active_index >= 0) {
00516         for (unsigned int i = 0; visible && i < menuitems.size(); i++) {
00517             if (i == (unsigned int)which_sub) {
00518                 drawItem(i, true, true, false);
00519             } else
00520                 drawItem(i, (static_cast<signed>(i) == active_index && isItemEnabled(i)), true, false);
00521         }
00522 
00523         if (m_parent && visible)
00524             m_parent->drawSubmenu(m_parent->which_sub);
00525     }
00526 
00527     menu.window.clear();
00528     renderTransFrame();
00529                     
00530     m_need_update = false;
00531     menu.window.showSubwindows();
00532 }
00533 
00534 
00535 void Menu::show() {
00536     if (m_need_update)
00537         update();
00538     menu.window.showSubwindows();
00539     menu.window.show();
00541     raise();
00542     visible = true;
00543 
00544     if (! m_parent && shown != this) {
00545         if (shown && (! shown->torn))
00546             shown->hide();
00547 
00548         shown = this;
00549     }
00550 
00551 }
00552 
00553 
00554 void Menu::hide() {
00555     if ((! torn) && hide_tree && m_parent && m_parent->isVisible()) {
00556         Menu *p = m_parent;
00557 
00558         while (p->isVisible() && (! p->torn) && p->m_parent)
00559             p = p->m_parent;
00560         p->internal_hide();
00561     } else
00562         internal_hide();
00563     
00564 }
00565 
00566 void Menu::grabInputFocus() {
00567     s_focused = this;
00568 
00569     // grab input focus
00570     menu.window.setInputFocus(RevertToPointerRoot, CurrentTime);
00571 
00572 }
00573 
00574 
00575 void Menu::clearWindow() {
00576     menu.window.clear();
00577     menu.title.clear();
00578     menu.frame.clear();
00579 }
00580 
00581 void Menu::internal_hide() {
00582     if (which_sub >= 0) {
00583         MenuItem *tmp = menuitems[which_sub];
00584         tmp->submenu()->internal_hide();
00585     }
00586 
00587     if (m_parent && (! torn)) {
00588         m_parent->drawItem(m_parent->which_sub, false, true);
00589 
00590         m_parent->which_sub = -1;
00591     } else if (shown && shown->menu.window == menu.window)
00592         shown = (Menu *) 0;
00593 
00594     torn = visible = false;
00595     which_sub = which_press = which_sub = -1;
00596 
00597     menu.window.hide();
00598 }
00599 
00600 
00601 void Menu::move(int x, int y) {
00602 
00603     menu.window.move(x, y);
00604 
00605     if (which_sub != -1)
00606         drawSubmenu(which_sub);
00607 
00608     if (!(m_parent && m_parent->moving) && !torn) {
00609         redrawTitle();
00610         renderTransFrame();
00611     }
00612 }
00613 
00614 
00615 void Menu::redrawTitle() {
00616     const char *text = menu.label.c_str();
00617 
00618     const FbTk::Font &font = m_theme.titleFont();
00619     int dx = menu.bevel_w, len = menu.label.size();
00620     unsigned int l = font.textWidth(text, len) + menu.bevel_w*2;
00621 
00622     switch (m_theme.titleFontJustify()) {
00623     case FbTk::RIGHT:
00624         dx += width() - l;
00625         break;
00626 
00627     case FbTk::CENTER:
00628         dx += (width() - l) / 2;
00629         break;
00630     default:
00631         break;
00632     }
00633     menu.title.clear();
00634     font.drawText(menu.title.window(), // drawable
00635                   screenNumber(),
00636                   m_theme.titleTextGC().gc(), // graphic context
00637                   text, len,  // text string with lenght
00638                   dx, font.ascent() + menu.bevel_w);  // position
00639 
00640     menu.title.updateTransparent();
00641     
00642 }
00643 
00644 
00645 void Menu::drawSubmenu(unsigned int index) {
00646     if (which_sub >= 0 && static_cast<unsigned int>(which_sub) != index && 
00647         static_cast<unsigned int>(which_sub) < menuitems.size()) {
00648         MenuItem *itmp = menuitems[which_sub];
00649 
00650         if (! itmp->submenu()->isTorn())
00651             itmp->submenu()->internal_hide();
00652     }
00653 
00654     if (index >= menuitems.size())
00655         return;
00656 
00657     MenuItem *item = menuitems[index];
00658     if (item->submenu() && visible && (! item->submenu()->isTorn()) &&
00659         item->isEnabled()) {
00660             
00661         if (item->submenu()->m_parent != this)
00662             item->submenu()->m_parent = this;
00663             
00664         int sbl = index / menu.persub, i = index - (sbl * menu.persub);
00665         int new_x = x() + ((menu.item_w * (sbl + 1)) + menu.window.borderWidth());
00666         int new_y;
00667         
00668         if (m_alignment == ALIGNTOP) {
00669             new_y = (((shifted) ? menu.y_shift : y()) +
00670                      ((title_vis) ? menu.title_h + menu.title.borderWidth() : 0) -
00671                      ((item->submenu()->title_vis) ?
00672                       item->submenu()->menu.title_h + menu.window.borderWidth() : 0));
00673         } else {
00674             new_y = (((shifted) ? menu.y_shift : y()) +
00675                      (menu.item_h * i) +
00676                      ((title_vis) ? menu.title_h + menu.window.borderWidth() : 0) -
00677                      ((item->submenu()->title_vis) ?
00678                   item->submenu()->menu.title_h + menu.window.borderWidth() : 0));
00679         }
00680             
00681         if (m_alignment == ALIGNBOTTOM &&
00682             (new_y + item->submenu()->height()) > ((shifted) ? menu.y_shift :
00683                                                    y()) + height()) {
00684             new_y = (((shifted) ? menu.y_shift : y()) +
00685                      height() - item->submenu()->height());
00686         }
00687 
00688         if ((new_x + item->submenu()->width()) > m_screen_width) {
00689             new_x = ((shifted) ? menu.x_shift : x()) -
00690                 item->submenu()->width() - menu.window.borderWidth();
00691         }
00692             
00693         if (new_x < 0)
00694             new_x = 0;
00695 
00696         if ((new_y + item->submenu()->height()) > m_screen_height) {
00697             new_y = m_screen_height - item->submenu()->height() -
00698                 menu.window.borderWidth() * 2;
00699         }
00700             
00701         if (new_y < 0)
00702             new_y = 0;
00703 
00704         item->submenu()->move(new_x, new_y);
00705         if (! moving)
00706             drawItem(index, true);
00707         
00708         if (! item->submenu()->isVisible()) {
00709             item->submenu()->show();
00710             item->submenu()->raise();
00711         }
00712             
00713         item->submenu()->moving = moving;
00714         which_sub = index;
00715     } else
00716         which_sub = -1;
00717 
00718 }
00719 
00720 
00721 bool Menu::hasSubmenu(unsigned int index) const {
00722     if (index >= menuitems.size()) //boundary check
00723         return false;
00724     
00725     if (!menuitems[index]->submenu()) //has submenu?
00726         return false;
00727     
00728     return true;    
00729 }
00730 
00731 
00732 void Menu::drawItem(unsigned int index, bool highlight, bool clear, bool render_trans,
00733                     int x, int y, unsigned int w, unsigned int h) {
00734     if (index >= menuitems.size() || menuitems.size() == 0 || 
00735         menu.persub == 0)
00736         return;
00737 
00738     MenuItem *item = menuitems[index];
00739     if (! item) return;
00740 
00741     bool dotext = true, dohilite = true, dosel = true;
00742     const char *text = item->label().c_str();
00743     int sbl = index / menu.persub, i = index - (sbl * menu.persub);
00744     int item_x = (sbl * menu.item_w), item_y = (i * menu.item_h);
00745     int hilite_x = item_x, hilite_y = item_y, hoff_x = 0, hoff_y = 0;
00746     int text_x = 0, text_y = 0, len = strlen(text), sel_x = 0, sel_y = 0;
00747     unsigned int hilite_w = menu.item_w, hilite_h = menu.item_h, text_w = 0, text_h = 0;
00748     unsigned int half_w = menu.item_h / 2, quarter_w = menu.item_h / 4;
00749     const FbTk::Font &font = m_theme.frameFont();
00750     if (text) {     
00751         text_w = font.textWidth(text, len);
00752 
00753         text_y = item_y + menu.bevel_w/2 + font.ascent();
00754 
00755         switch(m_theme.frameFontJustify()) {
00756         case FbTk::LEFT:
00757             text_x = item_x + menu.bevel_w + menu.item_h + 1;
00758             break;
00759             
00760         case FbTk::RIGHT:
00761             text_x = item_x + menu.item_w - (menu.item_h + menu.bevel_w + text_w);
00762             break;          
00763         default: //center
00764             text_x = item_x + ((menu.item_w + 1 - text_w) / 2);
00765             break;
00766         }
00767 
00768         text_h = menu.item_h - menu.bevel_w;
00769     }
00770     
00771     GC gc =
00772         ((highlight || item->isSelected()) ? m_theme.hiliteTextGC().gc() :
00773          m_theme.frameTextGC().gc());
00774     const GContext &tgc =
00775         (highlight ? m_theme.hiliteTextGC() :
00776          (item->isEnabled() ? m_theme.frameTextGC() : m_theme.disableTextGC() ) );
00777     
00778     sel_x = item_x;
00779     
00780     if (m_theme.bulletPos() == FbTk::RIGHT)
00781         sel_x += (menu.item_w - menu.item_h - menu.bevel_w);
00782     
00783     sel_x += quarter_w;
00784     sel_y = item_y + quarter_w;
00785 
00786     if (clear) {
00787         FbTk::GContext def_gc(menu.frame.window());
00788         if (menu.frame_pixmap == 0) {
00789             def_gc.setForeground(m_theme.frameTexture().color());
00790             m_frame_pm.fillRectangle(def_gc.gc(), item_x, item_y, menu.item_w, menu.item_h);
00791 
00792         } else {
00793 
00794             m_frame_pm.copyArea(menu.frame_pixmap, def_gc.gc(),
00795                                 item_x, item_y,
00796                                 item_x, item_y,
00797                                 menu.item_w, menu.item_h);
00798         }    
00799     } else if (! (x == y && y == -1 && w == h && h == 0)) {
00800         // calculate the which part of the hilite to redraw
00801         if (! (std::max(item_x, x) <= (signed) std::min(item_x + menu.item_w, x + w) &&
00802                std::max(item_y, y) <= (signed) std::min(item_y + menu.item_h, y + h))) {
00803             dohilite = False;
00804         } else {
00805             hilite_x = std::max(item_x, x);
00806             hilite_y = std::max(item_y, y);
00807             hilite_w = std::min(item_x + menu.item_w, x + w) - hilite_x;
00808             hilite_h = std::min(item_y + menu.item_h, y + h) - hilite_y;
00809             hoff_x = hilite_x % menu.item_w;
00810             hoff_y = hilite_y % menu.item_h;
00811         }
00812         
00813         // check if we need to redraw the text      
00814         int text_ry = item_y + (menu.bevel_w / 2);
00815         if (! (std::max(text_x, x) <= (signed) std::min(text_x + text_w, x + w) &&
00816                std::max(text_ry, y) <= (signed) std::min(text_ry + text_h, y + h)))
00817             dotext = false;
00818         
00819         // check if we need to redraw the select pixmap/menu bullet
00820         if (! (std::max(sel_x, x) <= (signed) std::min(sel_x + half_w, x + w) &&
00821                std::max(sel_y, y) <= (signed) std::min(sel_y + half_w, y + h)))
00822             dosel = false;
00823     
00824     }
00825     
00826     if (dohilite && highlight && (menu.hilite_pixmap != ParentRelative)) {
00827         if (menu.hilite_pixmap) {
00828             m_frame_pm.copyArea(menu.hilite_pixmap,
00829                                 m_theme.hiliteGC().gc(), hoff_x, hoff_y,
00830                                 hilite_x, hilite_y,
00831                                 hilite_w, hilite_h);
00832         } else {            
00833             m_frame_pm.fillRectangle(m_theme.hiliteGC().gc(),
00834                                      hilite_x, hilite_y, hilite_w, hilite_h);
00835         }
00836         
00837     } 
00838     
00839     
00840     if (item->isToggleItem() && item->isSelected() &&
00841         menu.sel_pixmap != ParentRelative) {
00842         if (m_theme.selectedPixmap().pixmap().drawable()) {
00843             // enable clip mask
00844             XSetClipMask(FbTk::App::instance()->display(),
00845                          gc,
00846                          m_theme.selectedPixmap().mask().drawable());
00847             XSetClipOrigin(FbTk::App::instance()->display(),
00848                            gc, sel_x, item_y);
00849             // copy bullet pixmap to frame
00850             m_frame_pm.copyArea(m_theme.selectedPixmap().pixmap().drawable(),
00851                                 gc,
00852                                 0, 0,
00853                                 sel_x, item_y,
00854                                 m_theme.selectedPixmap().width(),
00855                                 m_theme.selectedPixmap().height());
00856             // disable clip mask
00857             XSetClipMask(FbTk::App::instance()->display(),
00858                          gc,
00859                          None);
00860         } else {
00861             if (menu.sel_pixmap) {
00862                 m_frame_pm.copyArea(highlight ? menu.frame_pixmap : menu.sel_pixmap,
00863                                     m_theme.hiliteGC().gc(), 
00864                                     0, 0,                                 
00865                                     sel_x, sel_y,
00866                                     half_w, half_w);
00867             } else {
00868                 m_frame_pm.fillRectangle(m_theme.hiliteGC().gc(),
00869                                          sel_x, sel_y, half_w, half_w);
00870             }
00871         }
00872         
00873     } else if (item->isToggleItem() && m_theme.unselectedPixmap().pixmap().drawable() != 0) {
00874         // enable clip mask
00875         XSetClipMask(FbTk::App::instance()->display(),
00876                      gc,
00877                      m_theme.unselectedPixmap().mask().drawable());
00878         XSetClipOrigin(FbTk::App::instance()->display(),
00879                        gc, sel_x, item_y);
00880         // copy bullet pixmap to frame
00881         m_frame_pm.copyArea(m_theme.unselectedPixmap().pixmap().drawable(),
00882                             gc,
00883                             0, 0,
00884                             sel_x, item_y,
00885                             m_theme.unselectedPixmap().width(),
00886                             m_theme.unselectedPixmap().height());
00887         // disable clip mask
00888         XSetClipMask(FbTk::App::instance()->display(),
00889                      gc,
00890                      None);
00891     }
00892     
00893     if (dotext && text) {
00895         // once we've cleaned up the menu code this will be somewhere else...
00896         if (strcmp(text, "---") == 0){ // draw separator
00897             m_frame_pm.drawRectangle(tgc.gc(),
00898                                      item_x + menu.bevel_w + menu.item_h + 1, item_y + (menu.item_h / 2),
00899                                      menu.item_w - ((menu.bevel_w + menu.item_h) * 2) - 1, 0);
00900         } else { // draw normal text
00901             m_theme.frameFont().drawText(m_frame_pm.drawable(), // drawable
00902                                          screenNumber(),
00903                                          tgc.gc(),
00904                                          text, len, // text string and lenght
00905                                          text_x, text_y); // position
00906         }
00907     }
00908 
00909     if (dosel && item->submenu()) {
00910         if (m_theme.bulletPixmap().pixmap().drawable() != 0) {
00911             // enable clip mask
00912             XSetClipMask(FbTk::App::instance()->display(),
00913                          gc,
00914                          m_theme.bulletPixmap().mask().drawable());
00915             XSetClipOrigin(FbTk::App::instance()->display(),
00916                            gc, sel_x, item_y);
00917             // copy bullet pixmap to frame
00918             m_frame_pm.copyArea(m_theme.bulletPixmap().pixmap().drawable(),
00919                                 gc,
00920                                 0, 0,
00921                                 sel_x, item_y,
00922                                 m_theme.bulletPixmap().width(),
00923                                 m_theme.bulletPixmap().height());
00924             // disable clip mask
00925             XSetClipMask(FbTk::App::instance()->display(),
00926                          gc,
00927                          None);
00928         } else {
00929             switch (m_theme.bullet()) {
00930             case MenuTheme::SQUARE:
00931                 m_frame_pm.drawRectangle(gc, sel_x, sel_y, half_w, half_w);
00932                 break;
00933 
00934             case MenuTheme::TRIANGLE:
00935                 XPoint tri[3];
00936 
00937                 if (m_theme.bulletPos() == FbTk::RIGHT) {
00938                     tri[0].x = sel_x + quarter_w - 2;
00939                     tri[0].y = sel_y + quarter_w - 2;
00940                     tri[1].x = 4;
00941                     tri[1].y = 2;
00942                     tri[2].x = -4;
00943                     tri[2].y = 2;
00944                 } else {
00945                     tri[0].x = sel_x + quarter_w - 2;
00946                     tri[0].y = item_y + half_w;
00947                     tri[1].x = 4;
00948                     tri[1].y = 2;
00949                     tri[2].x = 0;
00950                     tri[2].y = -4;
00951                 }
00952             
00953                 m_frame_pm.fillPolygon(gc, tri, 3, Convex,
00954                                        CoordModePrevious);
00955                 break;
00956             
00957             case MenuTheme::DIAMOND:
00958                 XPoint dia[4];
00959 
00960                 dia[0].x = sel_x + quarter_w - 3;
00961                 dia[0].y = item_y + half_w;
00962                 dia[1].x = 3;
00963                 dia[1].y = -3;
00964                 dia[2].x = 3;
00965                 dia[2].y = 3;
00966                 dia[3].x = -3;
00967                 dia[3].y = 3;
00968 
00969                 m_frame_pm.fillPolygon(gc, dia, 4, Convex,
00970                                        CoordModePrevious);
00971                 break;
00972             default:
00973                 break;
00974             }
00975         }
00976     }
00977 
00978     menu.frame.clearArea(item_x, item_y,
00979                          menu.item_w, menu.item_h, False);
00980 
00981     
00982     menu.frame.updateTransparent(item_x, item_y,
00983                                  menu.item_w, menu.item_h);
00984     
00985 }
00986 
00987 void Menu::setLabel(const char *labelstr) {
00988     //make sure we don't send 0 to std::string
00989     menu.label = (labelstr ? labelstr : "");
00990     reconfigure();
00991 }
00992 
00993 
00994 void Menu::setItemSelected(unsigned int index, bool sel) {
00995     if (index >= menuitems.size()) return;
00996 
00997     MenuItem *item = find(index);
00998     if (! item) return;
00999 
01000     item->setSelected(sel);
01001 
01002 }
01003 
01004 
01005 bool Menu::isItemSelected(unsigned int index) const{
01006     if (index >= menuitems.size()) return false;
01007 
01008     const MenuItem *item = find(index);
01009     if (!item)
01010         return false;
01011 
01012     return item->isSelected();
01013 }
01014 
01015 
01016 void Menu::setItemEnabled(unsigned int index, bool enable) {
01017     if (index >= menuitems.size()) return;
01018 
01019     MenuItem *item = find(index);
01020     if (! item) return;
01021 
01022     item->setEnabled(enable);
01023 
01024 }
01025 
01026 
01027 bool Menu::isItemEnabled(unsigned int index) const {
01028     if (index >= menuitems.size()) return false;
01029 
01030     const MenuItem *item = find(index);
01031     if (!item)
01032         return false;
01033 
01034     return item->isEnabled();
01035 }
01036 
01037 void Menu::handleEvent(XEvent &event) {
01038     if (event.type == FocusOut) {
01039         if (s_focused == this)
01040             s_focused = 0;
01041     } else if (event.type == FocusIn) {
01042         if (s_focused != this)
01043             s_focused = this; 
01044     }
01045 }
01046 
01047 void Menu::buttonPressEvent(XButtonEvent &be) {
01048     if (be.window == menu.title)
01049         grabInputFocus();
01050 
01051     if (be.window == menu.frame && menu.item_h != 0 && menu.item_w != 0) {
01052 
01053         int sbl = (be.x / menu.item_w), i = (be.y / menu.item_h);
01054         int w = (sbl * menu.persub) + i;
01055 
01056         if (w < static_cast<int>(menuitems.size()) && w >= 0) {
01057             which_press = i;
01058             which_sbl = sbl;
01059 
01060             MenuItem *item = menuitems[w];
01061 
01062             if (item->submenu()) {
01063                 if (!item->submenu()->isVisible())
01064                     drawSubmenu(w);
01065             } else
01066                 drawItem(w, item->isEnabled(), true, true);
01067         }
01068     } else {
01069         menu.x_move = be.x_root - x();
01070         menu.y_move = be.y_root - y();
01071     }
01072 }
01073 
01074 
01075 void Menu::buttonReleaseEvent(XButtonEvent &re) {
01076     if (re.window == menu.title) {
01077         if (moving) {
01078             moving = false;
01079             
01080             if (which_sub >= 0)
01081                 drawSubmenu(which_sub);
01082             update();
01083         }
01084 
01085         if (re.x >= 0 && re.x <= (signed) width() &&
01086             re.y >= 0 && re.y <= (signed) menu.title_h &&
01087             re.button == 3)
01088             hide();
01089             
01090     } else if (re.window == menu.frame &&
01091                re.x >= 0 && re.x < (signed) width() &&
01092                re.y >= 0 && re.y < (signed) menu.frame_h) {
01093             
01094         int sbl = (re.x / menu.item_w), i = (re.y / menu.item_h),
01095             ix = sbl * menu.item_w, iy = i * menu.item_h,
01096             w = (sbl * menu.persub) + i,
01097             p = (which_sbl * menu.persub) + which_press;
01098 
01099         if (w < static_cast<int>(menuitems.size()) && w >= 0) {
01100             if (p == w && isItemEnabled(w)) {
01101                 if (re.x > ix && re.x < (signed) (ix + menu.item_w) &&
01102                     re.y > iy && re.y < (signed) (iy + menu.item_h)) {
01103                     menuitems[w]->click(re.button, re.time);
01104                     itemSelected(re.button, w);
01105                     // redraw whole menu as enableds for any item
01106                     // may have changed
01107                     update(w);
01108                 }
01109             } else {
01110                 drawItem(p, isItemEnabled(p) && (p == which_sub), true, true);
01111             }
01112         } else
01113             drawItem(p, false, true, true);
01114     }
01115 }
01116 
01117 
01118 void Menu::motionNotifyEvent(XMotionEvent &me) {
01119 
01120     if (me.window == menu.title && (me.state & Button1Mask)) {
01121         stopHide();
01122         if (movable) {
01123             if (! moving) {
01124                 if (m_parent && (! torn)) {
01125                     m_parent->drawItem(m_parent->which_sub, false, true, true);
01126                     m_parent->which_sub = -1;
01127                 }
01128 
01129                 moving = torn = true;
01130 
01131                 if (which_sub >= 0)
01132                     drawSubmenu(which_sub);
01133             } else {
01134                 menu.window.move(me.x_root - menu.x_move, me.y_root - menu.y_move);
01135 
01136                 // if (which_sub >= 0)
01137                 //     drawSubmenu(which_sub);
01138             }
01139         }
01140     } else if ((! (me.state & Button1Mask)) && me.window == menu.frame &&
01141                me.x >= 0 && me.x < (signed) width() &&
01142                me.y >= 0 && me.y < (signed) menu.frame_h) {
01143         stopHide();
01144         int sbl = (me.x / menu.item_w), i = (me.y / menu.item_h),
01145             w = (sbl * menu.persub) + i;
01146 
01147         if ((i != which_press || sbl != which_sbl) &&
01148             (w < static_cast<int>(menuitems.size()) && w >= 0)) {
01149 
01150             if (which_press != -1 && which_sbl != -1) {
01151 
01152                 int p = which_sbl * menu.persub + which_press;
01153                 MenuItem *item = menuitems[p];
01154                 // don't redraw disabled items on enter/leave
01155                 if (item != 0 && item->isEnabled()) {
01156 
01157                     drawItem(p, false, true, true);
01158 
01159                     if (item->submenu()) {
01160 
01161                         if (item->submenu()->isVisible() &&
01162                             !item->submenu()->isTorn()) {
01163                             // setup hide timer for submenu
01164                             item->submenu()->startHide();
01165                         }
01166                     }
01167 
01168                 }
01169 
01170             }
01171 
01172             which_press = i;
01173             which_sbl = sbl;
01174 
01175             MenuItem *itmp = menuitems[w];
01176 
01177             if (itmp->submenu()) {
01178 
01179                 drawItem(w, true);
01180 
01181                 if (theme().menuMode() == MenuTheme::DELAY_OPEN) {
01182                     // setup show menu timer
01183                     timeval timeout;
01184                     timeout.tv_sec = 0;
01185                     timeout.tv_usec = theme().delayOpen() * 1000; // transformed to usec
01186                     m_submenu_timer.setTimeout(timeout);
01187                     m_submenu_timer.start();
01188 
01189                 }
01190 
01191             } else {
01192                 m_submenu_timer.stop();
01193                 if (itmp->isEnabled())
01194                     drawItem(w, true, true, true);
01195             }
01196         }
01197     }
01198 }
01199 
01200 
01201 void Menu::exposeEvent(XExposeEvent &ee) {
01202     if (ee.window == menu.title) {
01203         redrawTitle();
01204     } else if (ee.window == menu.frame) {
01205         // this is a compilicated algorithm... lets do it step by step...
01206         // first... we see in which sub level the expose starts... and how many
01207         // items down in that sublevel
01208         if (menu.item_w == 0)
01209             menu.item_w = 1;
01210         if (menu.item_h == 0)
01211             menu.item_h = 1;
01212         unsigned int sbl = (ee.x / menu.item_w), id = (ee.y / menu.item_h),
01213             // next... figure out how many sublevels over the redraw spans
01214             sbl_d = ((ee.x + ee.width) / menu.item_w),
01215             // then we see how many items down to redraw
01216             id_d = ((ee.y + ee.height) / menu.item_h);
01217         if (static_cast<signed>(id_d) > menu.persub) 
01218             id_d = menu.persub;
01219 
01220         // draw the sublevels and the number of items the exposure spans
01221         unsigned int i, ii;
01222         for (i = sbl; i <= sbl_d; i++) {
01223             // set the iterator to the first item in the sublevel needing redrawing
01224             unsigned int index = id + i * menu.persub;
01225             if (index < menuitems.size()) {
01226                 Menuitems::iterator it = menuitems.begin() + index;
01227                 Menuitems::iterator it_end = menuitems.end();
01228                 for (ii = id; ii <= id_d && it != it_end; ++it, ii++) {
01229                     unsigned int index = ii + (i * menu.persub);
01230                     drawItem(index, (which_sub == static_cast<signed>(index)), true, true,
01231                              ee.x, ee.y, ee.width, ee.height);
01232                 }
01233             }
01234         }
01235     }
01236 }
01237 
01238 
01239 void Menu::enterNotifyEvent(XCrossingEvent &ce) {
01240 
01241     if (menu.frame != ce.window)
01242         return;
01243 
01244     menu.x_shift = x(), menu.y_shift = y();
01245     if (x() + width() > m_screen_width) {
01246         menu.x_shift = m_screen_width - width() - 2*m_border_width;
01247         shifted = true;
01248     } else if (x() < 0) {
01249         menu.x_shift = 0; //-m_border_width;
01250         shifted = true;
01251     }
01252 
01253     if (y() + height() + 2*m_border_width > m_screen_height) {
01254         menu.y_shift = m_screen_height - height() - 2*m_border_width;
01255         shifted = true;
01256     } else if (y() + (signed) menu.title_h < 0) {
01257         menu.y_shift = 0; // -m_border_width;;
01258         shifted = true;
01259     }
01260 
01261 
01262     if (shifted)
01263         menu.window.move(menu.x_shift, menu.y_shift);
01264     
01265     if (which_sub >= 0 && static_cast<size_t>(which_sub) < menuitems.size()) {
01266         MenuItem *tmp = menuitems[which_sub];
01267         if (tmp->submenu()->isVisible()) {
01268             int sbl = (ce.x / menu.item_w), i = (ce.y / menu.item_h),
01269                 w = (sbl * menu.persub) + i;
01270 
01271             if (w != which_sub && (! tmp->submenu()->isTorn())) {
01272                 tmp->submenu()->internal_hide();
01273 
01274                 drawItem(which_sub, false, true, true);
01275                 which_sub = -1;
01276             }
01277         }
01278     }
01279 }
01280 
01281 void Menu::leaveNotifyEvent(XCrossingEvent &ce) {
01282     if (menu.frame != ce.window)
01283         return;
01284 
01285     if (which_press != -1 && which_sbl != -1 && menuitems.size() > 0) {
01286         int p = (which_sbl * menu.persub) + which_press;
01287 
01288         drawItem(p, (p == which_sub), true, true);
01289 
01290         which_sbl = which_press = -1;
01291     }
01292 
01293     if (shifted) {
01294         //        menu.window.move(menu.x, menu.y);
01295         shifted = false;
01296     }
01297 }
01298 
01299 void Menu::keyPressEvent(XKeyEvent &event) {
01300     KeySym ks;
01301     char keychar[1];
01302     XLookupString(&event, keychar, 1, &ks, 0);
01303     // a modifier key by itself doesn't do anything
01304     if (IsModifierKey(ks)) 
01305         return;
01306     if (event.state) // dont handle modifier with normal key
01307         return;
01308 
01309     switch (ks) {
01310     case XK_Up:
01311         prevItem();
01312         break;
01313     case XK_Down:
01314         nextItem();
01315         break;
01316     case XK_Left: // enter parent if we have one
01317         enterParent(); 
01318         break;
01319     case XK_Right: // enter submenu if we have one
01320         enterSubmenu();
01321         break;
01322     case XK_Escape: // close menu
01323         hide();
01324         break;
01325     case XK_Return:
01326         // send fake button 1 click
01327         if (which_press >= 0 && which_press < static_cast<signed>(menuitems.size())) {
01328             menuitems[which_press]->click(1, event.time);
01329             itemSelected(1, which_press);
01330             m_need_update = true;
01331             update();
01332         }
01333         break;
01334     default:
01335         break;
01336     }
01337 }
01338 
01339 void Menu::reconfigure() {
01340     m_need_update = true; // redraw items
01341 
01342     menu.bevel_w = m_theme.bevelWidth();
01343     m_border_width = m_theme.borderWidth();
01344 
01345     if (menu.bevel_w > 10) // clamp to "normal" size
01346         menu.bevel_w = 10;
01347 
01348     if (m_border_width > 20) // clamp to normal size
01349         m_border_width = 20;
01350     if (m_border_width < 0)
01351         m_border_width = 0;
01352 
01353     menu.window.setBackgroundColor(m_theme.borderColor());
01354     menu.title.setBackgroundColor(m_theme.borderColor());    
01355 
01356     menu.window.setBorderColor(m_theme.borderColor());
01357     menu.title.setBorderColor(m_theme.borderColor());
01358     menu.frame.setBorderColor(m_theme.borderColor());
01359 
01360     menu.window.setBorderWidth(m_border_width);
01361     menu.title.setBorderWidth(m_border_width);
01362     
01363     menu.frame.setAlpha(alpha());
01364     menu.title.setAlpha(alpha());
01365     menu.window.setAlpha(alpha());
01366 
01367     update();
01368 }
01369     
01370 void Menu::renderTransFrame() {
01371     menu.frame.clear();
01372     menu.frame.updateTransparent();
01373 }
01374 
01375 void Menu::openSubmenu() {
01376     if (!isVisible() || which_press < 0 || which_press >= static_cast<signed>(menuitems.size()) ||
01377         which_sbl < 0 || which_sbl >= static_cast<signed>(menuitems.size()))
01378         return;
01379 
01380     int item = which_sbl * menu.persub + which_press;
01381     if (item < 0 || item >= static_cast<signed>(menuitems.size()))
01382         return;
01383 
01384     drawItem(item, true);
01385     if (menuitems[item]->submenu() != 0 && !menuitems[item]->submenu()->isVisible())
01386         drawSubmenu(item);
01387 
01388 }
01389 
01390 void Menu::closeMenu() {
01391     if (isVisible() && !isTorn())
01392         internal_hide();
01393 }
01394 
01395 void Menu::startHide() {
01396     timeval timeout;
01397     timeout.tv_sec = 0;
01398     timeout.tv_usec = theme().delayClose() * 1000; // transformed to usec
01399     m_hide_timer.setTimeout(timeout);
01400     m_hide_timer.start(); 
01401 }
01402 
01403 void Menu::stopHide() {
01404     m_hide_timer.stop();
01405 }
01406 
01407 }; // end namespace FbTk

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA