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

gui/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->getMaxCharWidth())
00037 #define kConsoleLineHeight  (_font->getFontHeight() + 2)
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 = FontMan.getFontByUsage((Graphics::FontManager::FontUsage)
00097         g_gui.xmlEval()->getVar("Console.Font", Graphics::FontManager::kConsoleFont));
00098 
00099     _leftPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Left", 0);
00100     _rightPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Right", 0);
00101     _topPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Top", 0);
00102     _bottomPadding = g_gui.xmlEval()->getVar("Globals.Console.Padding.Bottom", 0);
00103 
00104     // Calculate the real width/height (rounded to char/line multiples)
00105     _w = (uint16)(_widthPercent * screenW);
00106     _h = (uint16)((_heightPercent * screenH - 2) / kConsoleLineHeight);
00107 
00108     _w = _w - _w / 20;
00109     _h = _h * kConsoleLineHeight + 2;
00110     _x = _w / 40;
00111 
00112     // Set scrollbar dimensions
00113     int scrollBarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0);
00114     _scrollBar->resize(_w - scrollBarWidth - 1, 0, scrollBarWidth, _h);
00115 
00116     _pageWidth = (_w - scrollBarWidth - 2 - _leftPadding - _topPadding - scrollBarWidth) / kConsoleCharWidth;
00117     _linesPerPage = (_h - 2 - _topPadding - _bottomPadding) / kConsoleLineHeight;
00118     _linesInBuffer = kBufferSize / kCharsPerLine;
00119 }
00120 
00121 void ConsoleDialog::slideUpAndClose() {
00122     if (_slideMode == kNoSlideMode) {
00123         _slideTime = g_system->getMillis();
00124         _slideMode = kUpSlideMode;
00125     }
00126 }
00127 
00128 void ConsoleDialog::open() {
00129     // TODO: find a new way to do this
00130     // Initiate sliding the console down. We do a very simple trick to achieve
00131     // this effect: we simply move the console dialog just above (outside) the
00132     // visible screen area, then shift it down in handleTickle() over a
00133     // certain period of time.
00134 
00135     const int screenW = g_system->getOverlayWidth();
00136     const int screenH = g_system->getOverlayHeight();
00137 
00138     // Calculate the real width/height (rounded to char/line multiples)
00139     uint16 w = (uint16)(_widthPercent * screenW);
00140     uint16 h = (uint16)((_heightPercent * screenH - 2) / kConsoleLineHeight);
00141 
00142     h = h * kConsoleLineHeight + 2;
00143     w = w - w / 20;
00144 
00145     if (_w != w || _h != h)
00146         init();
00147 
00148     _y = -_h;
00149 
00150     _slideTime = g_system->getMillis();
00151     _slideMode = kDownSlideMode;
00152 
00153     Dialog::open();
00154     if ((_promptStartPos == -1) || (_currentPos > _promptEndPos)) {
00155         // we print a prompt, if this is the first time we are called or if the
00156         //  engine wrote onto us since the last call
00157         print(PROMPT);
00158         _promptStartPos = _promptEndPos = _currentPos;
00159     }
00160 }
00161 
00162 void ConsoleDialog::close() {
00163     Dialog::close();
00164 }
00165 
00166 void ConsoleDialog::drawDialog(DrawLayer layerToDraw) {
00167     Dialog::drawDialog(layerToDraw);
00168 
00169     for (int line = 0; line < _linesPerPage; line++)
00170         drawLine(line, false);
00171 }
00172 
00173 void ConsoleDialog::drawLine(int line, bool restoreBg) {
00174     int x = _x + 1 + _leftPadding;
00175     int start = _scrollLine - _linesPerPage + 1;
00176     int y = _y + 2 + _topPadding;
00177     int limit = MIN(_pageWidth, (int)kCharsPerLine);
00178 
00179     y += line * kConsoleLineHeight;
00180 
00181     if (restoreBg) {
00182         Common::Rect r(_x, y - 2, _x + _pageWidth * kConsoleCharWidth, y+kConsoleLineHeight);
00183         g_gui.theme()->restoreBackground(r);
00184     }
00185 
00186     for (int column = 0; column < limit; column++) {
00187 #if 0
00188         int l = (start + line) % _linesInBuffer;
00189         byte c = buffer(l * kCharsPerLine + column);
00190 #else
00191         byte c = buffer((start + line) * kCharsPerLine + column);
00192 #endif
00193         g_gui.theme()->drawChar(Common::Rect(x, y, x+kConsoleCharWidth, y+kConsoleLineHeight), c, _font);
00194         x += kConsoleCharWidth;
00195     }
00196 }
00197 
00198 void ConsoleDialog::reflowLayout() {
00199     init();
00200 
00201     _scrollLine = _promptEndPos / kCharsPerLine;
00202     if (_scrollLine < _linesPerPage - 1)
00203         _scrollLine = _linesPerPage - 1;
00204     updateScrollBuffer();
00205 
00206     Dialog::reflowLayout();
00207     g_gui.scheduleTopDialogRedraw();
00208 }
00209 
00210 void ConsoleDialog::handleTickle() {
00211     uint32 time = g_system->getMillis();
00212     if (_caretTime < time) {
00213         _caretTime = time + kCaretBlinkTime;
00214         drawCaret(_caretVisible);
00215     }
00216 
00217     // Perform the "slide animation".
00218     if (_slideMode != kNoSlideMode) {
00219         const float tmp = (float)(g_system->getMillis() - _slideTime) / kConsoleSlideDownDuration;
00220         if (_slideMode == kUpSlideMode) {
00221             _y = (int)(_h * (0.0 - tmp));
00222         } else {
00223             _y = (int)(_h * (tmp - 1.0));
00224         }
00225 
00226         if (_slideMode == kDownSlideMode && _y > 0) {
00227             // End the slide
00228             _slideMode = kNoSlideMode;
00229             _y = 0;
00230             g_gui.scheduleTopDialogRedraw();
00231         } else if (_slideMode == kUpSlideMode && _y <= -_h) {
00232             // End the slide
00233             //_slideMode = kNoSlideMode;
00234             close();
00235         } else
00236             g_gui.scheduleTopDialogRedraw();
00237     }
00238 
00239     _scrollBar->handleTickle();
00240 }
00241 
00242 void ConsoleDialog::handleMouseWheel(int x, int y, int direction) {
00243     _scrollBar->handleMouseWheel(x, y, direction);
00244 }
00245 
00246 Common::String ConsoleDialog::getUserInput() {
00247     assert(_promptEndPos >= _promptStartPos);
00248     int len = _promptEndPos - _promptStartPos;
00249 
00250     // Copy the user input to str
00251     Common::String str;
00252     for (int i = 0; i < len; i++)
00253         str.insertChar(buffer(_promptStartPos + i), i);
00254 
00255     return str;
00256 }
00257 
00258 void ConsoleDialog::handleKeyDown(Common::KeyState state) {
00259     if (_slideMode != kNoSlideMode)
00260         return;
00261 
00262     switch (state.keycode) {
00263     case Common::KEYCODE_RETURN:
00264     case Common::KEYCODE_KP_ENTER: {
00265         if (_caretVisible)
00266             drawCaret(true);
00267 
00268         nextLine();
00269 
00270         bool keepRunning = true;
00271 
00272         Common::String userInput = getUserInput();
00273         if (!userInput.empty()) {
00274             // Add the input to the history
00275             addToHistory(userInput);
00276 
00277             // Pass it to the input callback, if any
00278             if (_callbackProc)
00279                 keepRunning = (*_callbackProc)(this, userInput.c_str(), _callbackRefCon);
00280         }
00281 
00282         print(PROMPT);
00283         _promptStartPos = _promptEndPos = _currentPos;
00284 
00285         g_gui.scheduleTopDialogRedraw();
00286         if (!keepRunning)
00287             slideUpAndClose();
00288         break;
00289         }
00290 
00291     case Common::KEYCODE_ESCAPE:
00292         slideUpAndClose();
00293         break;
00294 
00295     case Common::KEYCODE_BACKSPACE:
00296         if (_caretVisible)
00297             drawCaret(true);
00298 
00299         if (_currentPos > _promptStartPos) {
00300             _currentPos--;
00301             killChar();
00302         }
00303         scrollToCurrent();
00304         drawLine(pos2line(_currentPos));
00305         break;
00306 
00307     case Common::KEYCODE_TAB: {
00308         if (_completionCallbackProc) {
00309             int len = _currentPos - _promptStartPos;
00310             assert(len >= 0);
00311             char *str = new char[len + 1];
00312 
00313             // Copy the user input to str
00314             for (int i = 0; i < len; i++)
00315                 str[i] = buffer(_promptStartPos + i);
00316             str[len] = '\0';
00317 
00318             Common::String completion;
00319             if ((*_completionCallbackProc)(this, str, completion, _callbackRefCon)) {
00320                 if (_caretVisible)
00321                     drawCaret(true);
00322                 insertIntoPrompt(completion.c_str());
00323                 scrollToCurrent();
00324                 drawLine(pos2line(_currentPos));
00325             }
00326             delete[] str;
00327         }
00328         break;
00329         }
00330 
00331     // Keypad & special keys
00332     //   - if num lock is set, we always go to the default case
00333     //   - if num lock is not set, we either fall down to the special key case
00334     //     or ignore the key press in case of 0 (INSERT) or 5
00335 
00336     case Common::KEYCODE_KP0:
00337     case Common::KEYCODE_KP5:
00338         if (state.flags & Common::KBD_NUM)
00339             defaultKeyDownHandler(state);
00340         break;
00341 
00342     case Common::KEYCODE_KP_PERIOD:
00343         if (state.flags & Common::KBD_NUM) {
00344             defaultKeyDownHandler(state);
00345             break;
00346         }
00347         // fall through
00348     case Common::KEYCODE_DELETE:
00349         if (_currentPos < _promptEndPos) {
00350             killChar();
00351             drawLine(pos2line(_currentPos));
00352         }
00353         break;
00354 
00355     case Common::KEYCODE_KP1:
00356         if (state.flags & Common::KBD_NUM) {
00357             defaultKeyDownHandler(state);
00358             break;
00359         }
00360         // fall through
00361     case Common::KEYCODE_END:
00362         if (state.hasFlags(Common::KBD_SHIFT)) {
00363             _scrollLine = _promptEndPos / kCharsPerLine;
00364             if (_scrollLine < _linesPerPage - 1)
00365                 _scrollLine = _linesPerPage - 1;
00366             updateScrollBuffer();
00367         } else {
00368             _currentPos = _promptEndPos;
00369         }
00370         g_gui.scheduleTopDialogRedraw();
00371         break;
00372 
00373     case Common::KEYCODE_KP2:
00374         if (state.flags & Common::KBD_NUM) {
00375             defaultKeyDownHandler(state);
00376             break;
00377         }
00378         // fall through
00379     case Common::KEYCODE_DOWN:
00380         historyScroll(-1);
00381         break;
00382 
00383     case Common::KEYCODE_KP3:
00384         if (state.flags & Common::KBD_NUM) {
00385             defaultKeyDownHandler(state);
00386             break;
00387         }
00388         // fall through
00389     case Common::KEYCODE_PAGEDOWN:
00390         if (state.hasFlags(Common::KBD_SHIFT)) {
00391             _scrollLine += _linesPerPage - 1;
00392             if (_scrollLine > _promptEndPos / kCharsPerLine) {
00393                 _scrollLine = _promptEndPos / kCharsPerLine;
00394                 if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
00395                     _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00396             }
00397             updateScrollBuffer();
00398             g_gui.scheduleTopDialogRedraw();
00399         }
00400         break;
00401 
00402     case Common::KEYCODE_KP4:
00403         if (state.flags & Common::KBD_NUM) {
00404             defaultKeyDownHandler(state);
00405             break;
00406         }
00407         // fall through
00408     case Common::KEYCODE_LEFT:
00409         if (_currentPos > _promptStartPos)
00410             _currentPos--;
00411         drawLine(pos2line(_currentPos));
00412         break;
00413 
00414     case Common::KEYCODE_KP6:
00415         if (state.flags & Common::KBD_NUM) {
00416             defaultKeyDownHandler(state);
00417             break;
00418         }
00419         // fall through
00420     case Common::KEYCODE_RIGHT:
00421         if (_currentPos < _promptEndPos)
00422             _currentPos++;
00423         drawLine(pos2line(_currentPos));
00424         break;
00425 
00426     case Common::KEYCODE_KP7:
00427         if (state.flags & Common::KBD_NUM) {
00428             defaultKeyDownHandler(state);
00429             break;
00430         }
00431         // fall through
00432     case Common::KEYCODE_HOME:
00433         if (state.hasFlags(Common::KBD_SHIFT)) {
00434             _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00435             updateScrollBuffer();
00436         } else {
00437             _currentPos = _promptStartPos;
00438         }
00439         g_gui.scheduleTopDialogRedraw();
00440         break;
00441 
00442     case Common::KEYCODE_KP8:
00443         if (state.flags & Common::KBD_NUM) {
00444             defaultKeyDownHandler(state);
00445             break;
00446         }
00447         // fall through
00448     case Common::KEYCODE_UP:
00449         historyScroll(+1);
00450         break;
00451 
00452     case Common::KEYCODE_KP9:
00453         if (state.flags & Common::KBD_NUM) {
00454             defaultKeyDownHandler(state);
00455             break;
00456         }
00457         // fall through
00458     case Common::KEYCODE_PAGEUP:
00459         if (state.hasFlags(Common::KBD_SHIFT)) {
00460             _scrollLine -= _linesPerPage - 1;
00461             if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
00462                 _scrollLine = _firstLineInBuffer + _linesPerPage - 1;
00463             updateScrollBuffer();
00464             g_gui.scheduleTopDialogRedraw();
00465         }
00466         break;
00467 
00468     default:
00469         defaultKeyDownHandler(state);
00470     }
00471 }
00472 
00473 void ConsoleDialog::defaultKeyDownHandler(Common::KeyState &state) {
00474     if (state.hasFlags(Common::KBD_CTRL)) {
00475         specialKeys(state.keycode);
00476     } else if ((state.ascii >= 32 && state.ascii <= 127) || (state.ascii >= 160 && state.ascii <= 255)) {
00477         for (int i = _promptEndPos - 1; i >= _currentPos; i--)
00478             buffer(i + 1) = buffer(i);
00479         _promptEndPos++;
00480         printChar((byte)state.ascii);
00481         scrollToCurrent();
00482     }
00483 }
00484 
00485 void ConsoleDialog::insertIntoPrompt(const char* str) {
00486     unsigned int l = strlen(str);
00487     for (int i = _promptEndPos - 1; i >= _currentPos; i--)
00488         buffer(i + l) = buffer(i);
00489     for (unsigned int j = 0; j < l; ++j) {
00490         _promptEndPos++;
00491         printCharIntern(str[j]);
00492     }
00493 }
00494 
00495 void ConsoleDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
00496     switch (cmd) {
00497     case kSetPositionCmd:
00498         int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer;
00499         if (newPos != _scrollLine) {
00500             _scrollLine = newPos;
00501             g_gui.scheduleTopDialogRedraw();
00502         }
00503         break;
00504     }
00505 }
00506 
00507 void ConsoleDialog::specialKeys(Common::KeyCode keycode) {
00508     switch (keycode) {
00509     case Common::KEYCODE_a:
00510         _currentPos = _promptStartPos;
00511         g_gui.scheduleTopDialogRedraw();
00512         break;
00513     case Common::KEYCODE_d:
00514         if (_currentPos < _promptEndPos) {
00515             killChar();
00516             g_gui.scheduleTopDialogRedraw();
00517         }
00518         break;
00519     case Common::KEYCODE_e:
00520         _currentPos = _promptEndPos;
00521         g_gui.scheduleTopDialogRedraw();
00522         break;
00523     case Common::KEYCODE_k:
00524         killLine();
00525         g_gui.scheduleTopDialogRedraw();
00526         break;
00527     case Common::KEYCODE_w:
00528         killLastWord();
00529         g_gui.scheduleTopDialogRedraw();
00530         break;
00531     case Common::KEYCODE_v:
00532         if (g_system->hasFeature(OSystem::kFeatureClipboardSupport) && g_system->hasTextInClipboard()) {
00533             Common::String text = g_system->getTextFromClipboard();
00534             insertIntoPrompt(text.c_str());
00535             scrollToCurrent();
00536             drawLine(pos2line(_currentPos));
00537         }
00538         break;
00539     case Common::KEYCODE_c:
00540         if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
00541             Common::String userInput = getUserInput();
00542             if (!userInput.empty())
00543                 g_system->setTextInClipboard(userInput);
00544         }
00545         break;
00546     default:
00547         break;
00548     }
00549 }
00550 
00551 void ConsoleDialog::killChar() {
00552     for (int i = _currentPos; i < _promptEndPos; i++)
00553         buffer(i) = buffer(i + 1);
00554     if (_promptEndPos > _promptStartPos) {
00555         buffer(_promptEndPos) = ' ';
00556         _promptEndPos--;
00557     }
00558 }
00559 
00560 void ConsoleDialog::killLine() {
00561     for (int i = _currentPos; i < _promptEndPos; i++)
00562         buffer(i) = ' ';
00563     _promptEndPos = _currentPos;
00564 }
00565 
00566 void ConsoleDialog::killLastWord() {
00567     int cnt = 0;
00568     bool space = true;
00569     while (_currentPos > _promptStartPos) {
00570         if (buffer(_currentPos - 1) == ' ') {
00571             if (!space)
00572                 break;
00573         } else
00574             space = false;
00575         _currentPos--;
00576         cnt++;
00577     }
00578 
00579     for (int i = _currentPos; i < _promptEndPos; i++)
00580         buffer(i) = buffer(i + cnt);
00581     if (_promptEndPos > _promptStartPos) {
00582         buffer(_promptEndPos) = ' ';
00583         _promptEndPos -= cnt;
00584     }
00585 }
00586 
00587 void ConsoleDialog::addToHistory(const Common::String &str) {
00588     _history[_historyIndex] = str;
00589     _historyIndex = (_historyIndex + 1) % kHistorySize;
00590     _historyLine = 0;
00591     if (_historySize < kHistorySize)
00592         _historySize++;
00593 }
00594 
00595 void ConsoleDialog::historyScroll(int direction) {
00596     if (_historySize == 0)
00597         return;
00598 
00599     if (_historyLine == 0 && direction > 0) {
00600         int i;
00601         for (i = 0; i < _promptEndPos - _promptStartPos; i++)
00602             _history[_historyIndex].insertChar(buffer(_promptStartPos + i), i);
00603     }
00604 
00605     // Advance to the next line in the history
00606     int line = _historyLine + direction;
00607     if ((direction < 0 && line < 0) || (direction > 0 && line > _historySize))
00608         return;
00609     _historyLine = line;
00610 
00611     // Hide caret if visible
00612     if (_caretVisible)
00613         drawCaret(true);
00614 
00615     // Remove the current user text
00616     _currentPos = _promptStartPos;
00617     killLine();
00618 
00619     // ... and ensure the prompt is visible
00620     scrollToCurrent();
00621 
00622     // Print the text from the history
00623     int idx;
00624     if (_historyLine > 0)
00625         idx = (_historyIndex - _historyLine + _historySize) % _historySize;
00626     else
00627         idx = _historyIndex;
00628     int length = _history[idx].size();
00629     for (int i = 0; i < length; i++)
00630         printCharIntern(_history[idx][i]);
00631     _promptEndPos = _currentPos;
00632 
00633     // Ensure once more the caret is visible (in case of very long history entries)
00634     scrollToCurrent();
00635 
00636     g_gui.scheduleTopDialogRedraw();
00637 }
00638 
00639 void ConsoleDialog::nextLine() {
00640     int line = _currentPos / kCharsPerLine;
00641     if (line == _scrollLine)
00642         _scrollLine++;
00643     _currentPos = (line + 1) * kCharsPerLine;
00644 
00645     updateScrollBuffer();
00646 }
00647 
00648 
00649 // Call this (at least) when the current line changes or when
00650 // a new line is added
00651 void ConsoleDialog::updateScrollBuffer() {
00652     int lastchar = MAX(_promptEndPos, _currentPos);
00653     int line = lastchar / kCharsPerLine;
00654     int numlines = (line < _linesInBuffer) ? line + 1 : _linesInBuffer;
00655     int firstline = line - numlines + 1;
00656     if (firstline > _firstLineInBuffer) {
00657         // clear old line from buffer
00658         for (int i = lastchar; i < (line+1) * kCharsPerLine; ++i)
00659             buffer(i) = ' ';
00660         _firstLineInBuffer = firstline;
00661     }
00662 
00663     _scrollBar->_numEntries = numlines;
00664     _scrollBar->_currentPos = _scrollBar->_numEntries - (line - _scrollLine + _linesPerPage);
00665     _scrollBar->_entriesPerPage = _linesPerPage;
00666     _scrollBar->recalc();
00667 }
00668 
00669 int ConsoleDialog::printFormat(int dummy, const char *format, ...) {
00670     va_list argptr;
00671 
00672     va_start(argptr, format);
00673     int count = this->vprintFormat(dummy, format, argptr);
00674     va_end (argptr);
00675     return count;
00676 }
00677 
00678 int ConsoleDialog::vprintFormat(int dummy, const char *format, va_list argptr) {
00679     Common::String buf = Common::String::vformat(format, argptr);
00680 
00681     print(buf.c_str());
00682 
00683     return buf.size();
00684 }
00685 
00686 void ConsoleDialog::printChar(int c) {
00687     if (_caretVisible)
00688         drawCaret(true);
00689 
00690     printCharIntern(c);
00691     drawLine(pos2line(_currentPos));
00692 }
00693 
00694 void ConsoleDialog::printCharIntern(int c) {
00695     if (c == '\n')
00696         nextLine();
00697     else {
00698         buffer(_currentPos) = (char)c;
00699         _currentPos++;
00700         if ((_scrollLine + 1) * kCharsPerLine == _currentPos) {
00701             _scrollLine++;
00702             updateScrollBuffer();
00703         }
00704     }
00705 }
00706 
00707 void ConsoleDialog::print(const char *str) {
00708     if (_caretVisible)
00709         drawCaret(true);
00710 
00711     while (*str)
00712         printCharIntern(*str++);
00713 
00714     g_gui.scheduleTopDialogRedraw();
00715 }
00716 
00717 void ConsoleDialog::drawCaret(bool erase) {
00718     // TODO: use code from EditableWidget::drawCaret here
00719     int line = _currentPos / kCharsPerLine;
00720     int displayLine = line - _scrollLine + _linesPerPage - 1;
00721 
00722     // Only draw caret if visible
00723     if (!isVisible() || displayLine < 0 || displayLine >= _linesPerPage) {
00724         _caretVisible = false;
00725         return;
00726     }
00727 
00728     int x = _x + 1 + _leftPadding + (_currentPos % kCharsPerLine) * kConsoleCharWidth;
00729     int y = _y + _topPadding + displayLine * kConsoleLineHeight;
00730 
00731     _caretVisible = !erase;
00732     g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + kConsoleLineHeight), erase);
00733 }
00734 
00735 void ConsoleDialog::scrollToCurrent() {
00736     int line = _promptEndPos / kCharsPerLine;
00737 
00738     if (line + _linesPerPage <= _scrollLine) {
00739         // TODO - this should only occur for loong edit lines, though
00740     } else if (line > _scrollLine) {
00741         _scrollLine = line;
00742         updateScrollBuffer();
00743         g_gui.scheduleTopDialogRedraw();
00744     }
00745 }
00746 
00747 } // End of namespace GUI


Generated on Sat May 25 2019 05:00:41 for ResidualVM by doxygen 1.7.1
curved edge   curved edge