FIFE  2008.0
console.cpp
00001 /***************************************************************************
00002  *   Copyright (C) 2005-2008 by the FIFE team                              *
00003  *   http://www.fifengine.de                                               *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <cassert>
00024 
00025 // 3rd party library includes
00026 #include <boost/bind.hpp>
00027 #include <boost/lexical_cast.hpp>
00028 #include <boost/regex.hpp>
00029 #include <boost/tokenizer.hpp>
00030 
00031 // FIFE includes
00032 // These includes are split up in two parts, separated by one empty line
00033 // First block: files included from the FIFE root src directory
00034 // Second block: files included from the same folder
00035 #include "video/renderbackend.h"
00036 #include "util/time/timemanager.h"
00037 #include "util/log/logger.h"
00038 #include "util/base/exception.h"
00039 #include "gui/guimanager.h"
00040 #include "gui/base/gui_font.h"
00041 #include "gui/widgets/utf8textbox.h"
00042 
00043 #include "commandline.h"
00044 #include "console.h"
00045 
00046 namespace FIFE {
00047     const unsigned  Console::m_maxOutputRows = 50;
00048     static Logger _log(LM_CONSOLE);
00049 
00050     Console::Console()
00051         : gcn::Container(),
00052         m_consoleexec(0),
00053         m_input(new CommandLine()),
00054         m_output(new gcn::UTF8TextBox()),
00055         m_outputscrollarea(new gcn::ScrollArea(m_output)),
00056         m_status(new gcn::Label()),
00057         m_toolsbutton(new gcn::Button("Tools"))
00058         {
00059         reLayout();
00060 
00061         add(m_outputscrollarea);
00062         add(m_input);
00063         add(m_status);
00064         add(m_toolsbutton);
00065 
00066         setOpaque(true);
00067 
00068         m_input->setCallback( std::bind1st( std::mem_fun(&Console::execute), this) );
00069         m_prompt = "-- ";
00070 
00071         m_isAttached = false;
00072 
00073         m_fpsTimer.setInterval(500);
00074         m_fpsTimer.setCallback( boost::bind(&Console::updateCaption, this) );
00075 
00076         m_hiding = true;
00077 
00078         m_animationTimer.setInterval(20);
00079         m_animationTimer.setCallback( boost::bind(&Console::updateAnimation, this) );
00080 
00081         m_toolsbutton->addActionListener(this);
00082         m_toolsbutton->setFocusable(false);
00083         m_input->addFocusListener(this);
00084 
00085         GuiFont* font = GUIManager::instance()->createFont();
00086         font->setColor(255,255,255);
00087         setIOFont(font);
00088     }
00089 
00090     void Console::reLayout() {
00091         Image* screen = RenderBackend::instance()->getScreenImage();
00092         assert(screen);
00093 
00094         int w, h, b, input_h, bbar_h, button_w;
00095         w = screen->getWidth() * 4/5;
00096         h = screen->getHeight() * 4/5;
00097         b = 0;
00098         input_h = getFont()->getHeight();
00099         bbar_h = input_h;
00100         button_w = 80;
00101 
00102         gcn::Color black(0x00,0,0,0xff);
00103         gcn::Color white(0xff,0xff,0xff,0xff);
00104         gcn::Color dark(50,60,50,0xff);
00105 
00106         setSize(w, h);
00107         setPosition((screen->getWidth() - w) / 2,-h);
00108         setFrameSize(0);
00109 
00110         setForegroundColor(white);
00111         setBackgroundColor(black);
00112         setBaseColor(dark);
00113 
00114         setSize(w, h);
00115 
00116         m_outputscrollarea->setSize(w - 2*b, h - input_h - 3*b - bbar_h);
00117         m_outputscrollarea->setPosition(b,0);
00118 
00119         m_input->setPosition(b, h - input_h - b - bbar_h);
00120         m_input->setSize(w - 2*b, input_h);
00121 
00122         m_status->setPosition(b, h - b - bbar_h);
00123         m_status->setSize(w - 2*b, bbar_h);
00124 
00125         m_toolsbutton->setPosition(w - button_w, h - b - bbar_h);
00126         m_toolsbutton->setSize(button_w, bbar_h);
00127 
00128         m_output->setBackgroundColor(black);
00129         m_output->setFocusable(false);
00130 
00131         m_outputscrollarea->setBackgroundColor(black);
00132         m_outputscrollarea->setBaseColor(dark);
00133 
00134         m_input->setForegroundColor(white);
00135         m_input->setBackgroundColor(black);
00136 
00137         m_status->setForegroundColor(white);
00138         m_status->setBackgroundColor(black);
00139 
00140         m_toolsbutton->setForegroundColor(white);
00141         m_toolsbutton->setBackgroundColor(black);
00142         m_toolsbutton->setBaseColor(dark);
00143 
00144         m_hiddenPos = -h;
00145         m_animationDelta = h/6;
00146     }
00147 
00148     Console::~Console() {
00149         doHide();
00150 
00151         remove(m_input);
00152         remove(m_outputscrollarea);
00153         remove(m_status);
00154 
00155         delete m_output;
00156         delete m_input;
00157         delete m_outputscrollarea;
00158         delete m_status;
00159         delete m_toolsbutton;
00160     }
00161 
00162     void Console::updateCaption() {
00163         std::string caption = "FIFE Console - FPS: ";
00164         float fps = 1e3/double(TimeManager::instance()->getAverageFrameTime());
00165         caption += boost::lexical_cast<std::string>(fps);
00166         m_status->setCaption( caption );
00167     }
00168 
00169     void Console::updateAnimation() {
00170         if (m_hiding){
00171         setPosition(getX(), getY() - m_animationDelta);
00172         if (getY() <= m_hiddenPos){
00173             doHide();
00174             m_animationTimer.stop();
00175         }
00176         }else{
00177         setPosition(getX(), getY() + m_animationDelta);
00178         if (getY() >= 0){
00179             setPosition(getX(), 0);
00180             m_animationTimer.stop();
00181         }
00182     }
00183     }
00184 
00185     void Console::clear() {
00186         m_output->setText("");
00187     }
00188 
00189     void Console::doShow() {
00190         if (m_isAttached)
00191             return;
00192         m_isAttached = true;
00193         GUIManager::instance()->add(this);
00194         GUIManager::instance()->getTopContainer()->moveToTop(this);
00195         // Assure the input field is focused when shown.
00196         m_input->requestFocus();
00197 
00198         m_fpsTimer.start();
00199     }
00200 
00201     void Console::doHide() {
00202         if (!m_isAttached)
00203             return;
00204         m_isAttached = false;
00205         GUIManager::instance()->remove(this);
00206         m_fpsTimer.stop();
00207     }
00208 
00209     void Console::show() {
00210         if(m_hiding) {
00211             m_hiding = false;
00212             doShow();
00213             m_animationTimer.start();
00214         }
00215     }
00216 
00217     void Console::hide() {
00218         if(!m_hiding) {
00219             m_hiding = true;
00220             m_animationTimer.start();
00221         }
00222     }
00223 
00224     void Console::toggleShowHide() {
00225         m_hiding = !m_hiding;
00226         if(!m_hiding)
00227             doShow();
00228         m_animationTimer.start();
00229     }
00230 
00231     void Console::execute(std::string cmd) {
00232         FL_DBG(_log, LMsg("in execute with command ") << cmd);
00233         if (cmd.empty())
00234             return;
00235 
00236         // copy input to output
00237         println(m_prompt + cmd);
00238 
00239         // run the command
00240         try {
00241             if (m_consoleexec) {
00242                 std::string resp = m_consoleexec->onConsoleCommand(cmd);
00243                 println(resp);
00244             } else {
00245                 FL_WARN(_log, LMsg("ConsoleExecuter not bind, but command received: ") << cmd.c_str());
00246             }
00247         }
00248         catch (const FIFE::Exception & e) {
00249             FL_WARN(_log, LMsg("Console caught exception: ") << e.what());
00250             println(e.what());
00251         }
00252     }
00253 
00254     void Console::println(const std::string & s) {
00255         assert(m_output);
00256 
00257         // Add the text in rows
00258         boost::char_separator<char> separator("\n");
00259         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00260         tokenizer tokens(s,separator);
00261         for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i) {
00262             m_output->addRow(*i);
00263         }
00264 
00265         // Assure the maximum number of rows
00266         if( m_output->getNumberOfRows() > m_maxOutputRows ) {
00267             unsigned rows = m_output->getNumberOfRows();
00268             int delta_rows = rows - m_maxOutputRows;
00269             std::vector<std::string> rows_text;
00270             for(size_t i=delta_rows; i != rows; ++i) {
00271                 rows_text.push_back(m_output->getTextRow(i));
00272             }
00273             m_output->setText("");
00274             for(size_t i=0; i != rows_text.size(); ++i) {
00275                 m_output->addRow(rows_text[i]);
00276             }
00277         }
00278 
00279         // Assure the new text is visible
00280         gcn::Rectangle rect(0,m_output->getHeight(),0,0);
00281         m_outputscrollarea->showWidgetPart(m_output,rect);
00282     }
00283 
00284     void Console::action(const gcn::ActionEvent & event) {
00285         if (m_consoleexec) {
00286             m_consoleexec->onToolsClick();
00287         } else {
00288             FL_WARN(_log, "ConsoleExecuter not bind, but tools button clicked");
00289         }
00290     }
00291 
00292     void Console::setConsoleExecuter(ConsoleExecuter* const consoleexec) {
00293         m_consoleexec = consoleexec;
00294     }
00295 
00296     void Console::removeConsoleExecuter() {
00297         m_consoleexec = NULL;
00298     }
00299 
00300     void Console::setIOFont(GuiFont* font) {
00301         m_input->setFont(font);
00302         m_output->setFont(font);
00303     }
00304 
00305     void Console::focusLost(const gcn::Event& ) {
00306         hide();
00307     }
00308 }
00309 /* vim: set noexpandtab: set shiftwidth=2: set tabstop=2: */