src/inputbar.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: inputbar.cpp 2 2007-05-16 10:38:27Z eg $
00005 
00006 #include "inputbar.h"
00007 
00008 extern "C" {
00009 #include <assert.h>
00010 #include <stdlib.h>
00011 }
00012 
00013 #include "action.h"
00014 #include "actions.h"
00015 #include "binder.h"
00016 #include "kernel.h"
00017 #include "label.h"
00018 #include "logger.h"
00019 #include "monitor.h"
00020 #include "prompt.h"
00021 #include "theme.h"
00022 #include "workspace.h"
00023 #include "xcore.h"
00024 
00025 InputBar::InputBar(Monitor *monitor, Rectangle *rect)
00026     : Bar(monitor, rect)
00027 {
00028 
00029     LOGDEBUG("initializing input");
00030     currAction_ = 0;
00031     prompt_ = 0;
00032     promptCounter_ = 0;
00033     isArgument_ = false;
00034     entryBegin_ = entryEnd_ = 0;
00035     partitionBegin_ = selected_ = entryBegin_;
00036     args_ = "";
00037     LOGDEBUG("creating input");
00038 }
00039 
00040 InputBar::~InputBar() {
00041 }
00042 
00043 void InputBar::selectPrevEntry() {
00044 
00045     if (entryBegin_ == entryEnd_) {
00046         // nothing to select, empty list
00047         return;
00048     }
00049 
00050     if (selected_ != partitionBegin_) {
00051         selected_--;
00052     }
00053     else {
00054 
00055         if (partitionBegin_ != entryBegin_) {
00056 
00057             selected_ = --partitionBegin_;
00058             partitionBegin_ = prevPartitions_.top();
00059             prevPartitions_.pop();
00060         }
00061         else {
00062             clearPrevPartitionsStack();
00063         }
00064     }
00065 }
00066 
00067 void InputBar::selectNextEntry() {
00068 
00069     if (entryBegin_ == entryEnd_) {
00070         // nothing to select, empty list
00071         return;
00072     }
00073 
00074     Sstring::iterator tmp = selected_;
00075     selected_++;
00076 
00077     if (selected_ == entryEnd_) {
00078         selected_ = partitionBegin_ = entryBegin_;
00079         clearPrevPartitionsStack();
00080         return;
00081     }
00082 
00083     if (tmp == partitionEnd_) {
00084         prevPartitions_.push(partitionBegin_);
00085         partitionBegin_ = selected_;
00086     }
00087 }
00088 
00089 void InputBar::illuminate() {
00090 
00091     if (!isVisible()) {
00092         return;
00093     }
00094 
00095     drawBorder();
00096     LOGDEBUG("input update");
00097 
00098     // draw background
00099     label_->setAlignment(Label::CENTER);
00100     label_->setText("");
00101     label_->setX(1);
00102     label_->setWidth(width() - 2);
00103     label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00104                    theme_->BAR_SHINE, theme_->BAR_SHADOW);
00105 
00106     // draw prompt
00107     label_->setText(prompt_ ? prompt_->prompt() : "");
00108     label_->adjustWidth();
00109     label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00110                    theme_->BAR_SHINE, theme_->BAR_SHADOW);
00111     label_->setX(label_->x() + label_->width());
00112 
00113     // draw text
00114     label_->setText(text_);
00115     label_->adjustWidth();
00116     label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00117                    theme_->BAR_SHINE, theme_->BAR_SHADOW);
00118     label_->setX(label_->x() + label_->width());
00119 
00120     if (partitionBegin_ != entryBegin_) {
00121         label_->setText("<<");
00122         label_->adjustWidth();
00123         label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00124                        theme_->BAR_SHINE, theme_->BAR_SHADOW);
00125         label_->setX(label_->x() + label_->width());
00126     }
00127 
00128     label_->setText(">>");
00129     unsigned int nextWidth = label_->adjustWidth();
00130 
00131     for (Sstring::iterator it = partitionBegin_; it != entryEnd_; it++)
00132     {
00133         string currStr = *it;
00134         label_->setText(currStr);
00135         label_->adjustWidth();
00136 
00137         // draw entry
00138         if (label_->x() + label_->width() < (width() - nextWidth)) {
00139 
00140             if (selected_ != it) {
00141                 label_->update(theme_->LABEL_BACKGROUND_NORMAL,
00142                                theme_->LABEL_TEXT_NORMAL,
00143                                theme_->LABEL_SHINE_NORMAL,
00144                                theme_->LABEL_SHADOW_NORMAL);
00145             }
00146             else {
00147                 label_->update(theme_->LABEL_BACKGROUND_FOCUSSED,
00148                                theme_->LABEL_TEXT_FOCUSSED,
00149                                theme_->LABEL_SHINE_FOCUSSED,
00150                                theme_->LABEL_SHADOW_FOCUSSED,
00151                                true, true);
00152             }
00153         }
00154         else {
00155             partitionEnd_ = --it;
00156             label_->setText(">>");
00157             label_->adjustWidth();
00158             label_->update(theme_->BAR_BACKGROUND, theme_->BAR_TEXT,
00159                            theme_->BAR_SHINE, theme_->BAR_SHADOW);
00160             break;
00161         }
00162         label_->setX(label_->x() + label_->width());
00163     }
00164 }
00165 
00166 string InputBar::text(bool onExecEnter) {
00167 
00168     if ((selected_ == entryBegin_) && (entryBegin_ == entryEnd_)) {
00169         return text_;
00170     }
00171     else {
00172         // If an input begins with '/' character we use also the prefix path
00173         if (onExecEnter && (text_.length() > 0) && (text_[0] == '/')) {
00174             text_ = text_.substr(0, text_.find_last_of('/') + 1);
00175             return text_ + *selected_;
00176         }
00177         return *selected_;
00178     }
00179 }
00180 
00181 void InputBar::clearPrevPartitionsStack() {
00182     while (!prevPartitions_.empty()) {
00183         prevPartitions_.pop();
00184     }
00185 }
00186 
00187 void InputBar::removeChar() {
00188 
00189     if (!isVisible() || !prompt_) {
00190         return;
00191     }
00192 
00193     int textLength = text_.length();
00194     if (textLength < 1) {
00195         return;
00196     }
00197 
00198     if (prompt_->toQuery() && names_.size()>0) {
00199         unsigned int numNames = names_.size();
00200         for (; (numNames == names_.size()) && (textLength >= 0);
00201                 textLength--)
00202         {
00203 #ifdef POSIX_REGEX
00204                 string s = Binder::instance()->popRegexPattern();
00205                 LOGDEBUG("popping from STACK: " + s);
00206                 queryText(s);
00207                 textLength=s.length();
00208 #else
00209             queryText(text_.substr(0, textLength));
00210 #endif
00211         }
00212     }
00213     else {
00214         queryText(text_.substr(0, textLength - 1));
00215     }
00216     illuminate();
00217 }
00218 
00219 void InputBar::queryText(string text) {
00220 
00221     if (!isVisible() || !prompt_) {
00222         return;
00223     }
00224 
00225     QueryNamesForPrefix toQuery = prompt_->toQuery();
00226     names_.clear();
00227 
00228     if (toQuery) {
00229         text_ = ((*Binder::instance()).*toQuery)(text, &names_);
00230         entryBegin_ = names_.begin();
00231         entryEnd_ = names_.end();;
00232         selected_ = partitionBegin_ = entryBegin_;
00233         clearPrevPartitionsStack();
00234     }
00235     else {
00236         entryBegin_ = entryEnd_ = 0;
00237         partitionBegin_ = selected_ = entryBegin_;
00238         text_ = text;
00239     }
00240 }
00241 
00242 void InputBar::handleInput(XKeyEvent *event) {
00243 
00244     static const char *home = getenv("HOME");
00245     static bool isNext = false;
00246     char buffer[32];
00247     int count;
00248 
00249     if (!isVisible()) {
00250         return;
00251     }
00252     static KeySym sym;
00253     // patch contributed by Marcin Pawlik
00254     sym = XCORE->lookupNextKeySym(event, &count, buffer);
00255     if (IsFunctionKey(sym) || IsKeypadKey(sym) ||
00256             IsMiscFunctionKey(sym) || IsPFKey(sym) ||
00257             IsPrivateKeypadKey(sym))
00258     {
00259         return; // ignore
00260     }
00261 
00262     bool reset = false;
00263     if (event->state & ControlMask) {
00264         switch (sym) {
00265         case XK_H:
00266         case XK_h:
00267             sym = XK_BackSpace;
00268             break;
00269         case XK_J:
00270         case XK_j:
00271             sym = XK_Return;
00272             break;
00273         case XK_G:
00274         case XK_g:
00275             sym = XK_Escape;
00276             break;
00277         case XK_U:
00278         case XK_u:
00279             reset = true;
00280             break;
00281         }
00282     }
00283 
00284     switch (sym) {
00285     case XK_BackSpace:
00286         removeChar();
00287         break;
00288     case XK_Right:
00289         selectNextEntry();
00290         break;
00291     case XK_Left:
00292         selectPrevEntry();
00293         break;
00294     case XK_Return:
00295         handlePressedReturn();
00296         break;
00297     case XK_Escape:
00298         escape();
00299         break;
00300     case XK_Num_Lock:
00301         break;
00302     default:
00303         if (reset) {
00304             text_ = "";
00305             queryText(text_);
00306         }
00307         else if ((count == 1) && !iscntrl(buffer[0])) {
00308             buffer[count] = 0;
00309             string text = "";
00310             if (home && (buffer[0] == '~')) {
00311                 text = text_ + home;
00312             }
00313             else {
00314                 text = text_ + buffer;
00315             }
00316             queryText(text);
00317             text_ = text;
00318         }
00319         else if (sym == XK_Tab) {
00320             string text = text_;
00321             if (!isNext) {
00322                 queryText(text_);
00323             }
00324             isNext = (text == text_);
00325             if (isNext) {
00326                 selectNextEntry();
00327             }
00328         }
00329 #ifdef POSIX_REGEX
00330         if (text_=="") {Binder::instance()->clearRegexPattern();}else{
00331         if (!names_.empty()) Binder::instance()->pushRegexPattern(text_);}
00332         
00333 #endif
00334         break;
00335     }
00336     if (sym != XK_Tab) {
00337         isNext = false;
00338     }
00339     illuminate();
00340 }
00341 
00342 void InputBar::escape() {
00343 
00344     promptCounter_ = 0;
00345     args_ = "";
00346     prompt_ = 0;
00347     currAction_ = 0;
00348 #ifdef POSIX_REGEX
00349     Binder::instance()->clearRegexPattern();
00350 #endif
00351     XCORE->ungrabKeyboard();
00352     hide();
00353 }
00354 
00355 void InputBar::handlePressedReturn() {
00356 
00357     string actionKey;
00358     bool isDirectInvocation = false;
00359 
00360     LOGDEBUG("fetching selection");
00361     actionKey = text();
00362     unsigned int pos = actionKey.find_first_of('+');
00363     if (!isArgument_ && (pos != string::npos)) {
00364         args_ = actionKey.substr(pos + 1);
00365         actionKey = actionKey.substr(0, pos);
00366         isDirectInvocation = true;
00367     }
00368     LOGDEBUG("selection fetched");
00369     if (isArgument_ || (actionKey != "") || isDirectInvocation) {
00370 
00371         if (!isArgument_ || isDirectInvocation)
00372         { // fetch action
00373             LOGDEBUG("fetching action: " + actionKey );
00374             currAction_ = Util::get(KERNEL->actionBindings(), actionKey);
00375         }
00376 
00377         if (currAction_) {
00378 
00379             if (!isArgument_ &&
00380                 (currAction_->promptsCount() > 0) && !isDirectInvocation)
00381             {
00382                 // set prompt of first argument
00383                 prompt_ = currAction_->prompt(0);
00384                 isArgument_ = true;
00385                 queryText("");
00386             }
00387             else if (isArgument_) {
00388 
00389                 // fetch args
00390                 if (args_.length() > 0) {
00391                     args_ += '+';
00392                 }
00393                 args_ += text((currAction_->getToPerform() == &Actions::execute) ||
00394                               (currAction_->getToPerform() == &Actions::executeTerm));
00395 
00396                 promptCounter_++;
00397                 if (promptCounter_ < currAction_->promptsCount()) {
00398                     prompt_ = currAction_->prompt(promptCounter_);
00399                 }
00400                 queryText(""); // keyboard is already grabbed
00401             }
00402             illuminate();
00403 
00404             if ((promptCounter_ == currAction_->promptsCount()) ||
00405                     isDirectInvocation)
00406             {
00407                 LOGDEBUG("going to perform action");
00408                 if (isArgument_ || isDirectInvocation) {
00409                     LOGDEBUG("got args: " + args_);
00410                     currAction_->setArgument((char *)args_.c_str());
00411                 }
00412                 // otherwise default invocation
00413                 currAction_->perform();
00414                 escape();
00415             }
00416             else {
00417                 return;
00418             }
00419         }
00420     }
00421 }
00422 
00423 void InputBar::runKey(Prompt *prompt) {
00424     if (!isVisible()) {
00425         show();
00426     }
00427     XCORE->grabKeyboard(window());
00428     currAction_ = 0;
00429     prompt_ = prompt;
00430     isArgument_ = false;
00431     queryText("");
00432     illuminate();
00433 }
00434 
00435 void InputBar::runArgument(Action *action) {
00436     if (!action->isValid()) {
00437         return;
00438     }
00439     if (!isVisible()) {
00440         show();
00441     }
00442     XCORE->grabKeyboard(window());
00443     currAction_ = action;
00444     // set prompt of first argument
00445     prompt_ = currAction_->prompt(0);
00446     isArgument_ = true;
00447     queryText("");
00448     illuminate();
00449 }
00450 
00451 void InputBar::handleMotionNotify(XMotionEvent *event) {
00452     // nothing todo
00453 }
00454 
00455 void InputBar::handleButtonPress(XButtonEvent *event) {
00456     escape();
00457 }
00458 
00459 void InputBar::handleButtonRelease(XButtonEvent *event) {
00460     // nothing todo
00461 }
00462 
00463 bool InputBar::isArgument() const {
00464     return isArgument_;
00465 }

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