00001
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 IConsoleLine *IConsoleLine::front = NULL;
00117 int IConsoleLine::size = 0;
00118
00119
00120
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
00128
00129
00130 static void IConsoleClearCommand()
00131 {
00132 memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
00133 _iconsole_cmdline.size = 1;
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
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);
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
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
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 }