[Orxonox-commit 1460] r6178 - code/branches/presentation2/src/libraries/core

rgrieder at orxonox.net rgrieder at orxonox.net
Sun Nov 29 21:25:12 CET 2009


Author: rgrieder
Date: 2009-11-29 21:25:11 +0100 (Sun, 29 Nov 2009)
New Revision: 6178

Modified:
   code/branches/presentation2/src/libraries/core/IOConsole.cc
   code/branches/presentation2/src/libraries/core/IOConsole.h
Log:
IOConsole: Restructured some code and added more documentation.

Modified: code/branches/presentation2/src/libraries/core/IOConsole.cc
===================================================================
--- code/branches/presentation2/src/libraries/core/IOConsole.cc	2009-11-29 13:47:54 UTC (rev 6177)
+++ code/branches/presentation2/src/libraries/core/IOConsole.cc	2009-11-29 20:25:11 UTC (rev 6178)
@@ -44,6 +44,7 @@
 {
     IOConsole* IOConsole::singletonPtr_s = NULL;
 
+    //! Extracts the log level associated to a string (first character)
     int IOConsole::extractLogLevel(std::string* text)
     {
         // Handle line colouring by inspecting the first letter
@@ -264,7 +265,7 @@
             this->bStatusPrinted_ = true;
         }
 
-        // We always assume that the cursor is on the inputline.
+        // We always assume that the cursor is on the input line.
         // But we cannot always be sure about that, esp. if we scroll the console
         this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B';
         this->cout_ << "\033[" << this->statusLineWidths_.size() << 'A';
@@ -468,6 +469,7 @@
 
 namespace orxonox
 {
+    //! Redirects std::cout, creates the corresponding Shell and changes the terminal mode
     IOConsole::IOConsole()
         : shell_(new Shell("IOConsole", false, true))
         , buffer_(shell_->getInputBuffer())
@@ -475,7 +477,7 @@
         , promptString_("orxonox # ")
         , statusLines_(1)
         , inputLineHeight_(1)
-        , lastOutputLineHeight_(1)
+        , lastOutputLineHeight_(0)
     {
         // Disable standard this->cout_ logging
         OutputHandler::getInstance().disableCout();
@@ -488,31 +490,34 @@
         GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);
         this->terminalWidth_  = screenBufferInfo.dwSize.X;
         this->terminalHeight_ = screenBufferInfo.dwSize.Y;
+        // Determines where we are in respect to output already written with std::cout
+        this->inputLineRow_ = screenBufferInfo.dwCursorPosition.Y;
+/*
         this->lastTerminalWidth_  = this->terminalWidth_;
         this->lastTerminalHeight_ = this->terminalHeight_;
-        // Determines where we are in respect to output already written with std::cout
-        this->inputLineRow_ = screenBufferInfo.dwCursorPosition.Y;
+*/
 
         // Cursor already at the end of the screen buffer?
         // (assuming the current input line height is 1)
-        if (this->inputLineRow_ >= (int)this->terminalHeight_ - (int)this->statusLines_)
-            this->moveCursor(0, -this->inputLineRow_ + this->terminalHeight_ - this->statusLines_ - 1);
+        if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)
+            SetConsoleCursorPosition(this->stdOutHandle_, makeCOORD(0, this->terminalHeight_ - this->statusLines_));
 
         // Prevent input line from overflowing
         int maxInputLength = (this->terminalHeight_ - this->statusLines_) * this->terminalWidth_ - 1 - this->promptString_.size();
         // Consider that the echo of a command might include the command plus some other characters (assumed max 80)
         // Also put a minimum so the config file parser is not overwhelmed with the command history
-        this->shell_->getInputBuffer()->setMaxLength(std::min(8192, (maxInputLength - 80) / 2));
+        this->buffer_->setMaxLength(std::min(8192, (maxInputLength - 80) / 2));
 
         // Print input and status line and position cursor
+        this->inputChanged();
+        this->cursorChanged();
         this->lastRefreshTime_ = Game::getInstance().getGameClock().getRealMicroseconds();
         this->update(Game::getInstance().getGameClock());
-        this->inputChanged();
-        this->cursorChanged();
 
         this->shell_->registerListener(this);
     }
 
+    //! Resets std::cout redirection and restores the terminal mode
     IOConsole::~IOConsole()
     {
         this->shell_->unregisterListener(this);
@@ -534,6 +539,7 @@
         this->shell_->destroy();
     }
 
+    //! Processes the pending input key strokes, refreshes the status lines and handles std::cout (redirected)
     void IOConsole::update(const Clock& time)
     {
         // Process input
@@ -585,14 +591,16 @@
         }
 
         // TODO: Respect screen buffer size changes
+/*
         // The user can manually adjust the screen buffer size on Windows
         // And we don't want to screw the console because of that
-        //this->lastTerminalWidth_ = this->terminalWidth_;
-        //this->lastTerminalHeight_ = this->terminalHeight_;
-        //this->getTerminalSize(); // Also sets this->inputLineRow_ according to the cursor position
+        this->lastTerminalWidth_ = this->terminalWidth_;
+        this->lastTerminalHeight_ = this->terminalHeight_;
+        this->getTerminalSize(); // Also sets this->inputLineRow_ according to the cursor position
         // Is there still enough space below the cursor for the status line(s)?
-        //if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)
-        //    this->moveCursor(0, -this->inputLineRow_ + this->terminalHeight_ - this->statusLines_ - 1);
+        if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)
+            this->moveCursor(0, -this->inputLineRow_ + this->terminalHeight_ - this->statusLines_ - 1);
+*/
 
         // Refresh status line 5 times per second
         if (time.getMicroseconds() > this->lastRefreshTime_ + 1000000)
@@ -609,6 +617,7 @@
         }
     }
 
+    //! Prints output text. Similar to writeText, but sets the colour according to the output level
     void IOConsole::printOutputLine(const std::string& text, const COORD& pos)
     {
         std::string output = text;
@@ -618,17 +627,18 @@
         WORD colour = 0;
         switch (level)
         {
-        case  1: colour = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
-        case  2: colour = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY; break;
-        case  3: colour = FOREGROUND_INTENSITY; break;
-        case  4: colour = FOREGROUND_INTENSITY; break;
-        default: colour = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN; break;
+        case  1: colour = FOREGROUND_INTENSITY                    | FOREGROUND_RED ; break;
+        case  2: colour = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED ; break;
+        case  3: colour = FOREGROUND_INTENSITY                                     ; break;
+        case  4: colour = FOREGROUND_INTENSITY                                     ; break;
+        default: colour =                        FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ; break;
         }
 
         // Print output line
         this->writeText(output, pos, colour);
     }
 
+    //! Prints all status lines with current content
     void IOConsole::printStatusLines()
     {
         // Prepare text to be written
@@ -637,10 +647,10 @@
         oss <<               std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";
         // Clear rest of the line by inserting spaces
         oss << std::string(this->terminalWidth_ - oss.str().size(), ' ');
-        COORD pos = {0, this->inputLineRow_ + this->inputLineHeight_};
-        this->writeText(oss.str(), pos, FOREGROUND_GREEN);
+        this->writeText(oss.str(), makeCOORD(0, this->inputLineRow_ + this->inputLineHeight_), FOREGROUND_GREEN);
     }
 
+    //! Changes the console parameters for unbuffered input
     void IOConsole::setTerminalMode()
     {
         // Set the console mode to no-echo, raw input, and no window or mouse events
@@ -656,23 +666,13 @@
         FlushConsoleInputBuffer(this->stdInHandle_);
     }
 
+    //! Restores the console parameters
     void IOConsole::resetTerminalMode()
     {
         SetConsoleMode(this->stdInHandle_, this->originalTerminalSettings_);
     }
 
-    //! Moves the console cursor around and clamps its position to fit into the screen buffer
-    void IOConsole::moveCursor(int dx, int dy)
-    {
-        CONSOLE_SCREEN_BUFFER_INFO info;
-        GetConsoleScreenBufferInfo(this->stdOutHandle_, &info);
-        SHORT& x = info.dwCursorPosition.X;
-        x = clamp(x + dx, 0, info.dwSize.X - 1);
-        SHORT& y = info.dwCursorPosition.Y;
-        y = clamp(y + dy, 0, info.dwSize.Y - 1);
-        SetConsoleCursorPosition(this->stdOutHandle_, info.dwCursorPosition);
-    }
-
+    //! Sets this->terminalWidth_ and this->terminalHeight_
     void IOConsole::getTerminalSize()
     {
         CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
@@ -681,78 +681,88 @@
         this->terminalHeight_ = screenBufferInfo.dwSize.Y;
     }
 
+    //! Writes arbitrary text to the console with a certain colour and screen buffer position
     void IOConsole::writeText(const std::string& text, const COORD& coord, WORD attributes)
     {
         DWORD count;
         WriteConsoleOutputCharacter(stdOutHandle_, text.c_str(), text.size(), coord, &count);
-        WORD* attributeBuf = new WORD[text.size()];
-        for (unsigned int i = 0; i < text.size(); ++i)
-            attributeBuf[i] = attributes;
-        WriteConsoleOutputAttribute(stdOutHandle_, attributeBuf, text.size(), coord, &count);
+        FillConsoleOutputAttribute(stdOutHandle_, attributes, text.size(), coord, &count);
     }
 
-    void IOConsole::createNewOutputLines(unsigned int lines)
+    /** Scrolls the console screen buffer to create empty lines above the input line.
+    @details
+        If the input and status lines are already at the bottom of the screen buffer
+        the whole output gets scrolled up. In the other case the input and status
+        lines get scrolled down.
+        In any case the status and input lines get scrolled down as far as possible.
+    @param lines
+        Number of lines to be inserted. Behavior for negative values is undefined.
+    */
+    void IOConsole::createNewOutputLines(int lines)
     {
         CHAR_INFO fillChar = {' ', FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};
-        // Check whether we're already at the bottom
-        if (this->inputLineRow_ + lines > this->terminalHeight_ - this->statusLines_ - this->inputLineHeight_)
+        // Lines to scroll input/status down (if possible)
+        int linesDown = clamp(terminalHeight_ - inputLineRow_ - inputLineHeight_ - statusLines_, 0, lines);
+        if (linesDown > 0)
         {
-            // Scroll output up
-            SMALL_RECT oldRect = {0, lines, this->terminalWidth_ - 1, this->inputLineRow_ - 1};
-            COORD newPos = {0, 0};
-            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, newPos, &fillChar);
-        }
-        else
-        {
             // Scroll input and status lines down
-            SMALL_RECT oldRect = {0, this->inputLineRow_, this->terminalWidth_ - 1, this->inputLineRow_ + this->statusLines_ + this->inputLineHeight_ - 1};
-            this->inputLineRow_ += lines;
-            COORD newPos = {0, this->inputLineRow_};
-            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, newPos, &fillChar);
+            SMALL_RECT oldRect = {0, this->inputLineRow_,
+                this->terminalWidth_ - 1, this->inputLineRow_ + this->inputLineHeight_ + this->statusLines_ - 1};
+            this->inputLineRow_ += linesDown;
+            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, this->inputLineRow_), &fillChar);
             // Move cursor down to the new bottom so the user can see the status lines
             COORD pos = {0, this->inputLineRow_ + this->inputLineHeight_ - 1 + this->statusLines_};
             SetConsoleCursorPosition(stdOutHandle_, pos);
             // Get cursor back to the right position
             this->cursorChanged();
         }
+        // Check how many lines we still have to scroll up the output
+        if (lines - linesDown > 0)
+        {
+            // Scroll output up
+            SMALL_RECT oldRect = {0, lines - linesDown, this->terminalWidth_ - 1, this->inputLineRow_ - 1};
+            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, 0), &fillChar);
+        }
     }
 
     // ###############################
     // ###  ShellListener methods  ###
     // ###############################
 
-    //! Called if the text in the input-line has changed
+    //! Called if the text in the input line has changed
     void IOConsole::inputChanged()
     {
-        int inputLineLength = this->promptString_.size() + this->shell_->getInput().size();
-        int lineHeight = 1 + inputLineLength / this->terminalWidth_;
-        int newLines = lineHeight - this->inputLineHeight_;
+        int newInputLineLength = this->promptString_.size() + this->shell_->getInput().size();
+        int newInputLineHeight = 1 + newInputLineLength / this->terminalWidth_;
+        int newLines = newInputLineHeight - this->inputLineHeight_;
         if (newLines > 0)
         {
             // Abuse this function to scroll the console
             this->createNewOutputLines(newLines);
-            this->inputLineRow_ -= newLines; // Undo
+            // Either Compensate for side effects (input/status lines scrolled down)
+            // or we have to do this anyway (output scrolled up)
+            this->inputLineRow_ -= newLines;
         }
         else if (newLines < 0)
         {
             // Scroll status lines up
-            SMALL_RECT oldRect = {0, this->inputLineRow_ + this->inputLineHeight_, this->terminalWidth_ - 1, this->inputLineRow_ + this->inputLineHeight_ + this->statusLines_};
-            COORD newPos = {0, this->inputLineRow_ + this->inputLineHeight_ + newLines};
+            int statusLineRow = this->inputLineRow_ + this->inputLineHeight_;
+            SMALL_RECT oldRect = {0, statusLineRow, this->terminalWidth_ - 1, statusLineRow + this->statusLines_};
             CHAR_INFO fillChar = {' ', FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};
-            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, newPos, &fillChar);
+            ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, statusLineRow + newLines), &fillChar);
             // Clear potential leftovers
             if (-newLines - this->statusLines_ > 0)
             {
-                COORD pos = {0, this->inputLineRow_ + lineHeight + this->statusLines_};
+                COORD pos = {0, this->inputLineRow_ + newInputLineHeight + this->statusLines_};
                 this->writeText(std::string((-newLines - this->statusLines_) * this->terminalWidth_, ' '), pos);
             }
         }
-        this->inputLineHeight_ = lineHeight;
+        this->inputLineHeight_ = newInputLineHeight;
 
-        // Print the whole line, including spaces to erase leftovers
-        COORD pos = {0, this->inputLineRow_};
-        WORD colour = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
-        this->writeText(this->promptString_ + this->shell_->getInput() + std::string(this->terminalWidth_ - inputLineLength % this->terminalWidth_, ' '), pos, colour);
+        // Print the whole line, including spaces that erase leftovers
+        std::string inputLine = this->promptString_ + this->shell_->getInput();
+        inputLine += std::string(this->terminalWidth_ - newInputLineLength % this->terminalWidth_, ' ');
+        this->writeText(inputLine, makeCOORD(0, this->inputLineRow_), FOREGROUND_GREEN | FOREGROUND_INTENSITY);
         // If necessary, move cursor
         if (newLines != 0)
             this->cursorChanged();
@@ -761,34 +771,33 @@
     //! Called if the position of the cursor in the input-line has changed
     void IOConsole::cursorChanged()
     {
+        int rawCursorPos = this->promptString_.size() + this->buffer_->getCursorPosition();
+        // Compensate for cursor further to the right than the terminal width
         COORD pos;
-        unsigned int total = this->promptString_.size() + this->buffer_->getCursorPosition();
-        // Compensate for cursor further to the right than the terminal width
-        pos.X = total % this->terminalWidth_;
-        pos.Y = this->inputLineRow_ + total / this->terminalWidth_;
+        pos.X = rawCursorPos % this->terminalWidth_;
+        pos.Y = this->inputLineRow_ + rawCursorPos / this->terminalWidth_;
         SetConsoleCursorPosition(stdOutHandle_, pos);
     }
 
     //! Called if only the last output-line has changed
     void IOConsole::onlyLastLineChanged()
     {
-        int lineHeight = 1 + this->shell_->getNewestLineIterator()->size() / this->terminalWidth_;
-        int newLines = lineHeight - this->lastOutputLineHeight_;
-        this->lastOutputLineHeight_ = lineHeight;
-        if (newLines > 0)
+        int newLineHeight = 1 + this->shell_->getNewestLineIterator()->size() / this->terminalWidth_;
+        // Compute the number of new lines needed
+        int newLines = newLineHeight - this->lastOutputLineHeight_;
+        this->lastOutputLineHeight_ = newLineHeight;
+        // Scroll console if necessary
+        if (newLines > 0) // newLines < 0 is assumed impossible
             this->createNewOutputLines(newLines);
-        // Write text (assuming it is longer than the previous text)
-        assert(newLines >= 0);
-        COORD pos = {0, this->inputLineRow_ - lineHeight};
-        this->printOutputLine(*(this->shell_->getNewestLineIterator()), pos);
+        this->printOutputLine(*(this->shell_->getNewestLineIterator()), makeCOORD(0, this->inputLineRow_ - newLineHeight));
     }
 
-    //! Called if a new output-line was added
+    //! Called if a new output line was added
     void IOConsole::lineAdded()
     {
+        // Scroll console
         this->lastOutputLineHeight_ = 1 + this->shell_->getNewestLineIterator()->size() / this->terminalWidth_;
-        if (this->lastOutputLineHeight_ > 0)
-            this->createNewOutputLines(this->lastOutputLineHeight_);
+        this->createNewOutputLines(this->lastOutputLineHeight_);
         // Write the text
         COORD pos = {0, this->inputLineRow_ - this->lastOutputLineHeight_};
         this->printOutputLine(*(this->shell_->getNewestLineIterator()), pos);

Modified: code/branches/presentation2/src/libraries/core/IOConsole.h
===================================================================
--- code/branches/presentation2/src/libraries/core/IOConsole.h	2009-11-29 13:47:54 UTC (rev 6177)
+++ code/branches/presentation2/src/libraries/core/IOConsole.h	2009-11-29 20:25:11 UTC (rev 6178)
@@ -61,9 +61,8 @@
     private:
         void setTerminalMode();
         void getTerminalSize();
-        int extractLogLevel(std::string* text);
-
         void printStatusLines();
+        static int extractLogLevel(std::string* text);
 
         // Methods from ShellListener
         void linesChanged();
@@ -73,43 +72,50 @@
         void cursorChanged();
         void executed();
         void exit();
+
         Shell*                  shell_;
         InputBuffer*            buffer_;
         std::ostream            cout_;
         std::ostringstream      origCout_;
-        unsigned int            terminalWidth_;
-        unsigned int            terminalHeight_;
-        unsigned int            lastTerminalWidth_;
-        unsigned int            lastTerminalHeight_;
+        int                     terminalWidth_;
+        int                     terminalHeight_;
+        int                     lastTerminalWidth_;
+        int                     lastTerminalHeight_;
         const std::string       promptString_;
 
 #ifdef ORXONOX_PLATFORM_UNIX
         bool willPrintStatusLines();
+        void printInputLine();
         void printOutputLine(const std::string& line);
-        void printInputLine();
         static void resetTerminalMode();
 
         bool                    bPrintStatusLine_;
         bool                    bStatusPrinted_;
-        std::vector<unsigned>   statusLineWidths_;
-        unsigned int            statusLineMaxWidth_;
-        static const unsigned   minOutputLines_ = 3;
+        std::vector<int>        statusLineWidths_;
+        int                     statusLineMaxWidth_;
+        static const            minOutputLines_ = 3;
         termios*                originalTerminalSettings_;
 
 #elif defined(ORXONOX_PLATFORM_WINDOWS)
         void resetTerminalMode();
         void moveCursor(int dx, int dy);
         void writeText(const std::string& text, const COORD& pos, WORD attributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
-        void createNewOutputLines(unsigned int lines);
+        void createNewOutputLines(int lines);
         void printOutputLine(const std::string& line, const COORD& pos);
 
+        static inline COORD makeCOORD(int x, int y)
+        {
+            COORD val = {x, y};
+            return val;
+        }
+
         DWORD                   originalTerminalSettings_;
         HANDLE                  stdInHandle_;
         HANDLE                  stdOutHandle_;
         int                     inputLineRow_;
-        unsigned int            inputLineHeight_;
-        const unsigned int      statusLines_;
-        unsigned int            lastOutputLineHeight_;
+        int                     inputLineHeight_;
+        const int               statusLines_;
+        int                     lastOutputLineHeight_;
         uint64_t                lastRefreshTime_;
 #endif
 




More information about the Orxonox-commit mailing list