00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "textbuf_type.h"
00014 #include "window_gui.h"
00015 #include "console_gui.h"
00016 #include "console_internal.h"
00017 #include "window_func.h"
00018 #include "string_func.h"
00019 #include "strings_func.h"
00020 #include "gfx_func.h"
00021 #include "settings_type.h"
00022 #include "console_func.h"
00023 #include "rev.h"
00024
00025 #include "widgets/console_widget.h"
00026
00027 #include "table/strings.h"
00028
00029 static const uint ICON_HISTORY_SIZE = 20;
00030 static const uint ICON_LINE_SPACING = 2;
00031 static const uint ICON_RIGHT_BORDERWIDTH = 10;
00032 static const uint ICON_BOTTOM_BORDERWIDTH = 12;
00033
00037 struct IConsoleLine {
00038 static IConsoleLine *front;
00039 static int size;
00040
00041 IConsoleLine *previous;
00042 char *buffer;
00043 TextColour colour;
00044 uint16 time;
00045
00051 IConsoleLine(char *buffer, TextColour colour) :
00052 previous(IConsoleLine::front),
00053 buffer(buffer),
00054 colour(colour),
00055 time(0)
00056 {
00057 IConsoleLine::front = this;
00058 IConsoleLine::size++;
00059 }
00060
00064 ~IConsoleLine()
00065 {
00066 IConsoleLine::size--;
00067 free(buffer);
00068
00069 delete previous;
00070 }
00071
00075 static const IConsoleLine *Get(uint index)
00076 {
00077 const IConsoleLine *item = IConsoleLine::front;
00078 while (index != 0 && item != NULL) {
00079 index--;
00080 item = item->previous;
00081 }
00082
00083 return item;
00084 }
00085
00093 static bool Truncate()
00094 {
00095 IConsoleLine *cur = IConsoleLine::front;
00096 if (cur == NULL) return false;
00097
00098 int count = 1;
00099 for (IConsoleLine *item = cur->previous; item != NULL; count++, cur = item, item = item->previous) {
00100 if (item->time > _settings_client.gui.console_backlog_timeout &&
00101 count > _settings_client.gui.console_backlog_length) {
00102 delete item;
00103 cur->previous = NULL;
00104 return true;
00105 }
00106
00107 if (item->time != MAX_UVALUE(uint16)) item->time++;
00108 }
00109
00110 return false;
00111 }
00112
00116 static void Reset()
00117 {
00118 delete IConsoleLine::front;
00119 IConsoleLine::front = NULL;
00120 IConsoleLine::size = 0;
00121 }
00122 };
00123
00124 IConsoleLine *IConsoleLine::front = NULL;
00125 int IConsoleLine::size = 0;
00126
00127
00128
00129 static Textbuf _iconsole_cmdline(ICON_CMDLN_SIZE);
00130 static char *_iconsole_history[ICON_HISTORY_SIZE];
00131 static int _iconsole_historypos;
00132 IConsoleModes _iconsole_mode;
00133
00134
00135
00136
00137
00138 static void IConsoleClearCommand()
00139 {
00140 memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE);
00141 _iconsole_cmdline.chars = _iconsole_cmdline.bytes = 1;
00142 _iconsole_cmdline.pixels = 0;
00143 _iconsole_cmdline.caretpos = 0;
00144 _iconsole_cmdline.caretxoffs = 0;
00145 SetWindowDirty(WC_CONSOLE, 0);
00146 }
00147
00148 static inline void IConsoleResetHistoryPos()
00149 {
00150 _iconsole_historypos = -1;
00151 }
00152
00153
00154 static const char *IConsoleHistoryAdd(const char *cmd);
00155 static void IConsoleHistoryNavigate(int direction);
00156
00157 static const struct NWidgetPart _nested_console_window_widgets[] = {
00158 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_BACKGROUND), SetResize(1, 1),
00159 };
00160
00161 static WindowDesc _console_window_desc(
00162 WDP_MANUAL, NULL, 0, 0,
00163 WC_CONSOLE, WC_NONE,
00164 0,
00165 _nested_console_window_widgets, lengthof(_nested_console_window_widgets)
00166 );
00167
00168 struct IConsoleWindow : Window
00169 {
00170 static int scroll;
00171 int line_height;
00172 int line_offset;
00173
00174 IConsoleWindow() : Window(&_console_window_desc)
00175 {
00176 _iconsole_mode = ICONSOLE_OPENED;
00177 this->line_height = FONT_HEIGHT_NORMAL + ICON_LINE_SPACING;
00178 this->line_offset = GetStringBoundingBox("] ").width + 5;
00179
00180 this->InitNested(0);
00181 ResizeWindow(this, _screen.width, _screen.height / 3);
00182 }
00183
00184 ~IConsoleWindow()
00185 {
00186 _iconsole_mode = ICONSOLE_CLOSED;
00187 }
00188
00193 void Scroll(int amount)
00194 {
00195 int max_scroll = max<int>(0, IConsoleLine::size + 1 - this->height / this->line_height);
00196 IConsoleWindow::scroll = Clamp<int>(IConsoleWindow::scroll + amount, 0, max_scroll);
00197 this->SetDirty();
00198 }
00199
00200 virtual void OnPaint()
00201 {
00202 const int right = this->width - 5;
00203
00204 GfxFillRect(0, 0, this->width - 1, this->height - 1, PC_BLACK);
00205 int ypos = this->height - this->line_height;
00206 for (const IConsoleLine *print = IConsoleLine::Get(IConsoleWindow::scroll); print != NULL; print = print->previous) {
00207 SetDParamStr(0, print->buffer);
00208 ypos = DrawStringMultiLine(5, right, -this->line_height, ypos, STR_JUST_RAW_STRING, print->colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - ICON_LINE_SPACING;
00209 if (ypos < 0) break;
00210 }
00211
00212 int delta = this->width - this->line_offset - _iconsole_cmdline.pixels - ICON_RIGHT_BORDERWIDTH;
00213 if (delta > 0) {
00214 DrawString(5, right, this->height - this->line_height, "]", (TextColour)CC_COMMAND, SA_LEFT | SA_FORCE);
00215 delta = 0;
00216 }
00217
00218 DrawString(this->line_offset + delta, right, this->height - this->line_height, _iconsole_cmdline.buf, (TextColour)CC_COMMAND, SA_LEFT | SA_FORCE);
00219
00220 if (_focused_window == this && _iconsole_cmdline.caret) {
00221 DrawString(this->line_offset + delta + _iconsole_cmdline.caretxoffs, right, this->height - this->line_height, "_", TC_WHITE, SA_LEFT | SA_FORCE);
00222 }
00223 }
00224
00225 virtual void OnHundredthTick()
00226 {
00227 if (IConsoleLine::Truncate() &&
00228 (IConsoleWindow::scroll > IConsoleLine::size)) {
00229 IConsoleWindow::scroll = max(0, IConsoleLine::size - (this->height / this->line_height) + 1);
00230 this->SetDirty();
00231 }
00232 }
00233
00234 virtual void OnMouseLoop()
00235 {
00236 if (_iconsole_cmdline.HandleCaret()) this->SetDirty();
00237 }
00238
00239 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00240 {
00241 if (_focused_window != this) return ES_NOT_HANDLED;
00242
00243 const int scroll_height = (this->height / this->line_height) - 1;
00244 switch (keycode) {
00245 case WKC_UP:
00246 IConsoleHistoryNavigate(1);
00247 this->SetDirty();
00248 break;
00249
00250 case WKC_DOWN:
00251 IConsoleHistoryNavigate(-1);
00252 this->SetDirty();
00253 break;
00254
00255 case WKC_SHIFT | WKC_PAGEDOWN:
00256 this->Scroll(-scroll_height);
00257 break;
00258
00259 case WKC_SHIFT | WKC_PAGEUP:
00260 this->Scroll(scroll_height);
00261 break;
00262
00263 case WKC_SHIFT | WKC_DOWN:
00264 this->Scroll(-1);
00265 break;
00266
00267 case WKC_SHIFT | WKC_UP:
00268 this->Scroll(1);
00269 break;
00270
00271 case WKC_BACKQUOTE:
00272 IConsoleSwitch();
00273 break;
00274
00275 case WKC_RETURN: case WKC_NUM_ENTER: {
00276
00277
00278
00279 IConsolePrintF(CC_COMMAND, LRM "] %s", _iconsole_cmdline.buf);
00280 const char *cmd = IConsoleHistoryAdd(_iconsole_cmdline.buf);
00281 IConsoleClearCommand();
00282
00283 if (cmd != NULL) IConsoleCmdExec(cmd);
00284 break;
00285 }
00286
00287 case WKC_CTRL | WKC_RETURN:
00288 _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
00289 IConsoleResize(this);
00290 MarkWholeScreenDirty();
00291 break;
00292
00293 case (WKC_CTRL | 'L'):
00294 IConsoleCmdExec("clear");
00295 break;
00296
00297 default:
00298 if (_iconsole_cmdline.HandleKeyPress(key, keycode) != HKPR_NOT_HANDLED) {
00299 IConsoleWindow::scroll = 0;
00300 IConsoleResetHistoryPos();
00301 this->SetDirty();
00302 } else {
00303 return ES_NOT_HANDLED;
00304 }
00305 break;
00306 }
00307 return ES_HANDLED;
00308 }
00309
00310 virtual void OnMouseWheel(int wheel)
00311 {
00312 this->Scroll(-wheel);
00313 }
00314 };
00315
00316 int IConsoleWindow::scroll = 0;
00317
00318 void IConsoleGUIInit()
00319 {
00320 IConsoleResetHistoryPos();
00321 _iconsole_mode = ICONSOLE_CLOSED;
00322
00323 IConsoleLine::Reset();
00324 memset(_iconsole_history, 0, sizeof(_iconsole_history));
00325
00326 IConsolePrintF(CC_WARNING, "OpenTTD Game Console Revision 7 - %s", _openttd_revision);
00327 IConsolePrint(CC_WHITE, "------------------------------------");
00328 IConsolePrint(CC_WHITE, "use \"help\" for more information");
00329 IConsolePrint(CC_WHITE, "");
00330 IConsoleClearCommand();
00331 }
00332
00333 void IConsoleClearBuffer()
00334 {
00335 IConsoleLine::Reset();
00336 }
00337
00338 void IConsoleGUIFree()
00339 {
00340 IConsoleClearBuffer();
00341 }
00342
00344 void IConsoleResize(Window *w)
00345 {
00346 switch (_iconsole_mode) {
00347 case ICONSOLE_OPENED:
00348 w->height = _screen.height / 3;
00349 w->width = _screen.width;
00350 break;
00351 case ICONSOLE_FULL:
00352 w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH;
00353 w->width = _screen.width;
00354 break;
00355 default: return;
00356 }
00357
00358 MarkWholeScreenDirty();
00359 }
00360
00362 void IConsoleSwitch()
00363 {
00364 switch (_iconsole_mode) {
00365 case ICONSOLE_CLOSED:
00366 new IConsoleWindow();
00367 break;
00368
00369 case ICONSOLE_OPENED: case ICONSOLE_FULL:
00370 DeleteWindowById(WC_CONSOLE, 0);
00371 break;
00372 }
00373
00374 MarkWholeScreenDirty();
00375 }
00376
00378 void IConsoleClose()
00379 {
00380 if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();
00381 }
00382
00389 static const char *IConsoleHistoryAdd(const char *cmd)
00390 {
00391
00392 while (IsWhitespace(*cmd)) cmd++;
00393
00394
00395 if (StrEmpty(cmd)) return NULL;
00396
00397
00398 if (_iconsole_history[0] == NULL || strcmp(_iconsole_history[0], cmd) != 0) {
00399 free(_iconsole_history[ICON_HISTORY_SIZE - 1]);
00400 memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1));
00401 _iconsole_history[0] = strdup(cmd);
00402 }
00403
00404
00405 IConsoleResetHistoryPos();
00406 return _iconsole_history[0];
00407 }
00408
00413 static void IConsoleHistoryNavigate(int direction)
00414 {
00415 if (_iconsole_history[0] == NULL) return;
00416 _iconsole_historypos = Clamp(_iconsole_historypos + direction, -1, ICON_HISTORY_SIZE - 1);
00417
00418 if (direction > 0 && _iconsole_history[_iconsole_historypos] == NULL) _iconsole_historypos--;
00419
00420 if (_iconsole_historypos == -1) {
00421 _iconsole_cmdline.DeleteAll();
00422 } else {
00423 _iconsole_cmdline.Assign(_iconsole_history[_iconsole_historypos]);
00424 }
00425 }
00426
00436 void IConsoleGUIPrint(TextColour colour_code, char *str)
00437 {
00438 new IConsoleLine(str, colour_code);
00439 SetWindowDirty(WC_CONSOLE, 0);
00440 }
00441
00442
00448 bool IsValidConsoleColour(TextColour c)
00449 {
00450
00451 if (!(c & TC_IS_PALETTE_COLOUR)) return TC_BEGIN <= c && c < TC_END;
00452
00453
00454
00455 c &= ~TC_IS_PALETTE_COLOUR;
00456 for (uint i = COLOUR_BEGIN; i < COLOUR_END; i++) {
00457 if (_colour_gradient[i][4] == c) return true;
00458 }
00459
00460 return false;
00461 }