1 /*************************************************************************** 2 * Copyright (C) 2005-2019 by the FIFE team * 3 * http://www.fifengine.net * 4 * This file is part of FIFE. * 5 * * 6 * FIFE is free software; you can redistribute it and/or * 7 * modify it under the terms of the GNU Lesser General Public * 8 * License as published by the Free Software Foundation; either * 9 * version 2.1 of the License, or (at your option) any later version. * 10 * * 11 * This library is distributed in the hope that it will be useful, * 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 14 * Lesser General Public License for more details. * 15 * * 16 * You should have received a copy of the GNU Lesser General Public * 17 * License along with this library; if not, write to the * 18 * Free Software Foundation, Inc., * 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 20 ***************************************************************************/ 21 22 // Standard C++ library includes 23 #include <cassert> 24 25 // 3rd party library includes 26 #include <boost/tokenizer.hpp> 27 28 // FIFE includes 29 // These includes are split up in two parts, separated by one empty line 30 // First block: files included from the FIFE root src directory 31 // Second block: files included from the same folder 32 #include "video/renderbackend.h" 33 #include "util/time/timemanager.h" 34 #include "util/log/logger.h" 35 #include "util/base/exception.h" 36 #include "gui/fifechan/fifechanmanager.h" 37 #include "gui/fifechan/base/gui_font.h" 38 39 #include "commandline.h" 40 #include "console.h" 41 42 namespace FIFE { 43 const unsigned Console::m_maxOutputRows = 50; 44 static Logger _log(LM_CONSOLE); 45 Console()46 Console::Console() 47 : fcn::Container(), 48 m_consoleexec(0), 49 m_input(new CommandLine()), 50 m_output(new fcn::TextBox()), 51 m_outputscrollarea(new fcn::ScrollArea(m_output)), 52 m_status(new fcn::Label()), 53 m_toolsbutton(new fcn::Button("Tools")) 54 { 55 reLayout(); 56 57 add(m_outputscrollarea); 58 add(m_input); 59 add(m_status); 60 add(m_toolsbutton); 61 62 setOpaque(true); 63 64 m_input->setCallback(std::bind1st( std::mem_fun(&Console::execute), this) ); 65 m_prompt = "-- "; 66 67 m_isAttached = false; 68 69 m_fpsTimer.setInterval(500); 70 m_fpsTimer.setCallback(std::bind(&Console::updateCaption, this) ); 71 72 m_hiding = true; 73 74 m_animationTimer.setInterval(20); 75 m_animationTimer.setCallback(std::bind(&Console::updateAnimation, this) ); 76 77 m_toolsbutton->addActionListener(this); 78 m_toolsbutton->setFocusable(false); 79 m_input->addFocusListener(this); 80 81 GuiFont* font = FifechanManager::instance()->createFont(); 82 font->setColor(255,255,255); 83 setIOFont(font); 84 } 85 reLayout()86 void Console::reLayout() { 87 int32_t w, h, b, input_h, bbar_h, button_w; 88 w = RenderBackend::instance()->getScreenWidth() * 4/5; 89 h = RenderBackend::instance()->getScreenHeight() * 4/5; 90 b = 0; 91 input_h = getFont()->getHeight(); 92 bbar_h = input_h; 93 button_w = 80; 94 95 fcn::Color black(0x00,0,0,0xff); 96 fcn::Color white(0xff,0xff,0xff,0xff); 97 fcn::Color dark(50,60,50,0xff); 98 99 setSize(w, h); 100 setPosition((RenderBackend::instance()->getScreenWidth() - w) / 2,-h); 101 setBorderSize(0); 102 103 setForegroundColor(white); 104 setBackgroundColor(black); 105 setBaseColor(dark); 106 107 setSize(w, h); 108 109 m_outputscrollarea->setSize(w - 2*b, h - input_h - 3*b - bbar_h); 110 m_outputscrollarea->setPosition(b,0); 111 112 m_input->setPosition(b, h - input_h - b - bbar_h); 113 m_input->setSize(w - 2*b, input_h); 114 115 m_status->setPosition(b, h - b - bbar_h); 116 m_status->setSize(w - 2*b, bbar_h); 117 118 m_toolsbutton->setPosition(w - button_w, h - b - bbar_h); 119 m_toolsbutton->setSize(button_w, bbar_h); 120 121 m_output->setBackgroundColor(black); 122 m_output->setFocusable(false); 123 124 m_outputscrollarea->setBackgroundColor(black); 125 m_outputscrollarea->setBaseColor(dark); 126 127 m_input->setForegroundColor(white); 128 m_input->setBackgroundColor(black); 129 130 m_status->setForegroundColor(white); 131 m_status->setBackgroundColor(black); 132 133 m_toolsbutton->setForegroundColor(white); 134 m_toolsbutton->setBackgroundColor(black); 135 m_toolsbutton->setBaseColor(dark); 136 137 m_hiddenPos = -h; 138 m_animationDelta = h/6; 139 } 140 ~Console()141 Console::~Console() { 142 doHide(); 143 144 remove(m_input); 145 remove(m_outputscrollarea); 146 remove(m_status); 147 148 delete m_output; 149 delete m_input; 150 delete m_outputscrollarea; 151 delete m_status; 152 delete m_toolsbutton; 153 } 154 updateCaption()155 void Console::updateCaption() { 156 std::string caption = "FIFE Console - FPS: "; 157 double fps = 1e3/TimeManager::instance()->getAverageFrameTime(); 158 caption += std::to_string(fps); 159 m_status->setCaption( caption ); 160 } 161 updateAnimation()162 void Console::updateAnimation() { 163 if (m_hiding){ 164 setPosition(getX(), getY() - m_animationDelta); 165 if (getY() <= m_hiddenPos){ 166 doHide(); 167 m_animationTimer.stop(); 168 } 169 }else{ 170 setPosition(getX(), getY() + m_animationDelta); 171 if (getY() >= 0){ 172 setPosition(getX(), 0); 173 m_animationTimer.stop(); 174 } 175 } 176 } 177 clear()178 void Console::clear() { 179 m_output->setText(""); 180 } 181 doShow()182 void Console::doShow() { 183 if (m_isAttached) 184 return; 185 m_isAttached = true; 186 FifechanManager::instance()->add(this); 187 FifechanManager::instance()->getTopContainer()->moveToTop(this); 188 // Assure the input field is focused when shown. 189 m_input->requestFocus(); 190 191 m_fpsTimer.start(); 192 } 193 doHide()194 void Console::doHide() { 195 if (!m_isAttached) 196 return; 197 m_isAttached = false; 198 FifechanManager::instance()->remove(this); 199 m_fpsTimer.stop(); 200 } 201 show()202 void Console::show() { 203 if(m_hiding) { 204 m_hiding = false; 205 doShow(); 206 m_animationTimer.start(); 207 } 208 } 209 hide()210 void Console::hide() { 211 if(!m_hiding) { 212 m_hiding = true; 213 m_animationTimer.start(); 214 } 215 } 216 toggleShowHide()217 void Console::toggleShowHide() { 218 m_hiding = !m_hiding; 219 if(!m_hiding) 220 doShow(); 221 m_animationTimer.start(); 222 } 223 execute(std::string cmd)224 void Console::execute(std::string cmd) { 225 FL_DBG(_log, LMsg("in execute with command ") << cmd); 226 if (cmd.empty()) 227 return; 228 229 // copy input to output 230 println(m_prompt + cmd); 231 232 // run the command 233 try { 234 if (m_consoleexec) { 235 std::string resp = m_consoleexec->onConsoleCommand(cmd); 236 println(resp); 237 } else { 238 FL_WARN(_log, LMsg("ConsoleExecuter not bind, but command received: ") << cmd.c_str()); 239 } 240 } 241 catch (const FIFE::Exception & e) { 242 FL_WARN(_log, LMsg("Console caught exception: ") << e.what()); 243 println(e.what()); 244 } 245 } 246 println(const std::string & s)247 void Console::println(const std::string & s) { 248 assert(m_output); 249 250 // Add the text in rows 251 boost::char_separator<char> separator("\n"); 252 typedef boost::tokenizer<boost::char_separator<char> > tokenizer; 253 tokenizer tokens(s,separator); 254 for(tokenizer::iterator i = tokens.begin(); i != tokens.end(); ++i) { 255 m_output->addRow(*i); 256 } 257 258 // Assure the maximum number of rows 259 if( m_output->getNumberOfRows() > m_maxOutputRows ) { 260 unsigned rows = m_output->getNumberOfRows(); 261 int32_t delta_rows = rows - m_maxOutputRows; 262 std::vector<std::string> rows_text; 263 for(size_t i=delta_rows; i != rows; ++i) { 264 rows_text.push_back(m_output->getTextRow(i)); 265 } 266 m_output->setText(""); 267 for(size_t i=0; i != rows_text.size(); ++i) { 268 m_output->addRow(rows_text[i]); 269 } 270 } 271 272 // Assure the new text is visible 273 fcn::Rectangle rect(0,m_output->getHeight(),0,0); 274 m_outputscrollarea->showWidgetPart(m_output,rect); 275 } 276 action(const fcn::ActionEvent & event)277 void Console::action(const fcn::ActionEvent & event) { 278 if (m_consoleexec) { 279 m_consoleexec->onToolsClick(); 280 } else { 281 FL_WARN(_log, "ConsoleExecuter not bind, but tools button clicked"); 282 } 283 } 284 setConsoleExecuter(ConsoleExecuter * const consoleexec)285 void Console::setConsoleExecuter(ConsoleExecuter* const consoleexec) { 286 m_consoleexec = consoleexec; 287 } 288 removeConsoleExecuter()289 void Console::removeConsoleExecuter() { 290 m_consoleexec = NULL; 291 } 292 setIOFont(GuiFont * font)293 void Console::setIOFont(GuiFont* font) { 294 m_input->setFont(font); 295 m_output->setFont(font); 296 } 297 focusLost(const fcn::Event &)298 void Console::focusLost(const fcn::Event& ) { 299 hide(); 300 } 301 } 302