src/menu.cpp

Go to the documentation of this file.
00001 // Copyright (c) 2003 - 2004 Anselm R. Garbe <anselmg at t-online.de>
00002 // See ../LICENSE.txt for license details.
00003 //
00004 // $Id: menu.cpp 2 2007-05-16 10:38:27Z eg $
00005 
00006 #include "menu.h"
00007 
00008 #include <sstream>
00009 
00010 #include "action.h"
00011 #include "clientbar.h"
00012 #include "cursors.h"
00013 #include "draw.h"
00014 #include "font.h"
00015 #include "kernel.h"
00016 #include "label.h"
00017 #include "logger.h"
00018 #include "monitor.h"
00019 #include "theme.h"
00020 #include "util.h"
00021 #include "workspace.h"
00022 #include "xcore.h"
00023 #include "xfont.h"
00024 
00026 
00027 Item::Item(string name, void *data, Type type) {
00028     data_ = data;
00029     type_ = type;
00030 
00031     switch (type_) {
00032     case WORKSPACE:
00033         {
00034             Workspace *workspace = (Workspace *)data;
00035             Monitor *monitor = workspace->attached();
00036             if (workspace->clients()->size()
00037                 || monitor->detachedClients()->size()
00038                 || monitor->stickyClients()->size())
00039             {
00040                 addItem(new Item(name, 0, ROOTITEM));
00041                 addItem(new Item("", 0, SEPARATOR));
00042                 name_ = name + "  >>";
00043             }
00044             else {
00045                 name_ = name;
00046             }
00047             if (workspace == monitor->focused()) {
00048                 name_ = "* " + name_;
00049             }
00050             else {
00051                 name_ = "  " + name_;
00052             }
00053         }
00054         break;
00055     case DCLIENT:
00056         name_ = "+ " + name;
00057         break;
00058     case ROOTITEM:
00059         name_ = "<<  " + name;
00060         break;
00061     case SEPARATOR:
00062         name_ = "  -----------------------";
00063         break;
00064     default:
00065         name_ = "  " + name;
00066         break;
00067     }
00068 }
00069 
00070 Item::~Item() {
00071     // clean up subitems
00072     while (items_.size()) {
00073         Item *item = items_.front();
00074         items_.erase(items_.begin());
00075         delete item;
00076     }
00077 }
00078 
00079 LItem *Item::items() {
00080     return &items_;
00081 }
00082 
00083 void Item::addItem(Item *item) {
00084     item->setParent(this);
00085     items_.push_back(item);
00086 }
00087 
00088 void Item::removeItem(Item *item) {
00089     item->setParent(0);
00090     items_.remove(item);
00091 }
00092 
00093 Item::Type Item::type() const {
00094     return type_;
00095 }
00096 
00097 string Item::name() const {
00098     return name_;
00099 }
00100 
00101 unsigned int Item::size() {
00102     return items_.size();
00103 }
00104 
00105 Item *Item::parent() const {
00106     return parent_;
00107 }
00108 
00109 void Item::setParent(Item *parent) {
00110     parent_ = parent;
00111 }
00112 
00113 void *Item::data() const {
00114     return data_;
00115 }
00116 
00118 
00119 Menu::Menu(Monitor *monitor)
00120     : Widget(monitor, new Rectangle(0, 0, 1, 1))
00121 {
00122     theme_ = this->monitor()->theme();
00123     root_ = subRoot_ = selected_ = 0;
00124 
00125     label_ = new Label(this->monitor(), window(), Label::LEFT, gc());
00126     label_->setX(1);
00127     label_->setY(1);
00128     label_->setWidth(1);
00129     label_->setHeight(this->monitor()->font()->height() + 2);
00130 
00131     initActions();
00132 }
00133 
00134 Menu::~Menu() {
00135 
00136 }
00137 
00138 void Menu::initActions() {
00139 
00140     MBindings *actionBindings = KERNEL->actionBindings();
00141     string actions = Util::get(KERNEL->commonSettings(), "menu.actions");
00142 
00143     string actionName = "";
00144     bool proceed = actions.size();
00145     for (string::iterator it = actions.begin(); proceed; it++) {
00146 
00147         if ((*it != ',') && (it != actions.end())) {
00148             actionName += *it;
00149         }
00150         else {
00151             Action *action = Util::get(actionBindings, actionName);
00152             if (action) {
00153                 actions_.push_back(action);
00154             }
00155             else {
00156                 LOGWARN("unknown action '" + actionName + "' in menu setup");
00157             }
00158             actionName = "";
00159         }
00160         proceed = it != actions.end();
00161     }
00162 
00163 }
00164 
00165 void Menu::updateItemTree() {
00166 
00167     if (root_) {
00168         delete root_;
00169     }
00170     root_ = new Item("", 0, Item::ROOT);
00171     subRoot_ = root_;
00172 
00173     // now build up the item tree
00174     for (LAction::iterator it = actions_.begin(); it != actions_.end(); it++) {
00175         Action *action = *it;
00176         if (action->isValid()) {
00177             root_->addItem(new Item(action->id(), action, Item::ACTION));
00178         }
00179     }
00180     if (root_->items()->size()) {
00181         root_->addItem(new Item("", 0, Item::SEPARATOR));
00182     }
00183 
00184     // now add all workspaces
00185     for (LWorkspace::iterator it = monitor()->begin();
00186          it != monitor()->end(); it++)
00187     {
00188         Workspace *workspace = *it;
00189         Item *wsItem = new Item(workspace->name(), workspace, Item::WORKSPACE);
00190         LClient *clients = workspace->clients();
00191         for (LClient::iterator it = clients->begin(); it != clients->end(); it++) {
00192             Client *client = *it;
00193             if (client->mode() != Client::STICKY) {
00194                 wsItem->addItem(new Item(client->name(), client, Item::CLIENT));
00195             }
00196         }
00197         CClient *stickyClients = monitor()->stickyClients();
00198         for (LClient::iterator it = stickyClients->begin();
00199                 it != stickyClients->end(); it++)
00200         {
00201             Client *client = *it;
00202             wsItem->addItem(new Item(client->name(), client, Item::CLIENT));
00203         }
00204         CClient *detachedClients = monitor()->detachedClients();
00205         if (detachedClients->size()) {
00206             if (workspace->clients()->size() || clients->size()) {
00207                 wsItem->addItem(new Item("", 0, Item::SEPARATOR));
00208             }
00209             for (LClient::iterator it = detachedClients->begin();
00210                     it != detachedClients->end(); it++)
00211             {
00212                 Client *client = *it;
00213                 wsItem->addItem(new Item(client->name(), client, Item::DCLIENT));
00214             }
00215         }
00216         root_->addItem(wsItem);
00217     }
00218 }
00219 
00220 void Menu::show() {
00221     KERNEL->setMenuMode(true);
00222     isVisible_ = true;
00223     XCORE->showRaised(window());
00224     updateItemTree();
00225     manage();
00226 }
00227 
00228 void Menu::hide() {
00229     KERNEL->setMenuMode(false);
00230     isVisible_ = false;
00231     XCORE->hide(window());
00232 }
00233 
00234 void Menu::illuminate() {
00235 
00236     Rectangle rect(*this);
00237     rect.setX(0);
00238     rect.setY(0);
00239     LOGDEBUG("drawing solid background");
00240     // draw solid background
00241     XCORE->raise(window());
00242     XCORE->setForeground(gc(), theme_->BAR_BACKGROUND);
00243     XCORE->fillRectangle(window(), gc(), &rect);
00244     LItem *items = subRoot_->items();
00245 
00246     unsigned int offsetY = 1;
00247     unsigned int i = 0;
00248     for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00249         Item *item = *it;
00250         label_->setY(offsetY + i * label_->height());
00251         label_->setText(item->name());
00252         if ((item == selected_) && (item->type() != Item::SEPARATOR)) {
00253             label_->update(theme_->LABEL_BACKGROUND_FOCUSSED,
00254                            theme_->LABEL_TEXT_FOCUSSED,
00255                            theme_->LABEL_SHINE_FOCUSSED,
00256                            theme_->LABEL_SHADOW_FOCUSSED,
00257                            true, true);
00258         }
00259         else {
00260             label_->update(theme_->LABEL_BACKGROUND_NORMAL,
00261                            theme_->LABEL_TEXT_NORMAL,
00262                            theme_->LABEL_SHINE_NORMAL,
00263                            theme_->LABEL_SHADOW_NORMAL);
00264         }
00265         i++;
00266     }
00267 
00268     Draw::drawRectBorder(window(), gc(), &rect,
00269             theme_->BAR_SHINE, theme_->BAR_SHADOW);
00270 }
00271 
00272 void Menu::manage() {
00273 
00274     if (!isVisible()) {
00275         return;
00276     }
00277 
00278     unsigned int maxWidth = 0;
00279     LItem *items = subRoot_->items();
00280     for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00281         Item *item = *it;
00282         label_->setText(item->name());
00283         if (label_->textWidth() > maxWidth) {
00284             maxWidth = label_->textWidth() + 10;
00285         }
00286     }
00287     label_->setWidth(maxWidth);
00288     setWidth(maxWidth + 2);
00289     setHeight(items->size() * label_->height() + 2);
00290 
00291     if (monitor()->clientBar()->y()) {
00292         setY(monitor()->height() - monitor()->clientBar()->height() - height());
00293     }
00294     else {
00295         setY(monitor()->clientBar()->height());
00296     }
00297 
00298     // time to illuminate menu
00299     resize();
00300     illuminate();
00301 }
00302 
00303 void Menu::handleButtonPress(XButtonEvent *event) {
00304     XCORE->raise(window());
00305     if (selected_) {
00306         switch (selected_->type()) {
00307         case Item::WORKSPACE:
00308             {
00309                 Workspace *workspace = (Workspace *)selected_->data();
00310                 if (event->button == Button1) {
00311                     if (selected_->items()->size()) {
00312                         subRoot_ = selected_;
00313                         manage();
00314                     }
00315                     else { // focus workspace
00316                         monitor()->focus(workspace);
00317                         escape();
00318                     }
00319                 }
00320                 else if (event->button == Button3) {
00321                     monitor()->focus(workspace);
00322                     updateItemTree();
00323                     manage();
00324                 }
00325             }
00326             break;
00327         case Item::ROOTITEM:
00328             subRoot_ = subRoot_->parent();
00329             manage();
00330             break;
00331         case Item::ACTION:
00332             {
00333                 Action *action = (Action *)selected_->data();
00334                 if (action->isValid()) {
00335                     action->perform();
00336                     escape();
00337                 }
00338             }
00339             break;
00340         case Item::CLIENT:
00341             {
00342                 Workspace *workspace = (Workspace *)subRoot_->data();
00343                 Client *client = (Client *)selected_->data();
00344                 if (event->button == Button3) {
00345                     monitor()->detachClient(client);
00346                     if (monitor()->focused() != workspace) {
00347                         monitor()->attachLastClient();
00348                     }
00349                 }
00350                 else {
00351                     monitor()->focus(workspace);
00352                     workspace->focus(client);
00353                     if (event->button == Button2) {
00354                         XCORE->warpPointer(client->clientWindow(),
00355                                            client->width() / 2,
00356                                            client->height() / 2);
00357                     }
00358                 }
00359                 escape();
00360             }
00361             break;
00362         case Item::DCLIENT:
00363             {
00364                 Client *client = (Client *)selected_->data();
00365                 monitor()->attachDetachedClient((Workspace *)subRoot_->data(),
00366                                                client);
00367                 if (event->button == Button2) {
00368                     XCORE->warpPointer(client->clientWindow(),
00369                                        client->x() + client->width() / 2,
00370                                        client->y() + client->height() / 2);
00371                 }
00372                 escape();
00373             }
00374             break;
00375         default:
00376             break;
00377         }
00378     }
00379 }
00380 
00381 void Menu::escape() {
00382     monitor()->clientBar()->toggleMenuMode();
00383 }
00384 
00385 void Menu::handleMotionNotify(XMotionEvent *event) {
00386 
00387     unsigned int selItem = event->y / label_->height();
00388     ostringstream oss;
00389     oss << "eventY=" << event->y << " selItem=" << selItem;
00390     LOGDEBUG(oss.str());
00391 
00392     unsigned int i = 0;
00393     LItem *items = subRoot_->items();
00394     for (LItem::iterator it = items->begin(); it != items->end(); it++) {
00395         Item *item = *it;
00396         if (selItem == i) {
00397             if (item == selected_) {
00398                 LOGDEBUG("no redraw");
00399                 return;
00400             }
00401             selected_ = item;
00402             illuminate();
00403             return;
00404         }
00405         i++;
00406     }
00407     selected_ = 0;
00408 }

Generated on Thu May 24 15:19:32 2007 for ncwm by  doxygen 1.5.1