34 /* console parser */ |
25 /* console parser */ |
35 IConsoleCmd *_iconsole_cmds; ///< list of registred commands |
26 IConsoleCmd *_iconsole_cmds; ///< list of registred commands |
36 IConsoleVar *_iconsole_vars; ///< list of registred vars |
27 IConsoleVar *_iconsole_vars; ///< list of registred vars |
37 IConsoleAlias *_iconsole_aliases; ///< list of registred aliases |
28 IConsoleAlias *_iconsole_aliases; ///< list of registred aliases |
38 |
29 |
39 /* console modes */ |
|
40 IConsoleModes _iconsole_mode; |
|
41 |
|
42 /* ** main console ** */ |
|
43 static char *_iconsole_buffer[ICON_BUFFER + 1]; |
|
44 static uint16 _iconsole_cbuffer[ICON_BUFFER + 1]; |
|
45 static Textbuf _iconsole_cmdline; |
|
46 |
|
47 /* ** stdlib ** */ |
30 /* ** stdlib ** */ |
48 byte _stdlib_developer = 1; |
31 byte _stdlib_developer = 1; |
49 bool _stdlib_con_developer = false; |
32 bool _stdlib_con_developer = false; |
50 FILE *_iconsole_output_file; |
33 FILE *_iconsole_output_file; |
51 |
34 |
52 /* ** main console cmd buffer ** */ |
|
53 static char *_iconsole_history[ICON_HISTORY_SIZE]; |
|
54 static byte _iconsole_historypos; |
|
55 |
|
56 /* *************** * |
|
57 * end of header * |
|
58 * *************** */ |
|
59 |
|
60 static void IConsoleClearCommand() |
|
61 { |
|
62 memset(_iconsole_cmdline.buf, 0, ICON_CMDLN_SIZE); |
|
63 _iconsole_cmdline.length = 0; |
|
64 _iconsole_cmdline.width = 0; |
|
65 _iconsole_cmdline.caretpos = 0; |
|
66 _iconsole_cmdline.caretxoffs = 0; |
|
67 SetWindowDirty(FindWindowById(WC_CONSOLE, 0)); |
|
68 } |
|
69 |
|
70 static inline void IConsoleResetHistoryPos() {_iconsole_historypos = ICON_HISTORY_SIZE - 1;} |
|
71 |
|
72 |
|
73 static void IConsoleHistoryAdd(const char *cmd); |
|
74 static void IConsoleHistoryNavigate(int direction); |
|
75 |
|
76 struct IConsoleWindow : Window |
|
77 { |
|
78 static byte scroll; |
|
79 |
|
80 IConsoleWindow(const WindowDesc *desc) : Window(desc) |
|
81 { |
|
82 _iconsole_mode = ICONSOLE_OPENED; |
|
83 SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll |
|
84 |
|
85 this->height = _screen.height / 3; |
|
86 this->width = _screen.width; |
|
87 } |
|
88 |
|
89 ~IConsoleWindow() |
|
90 { |
|
91 _iconsole_mode = ICONSOLE_CLOSED; |
|
92 ClrBit(_no_scroll, SCROLL_CON); |
|
93 } |
|
94 |
|
95 virtual void OnPaint() |
|
96 { |
|
97 int i = IConsoleWindow::scroll; |
|
98 int max = (this->height / ICON_LINE_HEIGHT) - 1; |
|
99 int delta = 0; |
|
100 GfxFillRect(this->left, this->top, this->width, this->height - 1, 0); |
|
101 while ((i > 0) && (i > IConsoleWindow::scroll - max) && (_iconsole_buffer[i] != NULL)) { |
|
102 DoDrawString(_iconsole_buffer[i], 5, |
|
103 this->height - (IConsoleWindow::scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]); |
|
104 i--; |
|
105 } |
|
106 /* If the text is longer than the window, don't show the starting ']' */ |
|
107 delta = this->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH; |
|
108 if (delta > 0) { |
|
109 DoDrawString("]", 5, this->height - ICON_LINE_HEIGHT, CC_COMMAND); |
|
110 delta = 0; |
|
111 } |
|
112 |
|
113 DoDrawString(_iconsole_cmdline.buf, 10 + delta, this->height - ICON_LINE_HEIGHT, CC_COMMAND); |
|
114 |
|
115 if (_iconsole_cmdline.caret) { |
|
116 DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, this->height - ICON_LINE_HEIGHT, TC_WHITE); |
|
117 } |
|
118 } |
|
119 |
|
120 virtual void OnMouseLoop() |
|
121 { |
|
122 if (HandleCaret(&_iconsole_cmdline)) this->SetDirty(); |
|
123 } |
|
124 |
|
125 virtual EventState OnKeyPress(uint16 key, uint16 keycode) |
|
126 { |
|
127 switch (keycode) { |
|
128 case WKC_UP: |
|
129 IConsoleHistoryNavigate(+1); |
|
130 this->SetDirty(); |
|
131 break; |
|
132 |
|
133 case WKC_DOWN: |
|
134 IConsoleHistoryNavigate(-1); |
|
135 this->SetDirty(); |
|
136 break; |
|
137 |
|
138 case WKC_SHIFT | WKC_PAGEUP: |
|
139 if (IConsoleWindow::scroll - (this->height / ICON_LINE_HEIGHT) - 1 < 0) { |
|
140 IConsoleWindow::scroll = 0; |
|
141 } else { |
|
142 IConsoleWindow::scroll -= (this->height / ICON_LINE_HEIGHT) - 1; |
|
143 } |
|
144 this->SetDirty(); |
|
145 break; |
|
146 |
|
147 case WKC_SHIFT | WKC_PAGEDOWN: |
|
148 if (IConsoleWindow::scroll + (this->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) { |
|
149 IConsoleWindow::scroll = ICON_BUFFER; |
|
150 } else { |
|
151 IConsoleWindow::scroll += (this->height / ICON_LINE_HEIGHT) - 1; |
|
152 } |
|
153 this->SetDirty(); |
|
154 break; |
|
155 |
|
156 case WKC_SHIFT | WKC_UP: |
|
157 if (IConsoleWindow::scroll <= 0) { |
|
158 IConsoleWindow::scroll = 0; |
|
159 } else { |
|
160 --IConsoleWindow::scroll; |
|
161 } |
|
162 this->SetDirty(); |
|
163 break; |
|
164 |
|
165 case WKC_SHIFT | WKC_DOWN: |
|
166 if (IConsoleWindow::scroll >= ICON_BUFFER) { |
|
167 IConsoleWindow::scroll = ICON_BUFFER; |
|
168 } else { |
|
169 ++IConsoleWindow::scroll; |
|
170 } |
|
171 this->SetDirty(); |
|
172 break; |
|
173 |
|
174 case WKC_BACKQUOTE: |
|
175 IConsoleSwitch(); |
|
176 break; |
|
177 |
|
178 case WKC_RETURN: case WKC_NUM_ENTER: |
|
179 IConsolePrintF(CC_COMMAND, "] %s", _iconsole_cmdline.buf); |
|
180 IConsoleHistoryAdd(_iconsole_cmdline.buf); |
|
181 |
|
182 IConsoleCmdExec(_iconsole_cmdline.buf); |
|
183 IConsoleClearCommand(); |
|
184 break; |
|
185 |
|
186 case WKC_CTRL | WKC_RETURN: |
|
187 _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL; |
|
188 IConsoleResize(this); |
|
189 MarkWholeScreenDirty(); |
|
190 break; |
|
191 |
|
192 case (WKC_CTRL | 'V'): |
|
193 if (InsertTextBufferClipboard(&_iconsole_cmdline)) { |
|
194 IConsoleResetHistoryPos(); |
|
195 this->SetDirty(); |
|
196 } |
|
197 break; |
|
198 |
|
199 case (WKC_CTRL | 'L'): |
|
200 IConsoleCmdExec("clear"); |
|
201 break; |
|
202 |
|
203 case (WKC_CTRL | 'U'): |
|
204 DeleteTextBufferAll(&_iconsole_cmdline); |
|
205 this->SetDirty(); |
|
206 break; |
|
207 |
|
208 case WKC_BACKSPACE: case WKC_DELETE: |
|
209 if (DeleteTextBufferChar(&_iconsole_cmdline, keycode)) { |
|
210 IConsoleResetHistoryPos(); |
|
211 this->SetDirty(); |
|
212 } |
|
213 break; |
|
214 |
|
215 case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME: |
|
216 if (MoveTextBufferPos(&_iconsole_cmdline, keycode)) { |
|
217 IConsoleResetHistoryPos(); |
|
218 this->SetDirty(); |
|
219 } |
|
220 break; |
|
221 |
|
222 default: |
|
223 if (IsValidChar(key, CS_ALPHANUMERAL)) { |
|
224 IConsoleWindow::scroll = ICON_BUFFER; |
|
225 InsertTextBufferChar(&_iconsole_cmdline, key); |
|
226 IConsoleResetHistoryPos(); |
|
227 this->SetDirty(); |
|
228 } else { |
|
229 return ES_NOT_HANDLED; |
|
230 } |
|
231 } |
|
232 return ES_HANDLED; |
|
233 } |
|
234 }; |
|
235 |
|
236 byte IConsoleWindow::scroll = ICON_BUFFER; |
|
237 |
|
238 static const Widget _iconsole_window_widgets[] = { |
|
239 {WIDGETS_END} |
|
240 }; |
|
241 |
|
242 static const WindowDesc _iconsole_window_desc = { |
|
243 0, 0, 2, 2, 2, 2, |
|
244 WC_CONSOLE, WC_NONE, |
|
245 WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, |
|
246 _iconsole_window_widgets, |
|
247 }; |
|
248 |
|
249 void IConsoleInit() |
35 void IConsoleInit() |
250 { |
36 { |
251 _iconsole_output_file = NULL; |
37 _iconsole_output_file = NULL; |
252 _iconsole_historypos = ICON_HISTORY_SIZE - 1; |
|
253 _iconsole_mode = ICONSOLE_CLOSED; |
|
254 |
|
255 #ifdef ENABLE_NETWORK /* Initialize network only variables */ |
38 #ifdef ENABLE_NETWORK /* Initialize network only variables */ |
256 _redirect_console_to_client = 0; |
39 _redirect_console_to_client = 0; |
257 #endif |
40 #endif |
258 |
41 |
259 memset(_iconsole_history, 0, sizeof(_iconsole_history)); |
42 IConsoleGUIInit(); |
260 memset(_iconsole_buffer, 0, sizeof(_iconsole_buffer)); |
43 |
261 memset(_iconsole_cbuffer, 0, sizeof(_iconsole_cbuffer)); |
|
262 _iconsole_cmdline.buf = CallocT<char>(ICON_CMDLN_SIZE); // create buffer and zero it |
|
263 _iconsole_cmdline.maxlength = ICON_CMDLN_SIZE; |
|
264 |
|
265 IConsolePrintF(CC_WARNING, "OpenTTD Game Console Revision 7 - %s", _openttd_revision); |
|
266 IConsolePrint(CC_WHITE, "------------------------------------"); |
|
267 IConsolePrint(CC_WHITE, "use \"help\" for more information"); |
|
268 IConsolePrint(CC_WHITE, ""); |
|
269 IConsoleStdLibRegister(); |
44 IConsoleStdLibRegister(); |
270 IConsoleClearCommand(); |
|
271 IConsoleHistoryAdd(""); |
|
272 } |
|
273 |
|
274 void IConsoleClearBuffer() |
|
275 { |
|
276 uint i; |
|
277 for (i = 0; i <= ICON_BUFFER; i++) { |
|
278 free(_iconsole_buffer[i]); |
|
279 _iconsole_buffer[i] = NULL; |
|
280 } |
|
281 } |
|
282 |
|
283 static void IConsoleClear() |
|
284 { |
|
285 free(_iconsole_cmdline.buf); |
|
286 IConsoleClearBuffer(); |
|
287 } |
45 } |
288 |
46 |
289 static void IConsoleWriteToLogFile(const char *string) |
47 static void IConsoleWriteToLogFile(const char *string) |
290 { |
48 { |
291 if (_iconsole_output_file != NULL) { |
49 if (_iconsole_output_file != NULL) { |
311 return false; |
69 return false; |
312 } |
70 } |
313 |
71 |
314 void IConsoleFree() |
72 void IConsoleFree() |
315 { |
73 { |
316 IConsoleClear(); |
74 IConsoleGUIFree(); |
317 CloseConsoleLogIfActive(); |
75 CloseConsoleLogIfActive(); |
318 } |
|
319 |
|
320 void IConsoleResize(Window *w) |
|
321 { |
|
322 switch (_iconsole_mode) { |
|
323 case ICONSOLE_OPENED: |
|
324 w->height = _screen.height / 3; |
|
325 w->width = _screen.width; |
|
326 break; |
|
327 case ICONSOLE_FULL: |
|
328 w->height = _screen.height - ICON_BOTTOM_BORDERWIDTH; |
|
329 w->width = _screen.width; |
|
330 break; |
|
331 default: return; |
|
332 } |
|
333 |
|
334 MarkWholeScreenDirty(); |
|
335 } |
|
336 |
|
337 void IConsoleSwitch() |
|
338 { |
|
339 switch (_iconsole_mode) { |
|
340 case ICONSOLE_CLOSED: |
|
341 new IConsoleWindow(&_iconsole_window_desc); |
|
342 break; |
|
343 |
|
344 case ICONSOLE_OPENED: case ICONSOLE_FULL: |
|
345 DeleteWindowById(WC_CONSOLE, 0); |
|
346 break; |
|
347 } |
|
348 |
|
349 MarkWholeScreenDirty(); |
|
350 } |
|
351 |
|
352 void IConsoleClose() {if (_iconsole_mode == ICONSOLE_OPENED) IConsoleSwitch();} |
|
353 void IConsoleOpen() {if (_iconsole_mode == ICONSOLE_CLOSED) IConsoleSwitch();} |
|
354 |
|
355 /** |
|
356 * Add the entered line into the history so you can look it back |
|
357 * scroll, etc. Put it to the beginning as it is the latest text |
|
358 * @param cmd Text to be entered into the 'history' |
|
359 */ |
|
360 static void IConsoleHistoryAdd(const char *cmd) |
|
361 { |
|
362 free(_iconsole_history[ICON_HISTORY_SIZE - 1]); |
|
363 |
|
364 memmove(&_iconsole_history[1], &_iconsole_history[0], sizeof(_iconsole_history[0]) * (ICON_HISTORY_SIZE - 1)); |
|
365 _iconsole_history[0] = strdup(cmd); |
|
366 IConsoleResetHistoryPos(); |
|
367 } |
|
368 |
|
369 /** |
|
370 * Navigate Up/Down in the history of typed commands |
|
371 * @param direction Go further back in history (+1), go to recently typed commands (-1) |
|
372 */ |
|
373 static void IConsoleHistoryNavigate(int direction) |
|
374 { |
|
375 int i = _iconsole_historypos + direction; |
|
376 |
|
377 /* watch out for overflows, just wrap around */ |
|
378 if (i < 0) i = ICON_HISTORY_SIZE - 1; |
|
379 if (i >= ICON_HISTORY_SIZE) i = 0; |
|
380 |
|
381 if (direction > 0) |
|
382 if (_iconsole_history[i] == NULL) i = 0; |
|
383 |
|
384 if (direction < 0) { |
|
385 while (i > 0 && _iconsole_history[i] == NULL) i--; |
|
386 } |
|
387 |
|
388 _iconsole_historypos = i; |
|
389 IConsoleClearCommand(); |
|
390 /* copy history to 'command prompt / bash' */ |
|
391 assert(_iconsole_history[i] != NULL && IsInsideMM(i, 0, ICON_HISTORY_SIZE)); |
|
392 ttd_strlcpy(_iconsole_cmdline.buf, _iconsole_history[i], _iconsole_cmdline.maxlength); |
|
393 UpdateTextBufferSize(&_iconsole_cmdline); |
|
394 } |
76 } |
395 |
77 |
396 /** |
78 /** |
397 * Handle the printing of text entered into the console or redirected there |
79 * Handle the printing of text entered into the console or redirected there |
398 * by any other means. Text can be redirected to other players in a network game |
80 * by any other means. Text can be redirected to other players in a network game |