console_gui.cpp

Go to the documentation of this file.
00001 /* $Id: console_gui.cpp 15723 2009-03-15 15:12:06Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "textbuf_gui.h"
00007 #include "window_gui.h"
00008 #include "console_gui.h"
00009 #include "console_internal.h"
00010 #include "window_func.h"
00011 #include "string_func.h"
00012 #include "gfx_func.h"
00013 #include "core/math_func.hpp"
00014 #include "settings_type.h"
00015 #include "rev.h"
00016 
00017 #include "table/strings.h"
00018 
00019 enum {
00020   ICON_HISTORY_SIZE       = 20,
00021   ICON_LINE_HEIGHT        = 12,
00022   ICON_RIGHT_BORDERWIDTH  = 10,
00023   ICON_BOTTOM_BORDERWIDTH = 12,
00024 };
00025 
00029 struct IConsoleLine {
00030   static IConsoleLine *front; 
00031   static int size;            
00032 
00033   IConsoleLine *previous; 
00034   char *buffer;           
00035   TextColour colour;      
00036   uint16 time;            
00037 
00043   IConsoleLine(char *buffer, TextColour colour) :
00044       previous(IConsoleLine::front),
00045       buffer(buffer),
00046       colour(colour),
00047       time(0)
00048   {
00049     IConsoleLine::front = this;
00050     IConsoleLine::size++;
00051   }
00052 
00056   ~IConsoleLine()
00057   {
00058     IConsoleLine::size--;
00059     free(buffer);
00060 
00061     delete previous;
00062   }
00063 
00067   static const IConsoleLine *Get(uint index)
00068   {
00069     const IConsoleLine *item = IConsoleLine::front;
00070     while (index != 0 && item != NULL) {
00071       index--;
00072       item = item->previous;
00073     }
00074 
00075     return item;
00076   }
00077 
00085   static bool Truncate()
00086   {
00087     IConsoleLine *cur = IConsoleLine::front;
00088     if (cur == NULL) return false;
00089 
00090     int count = 1;
00091     for (IConsoleLine *item = cur->previous; item != NULL; count++, cur = item, item = item->previous) {
00092       if (item->time > _settings_client.gui.console_backlog_timeout &&
00093           count > _settings_client.gui.console_backlog_length) {
00094         delete item;
00095         cur->previous = NULL;
00096         return true;
00097       }
00098 
00099       if (item->time != MAX_UVALUE(uint16)) item->time++;
00100     }
00101 
00102     return false;
00103   }
00104 
00108   static void Reset()
00109   {
00110     delete IConsoleLine::front;
00111     IConsoleLine::front = NULL;
00112     IConsoleLine::size = 0;
00113   }
00114 };
00115 
00116 /* static */ IConsoleLine *IConsoleLine::front = NULL;
00117 /* static */ int IConsoleLine::size  = 0;
00118 
00119 
00120 /* ** main console cmd buffer ** */
00121 static Textbuf _iconsole_cmdline;
00122 static char *_iconsole_history[ICON_HISTORY_SIZE];
00123 static byte _iconsole_historypos;
00124 IConsoleModes _iconsole_mode;
00125 
00126 /* *************** *
00127  *  end of header  *
00128  * *************** */
00129 
00130 static void IConsoleClearCommand()
00131 {
00132   memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
00133   _iconsole_cmdline.size = 1; // only terminating zero
00134   _iconsole_cmdline.width = 0;
00135   _iconsole_cmdline.caretpos = 0;
00136   _iconsole_cmdline.caretxoffs = 0;
00137   SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
00138 }
00139 
00140 static inline void IConsoleResetHistoryPos() {_iconsole_historypos = ICON_HISTORY_SIZE - 1;}
00141 
00142 
00143 static void IConsoleHistoryAdd(const char *cmd);
00144 static void IConsoleHistoryNavigate(int direction);
00145 
00146 struct IConsoleWindow : Window
00147 {
00148   static int scroll;
00149 
00150   IConsoleWindow(const WindowDesc *desc) : Window(desc)
00151   {
00152     _iconsole_mode = ICONSOLE_OPENED;
00153 
00154     this->height = _screen.height / 3;
00155     this->width  = _screen.width;
00156   }
00157 
00158   ~IConsoleWindow()
00159   {
00160     _iconsole_mode = ICONSOLE_CLOSED;
00161   }
00162 
00163   virtual void OnPaint()
00164   {
00165     int max = (this->height / ICON_LINE_HEIGHT) - 1;
00166     const IConsoleLine *print = IConsoleLine::Get(IConsoleWindow::scroll);
00167     GfxFillRect(this->left, this->top, this->width, this->height - 1, 0);
00168     for (int i = 0; i < max && print != NULL; i++, print = print->previous) {
00169       DoDrawString(print->buffer, 5,
00170         this->height - (2 + i) * ICON_LINE_HEIGHT, print->colour);
00171     }
00172     /* If the text is longer than the window, don't show the starting ']' */
00173     int delta = this->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
00174     if (delta > 0) {
00175       DoDrawString("]", 5, this->height - ICON_LINE_HEIGHT, (TextColour)CC_COMMAND);
00176       delta = 0;
00177     }
00178 
00179     DoDrawString(_iconsole_cmdline.buf, 10 + delta, this->height - ICON_LINE_HEIGHT, (TextColour)CC_COMMAND);
00180 
00181     if (_focused_window == this && _iconsole_cmdline.caret) {
00182       DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, this->height - ICON_LINE_HEIGHT, TC_WHITE);
00183     }
00184   }
00185 
00186   virtual void OnHundredthTick()
00187   {
00188     if (IConsoleLine::Truncate() &&
00189         (IConsoleWindow::scroll > IConsoleLine::size)) {
00190       IConsoleWindow::scroll = max(0, IConsoleLine::size - (this->height / ICON_LINE_HEIGHT) + 1);
00191       this->SetDirty();
00192     }
00193   }
00194 
00195   virtual void OnMouseLoop()
00196   {
00197     if (HandleCaret(&_iconsole_cmdline)) this->SetDirty();
00198   }
00199 
00200   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00201   {
00202     if (_focused_window != this) return ES_NOT_HANDLED;
00203 
00204     const int scroll_height = (this->height / ICON_LINE_HEIGHT) - 1;
00205     switch (keycode) {
00206       case WKC_UP:
00207         IConsoleHistoryNavigate(1);
00208         this->SetDirty();
00209         break;
00210 
00211       case WKC_DOWN:
00212         IConsoleHistoryNavigate(-1);
00213         this->SetDirty();
00214         break;
00215 
00216       case WKC_SHIFT | WKC_PAGEDOWN:
00217         if (IConsoleWindow::scroll - scroll_height < 0) {
00218           IConsoleWindow::scroll = 0;
00219         } else {
00220           IConsoleWindow::scroll -= scroll_height;
00221         }
00222         this->SetDirty();
00223         break;
00224 
00225       case WKC_SHIFT | WKC_PAGEUP:
00226         if (IConsoleWindow::scroll + scroll_height > IConsoleLine::size - scroll_height) {
00227           IConsoleWindow::scroll = IConsoleLine::size - scroll_height;
00228         } else {
00229           IConsoleWindow::scroll += scroll_height;
00230         }
00231         this->SetDirty();
00232         break;
00233 
00234       case WKC_SHIFT | WKC_DOWN:
00235         if (IConsoleWindow::scroll <= 0) {
00236           IConsoleWindow::scroll = 0;
00237         } else {
00238           --IConsoleWindow::scroll;
00239         }
00240         this->SetDirty();
00241         break;
00242 
00243       case WKC_SHIFT | WKC_UP:
00244         if (IConsoleWindow::scroll >= IConsoleLine::size) {
00245           IConsoleWindow::scroll = IConsoleLine::size;
00246         } else {
00247           ++IConsoleWindow::scroll;
00248         }
00249         this->SetDirty();
00250         break;
00251 
00252       case WKC_BACKQUOTE:
00253         IConsoleSwitch();
00254         break;
00255 
00256       case WKC_RETURN: case WKC_NUM_ENTER:
00257         IConsolePrintF(CC_COMMAND, "] %s", _iconsole_cmdline.buf);
00258         IConsoleHistoryAdd(_iconsole_cmdline.buf);
00259 
00260         IConsoleCmdExec(_iconsole_cmdline.buf);
00261         IConsoleClearCommand();
00262         break;
00263 
00264       case WKC_CTRL | WKC_RETURN:
00265         _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
00266         IConsoleResize(this);
00267         MarkWholeScreenDirty();
00268         break;
00269 
00270       case (WKC_CTRL | 'V'):
00271         if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
00272           IConsoleResetHistoryPos();
00273           this->SetDirty();
00274         }
00275         break;
00276 
00277       case (WKC_CTRL | 'L'):
00278         IConsoleCmdExec("clear");
00279         break;
00280 
00281       case (WKC_CTRL | 'U'):
00282         DeleteTextBufferAll(&_iconsole_cmdline);
00283         this->SetDirty();
00284         break;
00285 
00286       case WKC_BACKSPACE: case WKC_DELETE:
00287         if (DeleteTextBufferChar(&_iconsole_cmdline, keycode)) {
00288           IConsoleResetHistoryPos();
00289           this->SetDirty();
00290         }
00291         break;
00292 
00293       case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
00294         if (MoveTextBufferPos(&_iconsole_cmdline, keycode)) {
00295           IConsoleResetHistoryPos();
00296           this->SetDirty();
00297         }
00298         break;
00299 
00300       default:
00301         if (IsValidChar(key, CS_ALPHANUMERAL)) {
00302           IConsoleWindow::scroll = 0;
00303           InsertTextBufferChar(&_iconsole_cmdline, key);
00304           IConsoleResetHistoryPos();
00305           this->SetDirty();
00306         } else {
00307           return ES_NOT_HANDLED;
00308         }
00309     }
00310     return ES_HANDLED;
00311   }
00312 };
00313 
00314 int IConsoleWindow::scroll = 0;
00315 
00316 static const Widget _iconsole_window_widgets[] = {
00317   {WIDGETS_END}
00318 };
00319 
00320 static const WindowDesc _iconsole_window_desc(
00321   0, 0, 2, 2, 2, 2,
00322   WC_CONSOLE, WC_NONE,
00323   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
00324   _iconsole_window_widgets
00325 );
00326 
00327 void IConsoleGUIInit()
00328 {
00329   _iconsole_historypos = ICON_HISTORY_SIZE - 1;
00330   _iconsole_mode = ICONSOLE_CLOSED;
00331 
00332   IConsoleLine::Reset();
00333   memset(_iconsole_history, 0, sizeof(_iconsole_history));
00334 
00335   _iconsole_cmdline.buf = CallocT<char>(ICON_CMDLN_SIZE); // create buffer and zero it
00336   _iconsole_cmdline.maxsize = ICON_CMDLN_SIZE;
00337 
00338   IConsolePrintF(CC_WARNING, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
00339   IConsolePrint(CC_WHITE,  "------------------------------------");
00340   IConsolePrint(CC_WHITE,  "use \"help\" for more information");
00341   IConsolePrint(CC_WHITE,  "");
00342   IConsoleClearCommand();
00343   IConsoleHistoryAdd("");
00344 }
00345 
00346 void IConsoleClearBuffer()
00347 {
00348   IConsoleLine::Reset();
00349 }
00350 
00351 void IConsoleGUIFree()
00352 {
00353   free(_iconsole_cmdline.buf);
00354   IConsoleClearBuffer();
00355 }
00356 
00357 void IConsoleResize(Window *w)
00358 {
00359   switch (_iconsole_mode) {
00360     case ICONSOLE_OPENED:
00361       w->height = _screen.height / 3;
00362       w->width = _screen.width;
00363       break;
00364     case ICONSOLE_FULL:
00365       w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
00366       w->width = _screen.width;
00367       break;
00368     default: return;
00369   }
00370 
00371   MarkWholeScreenDirty();
00372 }
00373 
00374 void IConsoleSwitch()
00375 {
00376   switch (_iconsole_mode) {
00377     case ICONSOLE_CLOSED:
00378       new IConsoleWindow(&_iconsole_window_desc);
00379       break;
00380 
00381     case ICONSOLE_OPENED: case ICONSOLE_FULL:
00382       DeleteWindowById(WC_CONSOLE, 0);
00383       break;
00384   }
00385 
00386   MarkWholeScreenDirty();
00387 }
00388 
00389 void IConsoleClose() {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();}
00390 void IConsoleOpen()  {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();}
00391 
00397 static void IConsoleHistoryAdd(const char *cmd)
00398 {
00399   free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
00400 
00401   memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
00402   _iconsole_history[0] = strdup(cmd);
00403   IConsoleResetHistoryPos();
00404 }
00405 
00410 static void IConsoleHistoryNavigate(int direction)
00411 {
00412   int i = _iconsole_historypos + direction;
00413 
00414   /* watch out for overflows, just wrap around */
00415   if (i < 0) i = ICON_HISTORY_SIZE - 1;
00416   if (i >= ICON_HISTORY_SIZE) i = 0;
00417 
00418   if (direction > 0) {
00419     if (_iconsole_history[i] == NULL) i = 0;
00420   }
00421 
00422   if (direction < 0) {
00423     while (i > 0 && _iconsole_history[i] == NULL) i--;
00424   }
00425 
00426   _iconsole_historypos = i;
00427   IConsoleClearCommand();
00428   /* copy history to 'command prompt / bash' */
00429   assert(_iconsole_history[i] != NULL && IsInsideMM(i, 0, ICON_HISTORY_SIZE));
00430   ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxsize);
00431   UpdateTextBufferSize(&_iconsole_cmdline);
00432 }
00433 
00443 void IConsoleGUIPrint(ConsoleColour colour_code, char *str)
00444 {
00445   new IConsoleLine(str, (TextColour)colour_code);
00446   SetWindowDirty(FindWindowById(WC_CONSOLE, 0));
00447 }

Generated on Sun Nov 15 15:40:10 2009 for OpenTTD by  doxygen 1.5.6