ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

console.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "gui/console.h"
00024 #include "gui/widgets/scrollbar.h"
00025 #include "gui/ThemeEval.h"
00026 #include "gui/gui-manager.h"
00027 
00028 #include "base/version.h"
00029 
00030 #include "common/system.h"
00031 
00032 #include "graphics/fontman.h"
00033 
00034 namespace GUI {
00035 
00036 #define kConsoleCharWidth  (_font->getCharWidth('M'))
00037 #define kConsoleLineHeight (_font->getFontHeight())
00038 
00039 enum {
00040     kConsoleSlideDownDuration = 200 // Time in milliseconds
00041 };
00042 
00043 
00044 #define PROMPT  ") "
00045 
00046 /* TODO:
00047  * - it is very inefficient to redraw the full thingy when just one char is added/removed.
00048  *   Instead, we could just copy the GFX of the blank console (i.e. after the transparent
00049  *   background is drawn, before any text is drawn). Then using that, it becomes trivial
00050  *   to erase a single character, do scrolling etc.
00051  * - a *lot* of others things, this code is in no way complete and heavily under progress
00052  */
00053 ConsoleDialog::ConsoleDialog(float widthPercent, float heightPercent)
00054     : Dialog(0, 0, 1, 1),
00055     _widthPercent(widthPercent), _heightPercent(heightPercent) {
00056 
00057     // Reset the line buffer
00058     memset(_buffer, ' ', kBufferSize);
00059 
00060     // Dummy
00061     _scrollBar = new ScrollBarWidget(this, 0, 0, 5, 10);
00062     _scrollBar->setTarget(this);
00063 
00064     init();
00065 
00066     _currentPos = 0;
00067     _scrollLine = _linesPerPage - 1;
00068     _firstLineInBuffer = 0;
00069 
00070     _caretVisible = false;
00071     _caretTime = 0;
00072 
00073     _slideMode = kNoSlideMode;
00074     _slideTime = 0;
00075 
00076     _promptStartPos = _promptEndPos = -1;
00077 
00078     // Init callback
00079     _callbackProc = 0;
00080     _callbackRefCon = 0;
00081 
00082     // Init History
00083     _historyIndex = 0;
00084     _historyLine = 0;
00085     _historySize = 0;
00086 
00087     // Display greetings & prompt
00088     print(gScummVMFullVersion);
00089     print("\nConsole is ready\n");
00090 }
00091 
00092 void ConsoleDialog::init() {
00093     const int screenW = g_system->getOverlayWidth();
00094     const int screenH = g_system->getOverlayHeight();
00095 
00096     _font = &g_gui.getFont(ThemeEngine::kFontStyleConsole);
00097 
00098     _leftPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Left", 0);
00099     _rightPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Right", 0);
00100     _topPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Top", 0);
00101     _bottomPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Bottom", 0);
00102 
00103     // Calculate the real width/height (rounded to char/line multiples)
00104     _w = (uint16)(_widthPercent * screenW);
00105     _h = (uint16)((_heightPercent * screenH - 2) / kConsoleLineHeight);
00106 
00107     _w = _w - _w / 20;
00108     _h = _h * kConsoleLineHeight + 2;
00109     _x = _w / 40;
00110 
00111     // Set scrollbar dimensions
00112     int scrollBarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
00113     _scrollBar->resize(_w - scrollBarWidth - 1, 0, scrollBarWidth, _h);
00114 
00115     _pageWidth = (_w - scrollBarWidth - 2 - _leftPadding - _topPadding - scrollBarWidth) / kConsoleCharWidth;
00116     _linesPerPage = (_h - 2 - _topPadding - _bottomPadding) / kConsoleLineHeight;
00117     _linesInBuffer = kBufferSize / kCharsPerLine;
00118 }
00119 
00120 void ConsoleDialog::slideUpAndClose() {
00121     if (_slideMode == kNoSlideMode) {
00122         _slideTime = g_system->getMillis();
00123         _slideMode = kUpSlideMode;
00124     }
00125 }
00126 
00127 void ConsoleDialog::open() {
00128     // TODO: find a new way to do this
00129     // Initiate sliding the console down. We do a very simple trick to achieve
00130     // this effect: we simply move the console dialog just above (outside) the
00131     // visible screen area, then shift it down in handleTickle() over a
00132     // certain period of time.
00133 
00134     const int screenW = g_system->getOverlayWidth();
00135     const int screenH = g_system->getOverlayHeight();
00136 
00137     // Calculate the real width/height (rounded to char/line multiples)
00138     uint16 w = (uint16)(_widthPercent * screenW);
00139     uint16 h = (uint16)((_heightPercent * screenH - 2) / kConsoleLineHeight);
00140 
00141     h = h * kConsoleLineHeight + 2;
00142     w = w - w / 20;
00143 
00144     if (_w != w || _h != h)
00145         init();
00146 
00147     _y = -_h;
00148 
00149     _slideTime = g_system->getMillis();
00150     _slideMode = kDownSlideMode;
00151 
00152     Dialog::open();
00153     if ((_promptStartPos == -1) || (_currentPos > _promptEndPos)) {
00154         // we print a prompt, if this is the first time we are called or if the
00155         //  engine wrote onto us since the last call
00156         print(PROMPT);
00157         _promptStartPos = _promptEndPos = _currentPos;
00158     }
00159 }
00160 
00161 void ConsoleDialog::close() {
00162     Dialog::close();
00163 }
00164 
00165 void ConsoleDialog::drawDialog(DrawLayer layerToDraw) {
00166     Dialog::drawDialog(layerToDraw);
00167 
00168     for (int line = 0; line < _linesPerPage; line++)
00169         drawLine(line);
00170 }
00171 
00172 void ConsoleDialog::drawLine(int line) {
00173     int x = _x + 1 + _leftPadding;
00174     int start = _scrollLine - _linesPerPage + 1;
00175     int y = _y + 2 + _topPadding;
00176     int limit = MIN(_pageWidth, (int)kCharsPerLine);
00177 
00178     y += line * kConsoleLineHeight;
00179 
00180     for (int column = 0; column < limit; column++) {
00181 #if 0
00182         int l = (start + line) % _linesInBuffer;
00183         byte c = buffer(l * kCharsPerLine + column);
00184 #else
00185         byte c = buffer((start + line) * kCharsPerLine + column);
00186 #endif
00187         g_gui.theme()->drawChar(Common::Rect(x, y, x+kConsoleCharWidth, y+kConsoleLineHeight), c, _font);
00188         x += kConsoleCharWidth;
00189     }
00190 }
00191 
00192 void ConsoleDialog::reflowLayout() {
00193     init();
00194 
00195     _scrollLine = _promptEndPos / kCharsPerLine;
00196     if (_scrollLine < _linesPerPage - 1)
00197         _scrollLine = _linesPerPage - 1;
00198     updateScrollBuffer();
00199 
00200     Dialog::reflowLayout();
00201     g_gui.scheduleTopDialogRedraw();
00202 }
00203 
00204 void ConsoleDialog::handleTickle() {
00205     uint32 time = g_system->getMillis();
00206     if (_caretTime < time) {
00207         _caretTime = time + kCaretBlinkTime;
00208         drawCaret(_caretVisible);
00209     }
00210 
00211     // Perform the "slide animation".
00212     if (_slideMode != kNoSlideMode) {
00213         const float tmp = (float)(g_system->getMillis() - _slideTime) / kConsoleSlideDownDuration;
00214         if (_slideMode == kUpSlideMode) {
00215             _y = (int)(_h * (0.0 - tmp));
00216         } else {
00217             _y = (int)(_h * (tmp - 1.0));
00218         }
00219 
00220         if (_slideMode == kDownSlideMode && _y > 0) {
00221             // End the slide
00222             _slideMode = kNoSlideMode;
00223             _y = 0;
00224             g_gui.scheduleTopDialogRedraw();
00225         } else if (_slideMode == kUpSlideMode && _y <= -_h) {
00226             // End the slide
00227             //_slideMode = kNoSlideMode;
00228             close();
00229         } else
00230             g_gui.scheduleTopDialogRedraw();
00231     }
00232 
00233     _scrollBar->handleTickle();
00234 }
00235 
00236 void ConsoleDialog::handleMouseWheel(int x, int y, int direction) {
00237     _scrollBar->handleMouseWheel(x, y, direction);
00238 }
00239 
00240 Common::String ConsoleDialog::getUserInput() {
00241     assert(_promptEndPos >= _promptStartPos);
00242     int len = _promptEndPos - _promptStartPos;
00243 
00244     // Copy the user input to str
00245     Common::String str;
00246     for (int i = 0; i < len; i++)
00247         str.insertChar(buffer(_promptStartPos + i), i);
00248 
00249     return str;
00250 }
00251 
00252 void ConsoleDialog::handleKeyDown(Common::KeyState state) {
00253     if (_slideMode != kNoSlideMode)
00254         return;
00255 
00256     switch (state.keycode) {
00257     case Common::KEYCODE_RETURN:
00258     case Common::KEYCODE_KP_ENTER: {
00259         if (_caretVisible)
00260             drawCaret(true);
00261 
00262         nextLine();
00263 
00264         bool keepRunning = true;
00265 
00266         Common::String userInput = getUserInput();
00267         if (!userInput.empty()) {
00268             // Add the input to the history
00269             addToHistory(userInput);
00270 
00271             // Pass it to the input callback, if any
00272             if (_callbackProc)
00273                 keepRunning = (*_callbackProc)(this, userInput.c_str(), _callbackRefCon);
00274         }
00275 
00276         print(PROMPT);
00277         _promptStartPos = _promptEndPos = _currentPos;
00278 
00279         g_gui.scheduleTopDialogRedraw();
00280         if (!keepRunning)
00281             slideUpAndClose();
00282         break;
00283         }
00284 
00285     case Common::KEYCODE_ESCAPE:
00286         slideUpAndClose();
00287         break;
00288 
00289     case Common::KEYCODE_BACKSPACE:
00290         if (_caretVisible)
00291             drawCaret(true);
00292 
00293         if (_currentPos > _promptStartPos) {
00294             _currentPos--;
00295             killChar();
00296         }
00297         scrollToCurrent();
00298         drawLine(pos2line(_currentPos));
00299         break;
00300 
00301     case Common::KEYCODE_TAB: {
00302         if (_completionCallbackProc) {
00303             int len = _currentPos - _promptStartPos;
00304             assert(len >= 0);
00305             char *str = new char[len + 1];
00306 
00307             // Copy the user input to str
00308             for (int i = 0; i < len; i++)
00309                 str[i] = buffer(_promptStartPos + i);
00310             str[len] = '\0';
00311 
00312             Common::String completion;
00313             if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon)) {
00314                 if (_caretVisible)
00315                     drawCaret(true);
00316                 insertIntoPrompt(completion.c_str());
00317                 scrollToCurrent();
00318                 drawLine(pos2line(_currentPos));
00319             }
00320             delete[] str;
00321         }
00322         break;
00323         }
00324 
00325     // Keypad & special keys
00326     //   - if num lock is set, we always go to the default case
00327     //   - if num lock is not set, we either fall down to the special key case
00328     //     or ignore the key press in case of 0 (INSERT) or 5
00329 
00330     case Common::KEYCODE_KP0:
00331     case Common::KEYCODE_KP5:
00332         if (state.flags & Common::KBD_NUM)
00333             defaultKeyDownHandler(state);
00334         break;
00335 
00336     case Common::KEYCODE_KP_PERIOD:
00337         if (state.flags & Common::KBD_NUM) {
00338             defaultKeyDownHandler(state);
00339             break;
00340         }
00341         // fall through
00342     case Common::KEYCODE_DELETE:
00343         if (_currentPos < _promptEndPos) {
00344             killChar();
00345             drawLine(pos2line(_currentPos));
00346         }
00347         break;
00348 
00349     case Common::KEYCODE_KP1:
00350         if (state.flags & Common::KBD_NUM) {
00351             defaultKeyDownHandler(state);
00352             break;
00353         }
00354         // fall through
00355     case Common::KEYCODE_END:
00356         if (state.hasFlags(Common::KBD_SHIFT)) {
00357             _scrollLine = _promptEndPos / kCharsPerLine;
00358             if (_scrollLine < _linesPerPage - 1)
00359                 _scrollLine = _linesPerPage - 1;
00360             updateScrollBuffer();
00361         } else {
00362             _currentPos = _promptEndPos;
00363         }
00364         g_gui.scheduleTopDialogRedraw();
00365         break;
00366 
00367     case Common::KEYCODE_KP2:
00368         if (state.flags & Common::KBD_NUM) {
00369             defaultKeyDownHandler(state);
00370             break;
00371         }
00372         // fall through
00373     case Common::KEYCODE_DOWN:
00374         historyScroll(-1);
00375         break;
00376 
00377     case Common::KEYCODE_KP3:
00378         if (state.flags & Common::KBD_NUM) {
00379             defaultKeyDownHandler(state);
00380             break;
00381         }
00382         // fall through
00383     case Common::KEYCODE_PAGEDOWN:
00384         if (state.hasFlags(Common::KBD_SHIFT)) {
00385             _scrollLine += _linesPerPage - 1;
00386             if (_scrollLine > _promptEndPos / kCharsPerLine) {
00387                 _scrollLine = _promptEndPos / kCharsPerLine;
00388                 if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
00389                     _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00390             }
00391             updateScrollBuffer();
00392             g_gui.scheduleTopDialogRedraw();
00393         }
00394         break;
00395 
00396     case Common::KEYCODE_KP4:
00397         if (state.flags & Common::KBD_NUM) {
00398             defaultKeyDownHandler(state);
00399             break;
00400         }
00401         // fall through
00402     case Common::KEYCODE_LEFT:
00403         if (_currentPos > _promptStartPos)
00404             _currentPos--;
00405         drawLine(pos2line(_currentPos));
00406         break;
00407 
00408     case Common::KEYCODE_KP6:
00409         if (state.flags & Common::KBD_NUM) {
00410             defaultKeyDownHandler(state);
00411             break;
00412         }
00413         // fall through
00414     case Common::KEYCODE_RIGHT:
00415         if (_currentPos < _promptEndPos)
00416             _currentPos++;
00417         drawLine(pos2line(_currentPos));
00418         break;
00419 
00420     case Common::KEYCODE_KP7:
00421         if (state.flags & Common::KBD_NUM) {
00422             defaultKeyDownHandler(state);
00423             break;
00424         }
00425         // fall through
00426     case Common::KEYCODE_HOME:
00427         if (state.hasFlags(Common::KBD_SHIFT)) {
00428             _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00429             updateScrollBuffer();
00430         } else {
00431             _currentPos = _promptStartPos;
00432         }
00433         g_gui.scheduleTopDialogRedraw();
00434         break;
00435 
00436     case Common::KEYCODE_KP8:
00437         if (state.flags & Common::KBD_NUM) {
00438             defaultKeyDownHandler(state);
00439             break;
00440         }
00441         // fall through
00442     case Common::KEYCODE_UP:
00443         historyScroll(+1);
00444         break;
00445 
00446     case Common::KEYCODE_KP9:
00447         if (state.flags & Common::KBD_NUM) {
00448             defaultKeyDownHandler(state);
00449             break;
00450         }
00451         // fall through
00452     case Common::KEYCODE_PAGEUP:
00453         if (state.hasFlags(Common::KBD_SHIFT)) {
00454             _scrollLine -= _linesPerPage - 1;
00455             if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
00456                 _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00457             updateScrollBuffer();
00458             g_gui.scheduleTopDialogRedraw();
00459         }
00460         break;
00461 
00462     default:
00463         defaultKeyDownHandler(state);
00464     }
00465 }
00466 
00467 void ConsoleDialog::defaultKeyDownHandler(Common::KeyState &state) {
00468     if (state.hasFlags(Common::KBD_CTRL)) {
00469         specialKeys(state.keycode);
00470     } else if ((state.ascii >= 32 && state.ascii <= 127) || (state.ascii >= 160 && state.ascii <= 255)) {
00471         for (int i = _promptEndPos - 1; i >= _currentPos; i--)
00472             buffer(i + 1) = buffer(i);
00473         _promptEndPos++;
00474         printChar((byte)state.ascii);
00475         scrollToCurrent();
00476     }
00477 }
00478 
00479 void ConsoleDialog::insertIntoPrompt(const char* str) {
00480     unsigned int l = strlen(str);
00481     for (int i = _promptEndPos - 1; i >= _currentPos; i--)
00482         buffer(i + l) = buffer(i);
00483     for (unsigned int j = 0; j < l; ++j) {
00484         _promptEndPos++;
00485         printCharIntern(str[j]);
00486     }
00487 }
00488 
00489 void ConsoleDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00490     switch (cmd) {
00491     case kSetPositionCmd:
00492         int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer;
00493         if (newPos != _scrollLine) {
00494             _scrollLine = newPos;
00495             g_gui.scheduleTopDialogRedraw();
00496         }
00497         break;
00498     }
00499 }
00500 
00501 void ConsoleDialog::specialKeys(Common::KeyCode keycode) {
00502     switch (keycode) {
00503     case Common::KEYCODE_a:
00504         _currentPos = _promptStartPos;
00505         g_gui.scheduleTopDialogRedraw();
00506         break;
00507     case Common::KEYCODE_d:
00508         if (_currentPos < _promptEndPos) {
00509             killChar();
00510             g_gui.scheduleTopDialogRedraw();
00511         }
00512         break;
00513     case Common::KEYCODE_e:
00514         _currentPos = _promptEndPos;
00515         g_gui.scheduleTopDialogRedraw();
00516         break;
00517     case Common::KEYCODE_k:
00518         killLine();
00519         g_gui.scheduleTopDialogRedraw();
00520         break;
00521     case Common::KEYCODE_w:
00522         killLastWord();
00523         g_gui.scheduleTopDialogRedraw();
00524         break;
00525     case Common::KEYCODE_v:
00526         if (g_system->hasFeature(OSystem::kFeatureClipboardSupport) && g_system->hasTextInClipboard()) {
00527             Common::String text = g_system->getTextFromClipboard();
00528             insertIntoPrompt(text.c_str());
00529             scrollToCurrent();
00530             drawLine(pos2line(_currentPos));
00531         }
00532         break;
00533     case Common::KEYCODE_c:
00534         if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
00535             Common::String userInput = getUserInput();
00536             if (!userInput.empty())
00537                 g_system->setTextInClipboard(userInput);
00538         }
00539         break;
00540     default:
00541         break;
00542     }
00543 }
00544 
00545 void ConsoleDialog::killChar() {
00546     for (int i = _currentPos; i < _promptEndPos; i++)
00547         buffer(i) = buffer(i + 1);
00548     if (_promptEndPos > _promptStartPos) {
00549         buffer(_promptEndPos) = ' ';
00550         _promptEndPos--;
00551     }
00552 }
00553 
00554 void ConsoleDialog::killLine() {
00555     for (int i = _currentPos; i < _promptEndPos; i++)
00556         buffer(i) = ' ';
00557     _promptEndPos = _currentPos;
00558 }
00559 
00560 void ConsoleDialog::killLastWord() {
00561     int cnt = 0;
00562     bool space = true;
00563     while (_currentPos > _promptStartPos) {
00564         if (buffer(_currentPos - 1) == ' ') {
00565             if (!space)
00566                 break;
00567         } else
00568             space = false;
00569         _currentPos--;
00570         cnt++;
00571     }
00572 
00573     for (int i = _currentPos; i < _promptEndPos; i++)
00574         buffer(i) = buffer(i + cnt);
00575     if (_promptEndPos > _promptStartPos) {
00576         buffer(_promptEndPos) = ' ';
00577         _promptEndPos -= cnt;
00578     }
00579 }
00580 
00581 void ConsoleDialog::addToHistory(const Common::String &str) {
00582     _history[_historyIndex] = str;
00583     _historyIndex = (_historyIndex + 1) % kHistorySize;
00584     _historyLine = 0;
00585     if (_historySize < kHistorySize)
00586         _historySize++;
00587 }
00588 
00589 void ConsoleDialog::historyScroll(int direction) {
00590     if (_historySize == 0)
00591         return;
00592 
00593     if (_historyLine == 0 && direction > 0) {
00594         int i;
00595         for (i = 0; i < _promptEndPos - _promptStartPos; i++)
00596             _history[_historyIndex].insertChar(buffer(_promptStartPos + i), i);
00597     }
00598 
00599     // Advance to the next line in the history
00600     int line = _historyLine + direction;
00601     if ((direction < 0 && line < 0) || (direction > 0 && line > _historySize))
00602         return;
00603     _historyLine = line;
00604 
00605     // Hide caret if visible
00606     if (_caretVisible)
00607         drawCaret(true);
00608 
00609     // Remove the current user text
00610     _currentPos = _promptStartPos;
00611     killLine();
00612 
00613     // ... and ensure the prompt is visible
00614     scrollToCurrent();
00615 
00616     // Print the text from the history
00617     int idx;
00618     if (_historyLine > 0)
00619         idx = (_historyIndex - _historyLine + _historySize) % _historySize;
00620     else
00621         idx = _historyIndex;
00622     int length = _history[idx].size();
00623     for (int i = 0; i < length; i++)
00624         printCharIntern(_history[idx][i]);
00625     _promptEndPos = _currentPos;
00626 
00627     // Ensure once more the caret is visible (in case of very long history entries)
00628     scrollToCurrent();
00629 
00630     g_gui.scheduleTopDialogRedraw();
00631 }
00632 
00633 void ConsoleDialog::nextLine() {
00634     int line = _currentPos / kCharsPerLine;
00635     if (line == _scrollLine)
00636         _scrollLine++;
00637     _currentPos = (line + 1) * kCharsPerLine;
00638 
00639     updateScrollBuffer();
00640 }
00641 
00642 
00643 // Call this (at least) when the current line changes or when
00644 // a new line is added
00645 void ConsoleDialog::updateScrollBuffer() {
00646     int lastchar = MAX(_promptEndPos, _currentPos);
00647     int line = lastchar / kCharsPerLine;
00648     int numlines = (line < _linesInBuffer) ? line + 1 : _linesInBuffer;
00649     int firstline = line - numlines + 1;
00650     if (firstline > _firstLineInBuffer) {
00651         // clear old line from buffer
00652         for (int i = lastchar; i < (line+1) * kCharsPerLine; ++i)
00653             buffer(i) = ' ';
00654         _firstLineInBuffer = firstline;
00655     }
00656 
00657     _scrollBar->_numEntries = numlines;
00658     _scrollBar->_currentPos = _scrollBar->_numEntries - (line - _scrollLine + _linesPerPage);
00659     _scrollBar->_entriesPerPage = _linesPerPage;
00660     _scrollBar->recalc();
00661 }
00662 
00663 int ConsoleDialog::printFormat(int dummy, const char *format, ...) {
00664     va_list argptr;
00665 
00666     va_start(argptr, format);
00667     int count = this->vprintFormat(dummy, format, argptr);
00668     va_end (argptr);
00669     return count;
00670 }
00671 
00672 int ConsoleDialog::vprintFormat(int dummy, const char *format, va_list argptr) {
00673     Common::String buf = Common::String::vformat(format, argptr);
00674 
00675     print(buf.c_str());
00676 
00677     return buf.size();
00678 }
00679 
00680 void ConsoleDialog::printChar(int c) {
00681     if (_caretVisible)
00682         drawCaret(true);
00683 
00684     printCharIntern(c);
00685     drawLine(pos2line(_currentPos));
00686 }
00687 
00688 void ConsoleDialog::printCharIntern(int c) {
00689     if (c == '\n')
00690         nextLine();
00691     else {
00692         buffer(_currentPos) = (char)c;
00693         _currentPos++;
00694         if ((_scrollLine + 1) * kCharsPerLine == _currentPos) {
00695             _scrollLine++;
00696             updateScrollBuffer();
00697         }
00698     }
00699 }
00700 
00701 void ConsoleDialog::print(const char *str) {
00702     if (_caretVisible)
00703         drawCaret(true);
00704 
00705     while (*str)
00706         printCharIntern(*str++);
00707 
00708     g_gui.scheduleTopDialogRedraw();
00709 }
00710 
00711 void ConsoleDialog::drawCaret(bool erase) {
00712     // TODO: use code from EditableWidget::drawCaret here
00713     int line = _currentPos / kCharsPerLine;
00714     int displayLine = line - _scrollLine + _linesPerPage - 1;
00715 
00716     // Only draw caret if visible
00717     if (!isVisible() || displayLine < 0 || displayLine >= _linesPerPage) {
00718         _caretVisible = false;
00719         return;
00720     }
00721 
00722     int x = _x + 1 + _leftPadding + (_currentPos % kCharsPerLine) * kConsoleCharWidth;
00723     int y = _y + 2 + _topPadding + displayLine * kConsoleLineHeight;
00724 
00725     _caretVisible = !erase;
00726     g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + kConsoleLineHeight), erase);
00727 }
00728 
00729 void ConsoleDialog::scrollToCurrent() {
00730     int line = _promptEndPos / kCharsPerLine;
00731 
00732     if (line + _linesPerPage <= _scrollLine) {
00733         // TODO - this should only occur for loong edit lines, though
00734     } else if (line > _scrollLine) {
00735         _scrollLine = line;
00736         updateScrollBuffer();
00737         g_gui.scheduleTopDialogRedraw();
00738     }
00739 }
00740 
00741 } // End of namespace GUI


Generated on Sat Sep 14 2019 05:01:18 for ResidualVM by doxygen 1.7.1
curved edge   curved edge