/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Benjamin Grauer co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_SHELL #include "shell.h" #include "shell_command.h" #include "shell_buffer.h" #include "shell_input.h" #include "text.h" #include "graphics_engine.h" #include "material.h" #include "event_handler.h" #include "debug.h" #include "class_list.h" #include "key_names.h" #include #include namespace OrxShell { SHELL_COMMAND(clear, Shell, clear) ->describe("Clears the shell from unwanted lines (empties all buffers)") ->setAlias("clear"); SHELL_COMMAND(deactivate, Shell, deactivate) ->describe("Deactivates the Shell. (moves it into background)") ->setAlias("hide"); SHELL_COMMAND(textsize, Shell, setTextSize) ->describe("Sets the size of the Text size, linespacing") ->defaultValues(15, 0); SHELL_COMMAND(textcolor, Shell, setTextColor) ->describe("Sets the Color of the Shells Text (red, green, blue, alpha)") ->defaultValues(SHELL_DEFAULT_TEXT_COLOR); SHELL_COMMAND(backgroundcolor, Shell, setBackgroundColor) ->describe("Sets the Color of the Shells Background (red, green, blue, alpha)") ->defaultValues(SHELL_DEFAULT_BACKGROUND_COLOR); SHELL_COMMAND(backgroundimage, Shell, setBackgroundImage) ->describe("sets the background image to load for the Shell") ->completionPlugin(0, OrxShell::CompletorFileSystem()); SHELL_COMMAND(font, Shell, setFont) ->describe("Sets the font of the Shell") ->defaultValues(SHELL_DEFAULT_FONT) ->completionPlugin(0, OrxShell::CompletorFileSystem(".ttf", "fonts/")); /** * standard constructor */ Shell::Shell () { this->setClassID(CL_SHELL, "Shell"); this->setName("Shell"); // EVENT-Handler subscription of '`' to all States. EventHandler::getInstance()->subscribe(this, ES_ALL, SDLK_BACKQUOTE); EventHandler::getInstance()->subscribe(this, ES_ALL, SDLK_F12); EventHandler::getInstance()->subscribe(this, ES_SHELL, SDLK_PAGEUP); EventHandler::getInstance()->subscribe(this, ES_SHELL, SDLK_PAGEDOWN); // BUFFER this->bufferOffset = 0; this->bufferIterator = ShellBuffer::getInstance()->getBuffer().begin(); // INPUT LINE this->setLayer(E2D_LAYER_ABOVE_ALL); this->shellInput.setLayer(E2D_LAYER_ABOVE_ALL); this->backgroundMaterial = new Material; // Element2D and generals this->setAbsCoor2D(3, -400); this->textSize = 15; this->lineSpacing = 0; this->bActive = true; this->fontFile = SHELL_DEFAULT_FONT; this->setBufferDisplaySize(10); this->setTextColor(SHELL_DEFAULT_TEXT_COLOR); this->setBackgroundColor(SHELL_DEFAULT_BACKGROUND_COLOR); this->deactivate(); // register the shell at the ShellBuffer ShellBuffer::getInstance()->registerShell(this); } /** * @brief standard deconstructor */ Shell::~Shell () { ShellBuffer::getInstance()->unregisterShell(this); // delete the displayable Buffers while (!this->bufferText.empty()) { delete this->bufferText.front(); this->bufferText.pop_front(); } // delete the inputLine delete this->backgroundMaterial; } /** * @brief activates the shell * * This also feeds the Last few lines from the main buffers into the displayBuffer */ void Shell::activate() { if (this->bActive == true) PRINTF(3)("The shell is already active\n"); this->bActive = true; EventHandler::getInstance()->pushState(ES_SHELL); EventHandler::getInstance()->withUNICODE(true); this->setRelCoorSoft2D(0, 0, 5); std::list::const_iterator textLine = --ShellBuffer::getInstance()->getBuffer().end(); bool top = false; for (std::list::iterator text = this->bufferText.begin(); text != this->bufferText.end(); ++text) { (*text)->setVisibility(true); if (!top) { (*text)->setText((*textLine)); if (textLine != ShellBuffer::getInstance()->getBuffer().begin()) top = true; textLine--; } } } /** * @brief deactiveates the Shell. */ void Shell::deactivate() { if (this->bActive == false) PRINTF(3)("The shell is already inactive\n"); this->bActive = false; EventHandler::getInstance()->withUNICODE(false); EventHandler::getInstance()->popState(); this->setRelCoorSoft2D(0, -(int)this->shellHeight, 5); for (std::list::iterator text = this->bufferText.begin(); text != this->bufferText.end(); ++text) (*text)->setVisibility(false); this->bufferOffset = 0; } /** * @brief sets the File to load the fonts from * @param fontFile the file to load the font from * * it is quite important, that the font pointed too really exists! * (be aware that within orxonox fontFile is relative to the Data-Dir) */ void Shell::setFont(const std::string& fontFile) { // if (!ResourceManager::isInDataDir(fontFile)) // return false; this->fontFile = fontFile; this->resetValues(); } /** * @brief sets the size of the text and spacing * @param textSize the size of the Text in Pixels * @param lineSpacing the size of the Spacing between two lines in pixels * * this also rebuilds the entire Text, inputLine and displayBuffer, * to be accurate again. */ void Shell::setTextSize(unsigned int textSize, unsigned int lineSpacing) { this->textSize = textSize; this->lineSpacing = lineSpacing; this->resetValues(); } /** * @brief sets the color of the Font. * @param r: red * @param g: green * @param b: blue * @param a: alpha-value. */ void Shell::setTextColor(float r, float g, float b, float a) { this->textColor[0] = r; this->textColor[1] = g; this->textColor[2] = b; this->textColor[3] = a; this->resetValues(); } /** * @brief sets the color of the Backgrond. * @param r: red * @param g: green * @param b: blue * @param a: alpha-value. */ void Shell::setBackgroundColor(float r, float g, float b, float a) { this->backgroundMaterial->setDiffuse(r, g, b); this->backgroundMaterial->setTransparency(a); } /** * @brief sets a nice background image to the Shell's background * @param fileName the filename of the Image to load */ void Shell::setBackgroundImage(const std::string& fileName) { this->backgroundMaterial->setDiffuseMap(fileName); } /** * @brief resets the Values of all visible shell's commandos to the Shell's stored values * * this functions synchronizes the stored Data with the visible one. */ void Shell::resetValues() { this->resetText(&this->shellInput, 0); this->shellInput.setRelCoor2D(15, (this->textSize + this->lineSpacing)*(this->bufferDisplaySize)); unsigned int i = 0; /* Here we create a Copy of the Buffer, so that we do not f**k up the List when some * output is routed from Some other Thread or by Changing any Values. */ std::list bufferTextCopy = this->bufferText; for (std::list::iterator text = bufferTextCopy.begin(); text != bufferTextCopy.end(); ++text, ++i) { this->resetText(*text, i); (*text)->setRelCoor2D( calculateLinePosition(i) ); } this->shellHeight = (this->textSize + this->lineSpacing) * (bufferDisplaySize+1); } void Shell::resetText(Text* text, unsigned int position) { text->setFont(this->fontFile, this->textSize); text->setColor(this->textColor[0], this->textColor[1], this->textColor[2]); text->setBlending(this->textColor[3]); text->setLayer(this->getLayer()); if (text->getParent2D() != this) text->setParent2D(this); } /** * @brief sets The count of Lines to display in the buffer. * @param bufferDisplaySize the count of lines to display in the Shell-Buffer. */ void Shell::setBufferDisplaySize(unsigned int bufferDisplaySize) { unsigned int oldSize = this->bufferText.size(); if (oldSize > bufferDisplaySize) { for (unsigned int i = bufferDisplaySize; i <= oldSize; i++) { delete this->bufferText.back(); this->bufferText.pop_back(); } } else if (oldSize < bufferDisplaySize) { for (unsigned int i = oldSize; i <= bufferDisplaySize; i++) { this->bufferText.push_back(new Text); } } this->bufferDisplaySize = bufferDisplaySize; this->resetValues(); } /** * @brief deletes all the Buffers */ void Shell::flush() { for (std::list::iterator text = this->bufferText.begin(); text != this->bufferText.end(); ++text) { (*text)->setText(""); // remove all chars from the BufferTexts. } ShellBuffer::getInstance()->flush(); // BUFFER FLUSHING } /** * @brief prints out some text to the input-buffers * @param text the text to output. */ void Shell::printToDisplayBuffer(const std::string& text) { this->bufferText.push_front(this->bufferText.back()); this->bufferText.pop_back(); unsigned int i = 0; for (std::list::iterator textIt = ++this->bufferText.begin(); textIt != this->bufferText.end(); ++textIt, i++) { (*textIt)->setRelCoorSoft2D(this->calculateLinePosition(i+1), 5); } this->bufferText.front()->setRelCoor2D(this->calculateLinePosition(0)- Vector2D(-1000,0)); this->bufferText.front()->setRelCoorSoft2D(this->calculateLinePosition(0),10); /* FANCY EFFECTS :) 1: lastText->setRelCoor2D(this->calculateLinePosition(0)- Vector(-1000,0,0)); lastText->setRelCoorSoft2D(this->calculateLinePosition(0),10); 2: lastText->setRelDir2D(-90); lastText->setRelDirSoft2D(0, 20); */ this->bufferText.front()->setText(text); } /** * moves the Display buffer (up + or down - ) * @param lineCount the count by which to shift the InputBuffer. * * @todo make this work */ void Shell::moveDisplayBuffer(int lineCount) { if (this->bufferOffset == 0) { this->bufferIterator = ShellBuffer::getInstance()->getBuffer().end(); // for (unsigned int i = 0; i < this->bufferDisplaySize; i++) // this->bufferIterator->prevStep(); } // boundraries if (this->bufferOffset + lineCount > (int)ShellBuffer::getInstance()->getBuffer().size()) lineCount = (int)ShellBuffer::getInstance()->getBuffer().size()- this->bufferOffset; else if (this->bufferOffset + lineCount < 0) lineCount = -bufferOffset; this->bufferOffset += lineCount; // moving the iterator to the right position int move = 0; while (move != lineCount) { if (move < lineCount) { ++move; this->bufferIterator--; } else { --move; this->bufferIterator++; } } // redisplay the buffers std::list::const_iterator it = this->bufferIterator; if (it == ShellBuffer::getInstance()->getBuffer().end()) { /// FIXME PRINTF(1)("Should not heappen\n"); it--; } for (std::list::iterator textIt = this->bufferText.begin(); textIt != this->bufferText.end(); ++textIt) { (*textIt)->setText((*it)); if (it == ShellBuffer::getInstance()->getBuffer().begin()) { /// FIXME PRINTF(1)("Should not heappen\n"); break; } it--; } } /** * clears the Shell (empties all buffers) */ void Shell::clear() { this->flush(); ShellBuffer::addBufferLineStatic("orxonox - shell\n ==================== \n", NULL); } /** * listens for some event * @param event the Event happened */ void Shell::process(const Event &event) { if (event.bPressed) { if (event.type == SDLK_BACKQUOTE || event.type == SDLK_F12) { if (this->bActive == false) this->activate(); else this->deactivate(); } else if (event.type == SDLK_PAGEUP) { this->moveDisplayBuffer(+this->bufferDisplaySize-1); } else if (event.type == SDLK_PAGEDOWN) { this->moveDisplayBuffer(-this->bufferDisplaySize+1); } } } /** * displays the Shell */ void Shell::draw() const { // transform for alignment. // setting the Blending effects this->backgroundMaterial->select(); glBegin(GL_TRIANGLE_STRIP); glTexCoord2f(0, 0); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y ); glTexCoord2f(1, 0); glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().y ); glTexCoord2f(0, 1); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight); glTexCoord2f(1, 1); glVertex2f(GraphicsEngine::getInstance()->getResolutionX() - this->getAbsCoor2D().x, this->getAbsCoor2D().y + this->shellHeight); glEnd(); } /////////////////////// // HELPER FUNCTIONS // /////////////////////// /** * @brief calculates the position of a Buffer-Display Line * @param lineNumber the lineNumber from the bottom to calculate the position from * @returns the Position of the Line. */ Vector2D Shell::calculateLinePosition(unsigned int lineNumber) { return Vector2D(5, (this->textSize + this->lineSpacing)*(this->bufferDisplaySize - lineNumber - 2) + this->textSize); } /** * @brief displays some nice output from the Shell */ void Shell::debug() const { PRINT(3)("Debugging output to console (not this shell)\n"); // if (this->pressedKey != SDLK_FIRST) // printf("%s::%f %f\n", SDLKToKeyname(this->pressedKey), this->delayed, this->repeatDelay); ShellBuffer::getInstance()->debug(); } // void Shell::testI (int i) // { // PRINTF(3)("This is the Test for one Int '%d'\n", i); // } // // void Shell::testS (const char* s) // { // PRINTF(3)("This is the Test for one String '%s'\n", s); // } // // void Shell::testB (bool b) // { // PRINTF(3)("This is the Test for one Bool: "); // if (b) // PRINTF(3)("true\n"); // else // PRINTF(3)("false\n"); // } // // void Shell::testF (float f) // { // PRINTF(3)("This is the Test for one Float '%f'\n", f); // } // // void Shell::testSF (const char* s, float f) // { // PRINTF(3)("This is the Test for one String '%s' and one Float '%f'\n",s , f); // } }