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/guichan/guichanmanager.h"
00040 #include "gui/guichan/base/gui_font.h"
00041 #include "gui/guichan/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 = GUIChanManager::instance()->createFont();
00086         font->setColor(255,255,255);
00087         setIOFont(font);
00088     }
00089 
00090     void Console::reLayout() {
00091         int32_t w, h, b, input_h, bbar_h, button_w;
00092         w = RenderBackend::instance()->getScreenWidth() * 4/5;
00093         h = RenderBackend::instance()->getScreenHeight() * 4/5;
00094         b = 0;
00095         input_h = getFont()->getHeight();
00096         bbar_h = input_h;
00097         button_w = 80;
00098 
00099         gcn::Color black(0x00,0,0,0xff);
00100         gcn::Color white(0xff,0xff,0xff,0xff);
00101         gcn::Color dark(50,60,50,0xff);
00102 
00103         setSize(w, h);
00104         setPosition((RenderBackend::instance()->getScreenWidth() - w) / 2,-h);
00105         setFrameSize(0);
00106 
00107         setForegroundColor(white);
00108         setBackgroundColor(black);
00109         setBaseColor(dark);
00110 
00111         setSize(w, h);
00112 
00113         m_outputscrollarea->setSize(w - 2*b, h - input_h - 3*b - bbar_h);
00114         m_outputscrollarea->setPosition(b,0);
00115 
00116         m_input->setPosition(b, h - input_h - b - bbar_h);
00117         m_input->setSize(w - 2*b, input_h);
00118 
00119         m_status->setPosition(b, h - b - bbar_h);
00120         m_status->setSize(w - 2*b, bbar_h);
00121 
00122         m_toolsbutton->setPosition(w - button_w, h - b - bbar_h);
00123         m_toolsbutton->setSize(button_w, bbar_h);
00124 
00125         m_output->setBackgroundColor(black);
00126         m_output->setFocusable(false);
00127 
00128         m_outputscrollarea->setBackgroundColor(black);
00129         m_outputscrollarea->setBaseColor(dark);
00130 
00131         m_input->setForegroundColor(white);
00132         m_input->setBackgroundColor(black);
00133 
00134         m_status->setForegroundColor(white);
00135         m_status->setBackgroundColor(black);
00136 
00137         m_toolsbutton->setForegroundColor(white);
00138         m_toolsbutton->setBackgroundColor(black);
00139         m_toolsbutton->setBaseColor(dark);
00140 
00141         m_hiddenPos = -h;
00142         m_animationDelta = h/6;
00143     }
00144 
00145     Console::~Console() {
00146         doHide();
00147 
00148         remove(m_input);
00149         remove(m_outputscrollarea);
00150         remove(m_status);
00151 
00152         delete m_output;
00153         delete m_input;
00154         delete m_outputscrollarea;
00155         delete m_status;
00156         delete m_toolsbutton;
00157     }
00158 
00159     void Console::updateCaption() {
00160         std::string caption = "FIFE Console - FPS: ";
00161         double fps = 1e3/TimeManager::instance()->getAverageFrameTime();
00162         caption += boost::lexical_cast<std::string>(fps);
00163         m_status->setCaption( caption );
00164     }
00165 
00166     void Console::updateAnimation() {
00167         if (m_hiding){
00168         setPosition(getX(), getY() - m_animationDelta);
00169         if (getY() <= m_hiddenPos){
00170             doHide();
00171             m_animationTimer.stop();
00172         }
00173         }else{
00174         setPosition(getX(), getY() + m_animationDelta);
00175         if (getY() >= 0){
00176             setPosition(getX(), 0);
00177             m_animationTimer.stop();
00178         }
00179     }
00180     }
00181 
00182     void Console::clear() {
00183         m_output->setText("");
00184     }
00185 
00186     void Console::doShow() {
00187         if (m_isAttached)
00188             return;
00189         m_isAttached = true;
00190         GUIChanManager::instance()->add(this);
00191         GUIChanManager::instance()->getTopContainer()->moveToTop(this);
00192         // Assure the input field is focused when shown.
00193         m_input->requestFocus();
00194 
00195         m_fpsTimer.start();
00196     }
00197 
00198     void Console::doHide() {
00199         if (!m_isAttached)
00200             return;
00201         m_isAttached = false;
00202         GUIChanManager::instance()->remove(this);
00203         m_fpsTimer.stop();
00204     }
00205 
00206     void Console::show() {
00207         if(m_hiding) {
00208             m_hiding = false;
00209             doShow();
00210             m_animationTimer.start();
00211         }
00212     }
00213 
00214     void Console::hide() {
00215         if(!m_hiding) {
00216             m_hiding = true;
00217             m_animationTimer.start();
00218         }
00219     }
00220 
00221     void Console::toggleShowHide() {
00222         m_hiding = !m_hiding;
00223         if(!m_hiding)
00224             doShow();
00225         m_animationTimer.start();
00226     }
00227 
00228     void Console::execute(std::string cmd) {
00229         FL_DBG(_log, LMsg("in execute with command ") << cmd);
00230         if (cmd.empty())
00231             return;
00232 
00233         // copy input to output
00234         println(m_prompt + cmd);
00235 
00236         // run the command
00237         try {
00238             if (m_consoleexec) {
00239                 std::string resp = m_consoleexec->onConsoleCommand(cmd);
00240                 println(resp);
00241             } else {
00242                 FL_WARN(_log, LMsg("ConsoleExecuter not bind, but command received: ") << cmd.c_str());
00243             }
00244         }
00245         catch (const FIFE::Exception & e) {
00246             FL_WARN(_log, LMsg("Console caught exception: ") << e.what());
00247             println(e.what());
00248         }
00249     }
00250 
00251     void Console::println(const std::string & s) {
00252         assert(m_output);
00253 
00254         // Add the text in rows
00255         boost::char_separator<char> separator("\n");
00256         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
00257         tokenizer tokens(s,separator);
00258         for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i) {
00259             m_output->addRow(*i);
00260         }
00261 
00262         // Assure the maximum number of rows
00263         if( m_output->getNumberOfRows() > m_maxOutputRows ) {
00264             unsigned rows = m_output->getNumberOfRows();
00265             int32_t delta_rows = rows - m_maxOutputRows;
00266             std::vector<std::string> rows_text;
00267             for(size_t i=delta_rows; i != rows; ++i) {
00268                 rows_text.push_back(m_output->getTextRow(i));
00269             }
00270             m_output->setText("");
00271             for(size_t i=0; i != rows_text.size(); ++i) {
00272                 m_output->addRow(rows_text[i]);
00273             }
00274         }
00275 
00276         // Assure the new text is visible
00277         gcn::Rectangle rect(0,m_output->getHeight(),0,0);
00278         m_outputscrollarea->showWidgetPart(m_output,rect);
00279     }
00280 
00281     void Console::action(const gcn::ActionEvent & event) {
00282         if (m_consoleexec) {
00283             m_consoleexec->onToolsClick();
00284         } else {
00285             FL_WARN(_log, "ConsoleExecuter not bind, but tools button clicked");
00286         }
00287     }
00288 
00289     void Console::setConsoleExecuter(ConsoleExecuter* const consoleexec) {
00290         m_consoleexec = consoleexec;
00291     }
00292 
00293     void Console::removeConsoleExecuter() {
00294         m_consoleexec = NULL;
00295     }
00296 
00297     void Console::setIOFont(GuiFont* font) {
00298         m_input->setFont(font);
00299         m_output->setFont(font);
00300     }
00301 
00302     void Console::focusLost(const gcn::Event& ) {
00303         hide();
00304     }
00305 }
00306 /* vim: set noexpandtab: set shiftwidth=2: set tabstop=2: */