/* 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_ #include "shell.h" #include "text_engine.h" #include "list.h" #include "graphics_engine.h" #include "event_handler.h" #include "debug.h" #include #include using namespace std; /** * standard constructor */ Shell::Shell () { this->setClassID(CL_SHELL, "Shell"); this->setName("Shell"); this->buffer = new tList; this->textSize = 10; //this->bufferSize = 0; this->bufferText = NULL; this->setBufferSize(100); this->setBufferDisplaySize(10); this->setAbsCoor2D(3, GraphicsEngine::getInstance()->getResolutionY()); this->delayed = 0; this->setRepeatDelay(.3, .05); this->pressedKey = SDLK_FIRST; this->inputLineText = TextEngine::getInstance()->createText("fonts/earth.ttf", 10, TEXT_DYNAMIC, 255, 0, 0); this->inputLineText->setAlignment(TEXT_ALIGN_LEFT); this->inputLineText->setText(NULL); this->inputLine = new char[1]; this->inputLine[0] = '\0'; this->inputLineText->setParent2D(this); EventHandler* evh = EventHandler::getInstance(); evh->subscribe(this, ES_ALL, SDLK_BACKQUOTE); for (int i = 1; i < SDLK_F15; i++) evh->subscribe(this, ES_SHELL, i); } Shell* Shell::singletonRef = NULL; /** * standard deconstructor */ Shell::~Shell () { // delete the displayable Buffers for (int i = 0; i < this->bufferDisplaySize; i++) delete this->bufferText[i]; delete this->bufferText; // delete the inputLine delete this->inputLineText; delete this->inputLine; // delete all the Chars in the Buffers tIterator* charIterator = this->buffer->getIterator(); char* charElem = charIterator->nextElement(); while (charElem != NULL) { delete charElem; charElem = charIterator->nextElement(); } delete charIterator; Shell::singletonRef = NULL; } /** * 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) { if (this->bufferText != NULL) { for (unsigned int i = 0; i < this->bufferDisplaySize; i++) delete this->bufferText[i]; delete this->bufferText; } this->bufferText = new Text*[bufferDisplaySize]; for (unsigned int i = 0; i < bufferDisplaySize; i++) { this->bufferText[i] = TextEngine::getInstance()->createText("fonts/earth.ttf", this->textSize, TEXT_DYNAMIC, 255, 0, 0); this->bufferText[i]->setAlignment(TEXT_ALIGN_LEFT); this->bufferText[i]->setRelCoor2D(5, 12+12*i); this->bufferText[i]->setText(NULL); this->bufferText[i]->setParent2D(this); } this->bufferDisplaySize = bufferDisplaySize; } /** * deletes all the Buffers */ void Shell::flushBuffers() { // remove all chars from the BufferTexts. if (this->bufferText) for (int i; i < this->bufferDisplaySize; i++) { this->bufferText[i]->setText(NULL); } // delete all the Chars in the Buffers tIterator* charIterator = this->buffer->getIterator(); char* charElem = charIterator->nextElement(); while (charElem != NULL) { delete charElem; charElem = charIterator->nextElement(); } delete charIterator; } /** * adds a new Line to the List of Buffers * @param line the Line as in the first argument in printf * @param args the arguments as a va_list * * @todo optimize */ bool Shell::addBufferLineStatic(const char* line, ...) { va_list arguments; va_start(arguments, line); #if DEBUG < 3 if (Shell::singletonRef == NULL) #endif vprintf(line, arguments); #if DEBUG < 3 else #else if (Shell::singletonRef != NULL) #endif Shell::singletonRef->addBufferLine(line, arguments); return true; } int curr = 0; /** * add a Line to the List of Buffers * @param line * @param arguments * * This function Adds one line to the buffer. * and displays the line as the First Line of the display-buffer */ void Shell::addBufferLine(const char* line, va_list arguments) { vsprintf(this->bufferArray, line, arguments); char* newLine = new char[strlen(this->bufferArray)+1]; strcpy(newLine, this->bufferArray); this->buffer->add(newLine); if (this->buffer->getSize() > this->bufferSize) { delete this->buffer->firstElement(); this->buffer->remove(this->buffer->firstElement()); } if (likely(bufferText != NULL)) { Text* moveText = this->bufferText[this->bufferDisplaySize-1]; for (int i = this->bufferDisplaySize-1; i > 0; i--) { this->bufferText[i] = this->bufferText[i-1]; } this->bufferText[0] = moveText; } this->bufferText[0]->setText(newLine); // this->bufferText-> // this->inputLineText->setText(newLine); } /** * moves the buffer around lineCount lines upwards (negative values move down) * @param lineCount the Count of lines to move upwards * * @todo */ void Shell::moveBuffer(int lineCount) { } /** * @param lineNumber the n-th line from the bottom * @returns the Buffer at Line lineNumber */ const char* Shell::getBufferLine(unsigned int lineNumber) { tIterator* charIterator = this->buffer->getIterator(); char* charElem = charIterator->nextElement(); int i = 1; while (charElem != NULL) { if (i++ < lineNumber) { delete charIterator; return charElem; } charElem = charIterator->nextElement(); } delete charIterator; } /** * deletes the InputLine */ void Shell::flushInputLine() { if (likely(this->inputLine != NULL)) { delete [] this->inputLine; } this->inputLine = new char[1]; *this->inputLine = '\0'; } /** * adds one character to the inputLine * @param character the character to add to the inputLine */ void Shell::addCharacter(char character) { char* addCharLine = new char[strlen(inputLine)+2]; sprintf(addCharLine, "%s%c", this->inputLine, character); delete this->inputLine; this->inputLine = addCharLine; this->inputLineText->setText(inputLine); } /** * adds multiple Characters to thr inputLine * @param characters a '\0' terminated char-array to add to the InputLine */ void Shell::addCharacters(const char* characters) { char* addCharLine = new char[strlen(inputLine)+strlen(characters)+1]; sprintf(addCharLine, "%s%s", this->inputLine, characters); delete this->inputLine; this->inputLine = addCharLine; this->inputLineText->setText(inputLine); } /** * removes characterCount characters from the InputLine * @param characterCount the count of Characters to remove from the input Line */ void Shell::removeCharacters(unsigned int characterCount) { if (strlen(this->inputLine) == 0) return; if (characterCount > strlen(this->inputLine)) characterCount = strlen(this->inputLine); char* removeCharLine = new char[strlen(inputLine)-characterCount+1]; strncpy(removeCharLine, this->inputLine, strlen(inputLine)-characterCount); removeCharLine[strlen(inputLine)-characterCount] = '\0'; delete this->inputLine; this->inputLine = removeCharLine; this->inputLineText->setText(inputLine); } /** * executes the command stored in the inputLine * @return true if the command was commited successfully, false otherwise */ bool Shell::executeCommand() { this->addBufferLineStatic("Execute Command: %s\n", this->inputLine); delete this->inputLine; this->inputLine = new char[1]; this->inputLine[0]='\0'; this->inputLineText->setText(this->inputLine); return false; } /** * sets the Repeate-delay and rate * @param repeatDelay the Delay it takes, to repeate a key * @param repeatRate the rate to repeate a pressed key */ void Shell::setRepeatDelay(float repeatDelay, float repeatRate) { this->repeatDelay = repeatDelay; this->repeatRate = repeatRate; } #include "key_names.h" /** * listens for some event * @param event the Event happened */ void Shell::process(const Event &event) { if (event.bPressed) { PRINTF(4)("Shell received command %s\n", SDLKToKeyname(event.type)); if (event.type == SDLK_BACKQUOTE) { if (EventHandler::getInstance()->getState() == ES_GAME) { EventHandler::getInstance()->setState(ES_SHELL); this->setRelCoorSoft2D(0, GraphicsEngine::getInstance()->getResolutionY()-150, 1, 5); } else { EventHandler::getInstance()->setState(ES_GAME); this->setRelCoorSoft2D(0, GraphicsEngine::getInstance()->getResolutionY()+10, 1, 5); } } else if (event.type == SDLK_TAB) this->autoComplete(); else if (event.type == SDLK_BACKSPACE) { this->delayed = this->repeatDelay; this->pressedKey = SDLK_BACKSPACE; this->removeCharacters(1); } else if (event.type == SDLK_RETURN) this->executeCommand(); else if (likely(event.type < 127)) { this->delayed = this->repeatDelay; this->pressedKey = event.type; this->addCharacter(event.type); } } else // if(!event.bPressed) { if (this->pressedKey == event.type) this->pressedKey = SDLK_FIRST; this->delayed = 0.0; } } /** * ticks the Shell for dt Seconds * @param dt the elapsed time since the last tick(); */ void Shell::tick(float dt) { if (this->delayed > 0.0) this->delayed -= dt; else if (this->pressedKey != SDLK_FIRST ) { this->delayed = this->repeatRate; if (this->pressedKey == SDLK_BACKSPACE) this->removeCharacters(1); else if (pressedKey < 127) this->addCharacter(this->pressedKey); } } /** * displays the Shell */ void Shell::draw() const { glPushMatrix(); // transform for alignment. // setting the Blending effects glColor4f(0.0f, 0.0f, 0.8f, .4); glEnable(GL_BLEND); glDisable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE); // glBindTexture(GL_TEXTURE_2D, this->texture); glBegin(GL_QUADS); // glTexCoord2f(this->texCoord.minU, this->texCoord.minV); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y ); // glTexCoord2f(this->texCoord.maxU, this->texCoord.minV); glVertex2f(this->getAbsCoor2D().x + 800, this->getAbsCoor2D().y ); // glTexCoord2f(this->texCoord.maxU, this->texCoord.maxV); glVertex2f(this->getAbsCoor2D().x + 800, this->getAbsCoor2D().y + 150); // glTexCoord2f(this->texCoord.minU, this->texCoord.maxV); glVertex2f(this->getAbsCoor2D().x, this->getAbsCoor2D().y + 150); glEnd(); } /** * autocompletes the Shell's inputLine * @returns true, if a result was found, false otherwise */ bool Shell::autoComplete() { PRINTF(3)("AutoCompletion not implemented yet\n"); } /** * displays some nice output from the Shell */ void Shell::debug() const { if (this->pressedKey != SDLK_FIRST) printf("%s::%f %f\n", SDLKToKeyname(this->pressedKey), this->delayed, this->repeatDelay); }