35 #include "network/ipaddress.h" |
35 #include "network/ipaddress.h" |
36 #include "coloredline.h" |
36 #include "coloredline.h" |
37 |
37 |
38 static const int g_pageSize = 10; |
38 static const int g_pageSize = 10; |
39 |
39 |
40 enum InputState |
40 // ------------------------------------------------------------------------------------------------- |
41 { |
41 // |
42 INPUTSTATE_NORMAL, |
42 int Interface::color_pair (Color fg, Color bg) |
43 INPUTSTATE_ADDRESS, |
|
44 INPUTSTATE_PASSWORD, |
|
45 INPUTSTATE_CONFIRM_DISCONNECTION, |
|
46 }; |
|
47 |
|
48 static StringList InputHistory; |
|
49 static int InputCursor = 0; |
|
50 static int CursorPosition = 0; |
|
51 static int InputPanning = 0; |
|
52 static bool NeedRefresh = false; |
|
53 static bool NeedStatusBarRender = false; |
|
54 static bool NeedInputRender = false; |
|
55 static bool NeedOutputRender = false; |
|
56 static bool NeedNicklistRender = false; |
|
57 static struct { char ch; int x; } CursorCharacter; |
|
58 static Vector<ColoredLine> OutputLines; |
|
59 static int OutputScroll = 0; |
|
60 static String Title; |
|
61 static InputState CurrentInputState = INPUTSTATE_NORMAL; |
|
62 static Function<void (void)> DisconnectConfirmFunction = nullptr; |
|
63 static IPAddress CurrentAddress; |
|
64 static String StatusBarText; |
|
65 static StringList PlayerNames; |
|
66 static String PasteBuffer; |
|
67 |
|
68 // ------------------------------------------------------------------------------------------------- |
|
69 // |
|
70 static FUNCTION |
|
71 interface_color_pair (Color fg, Color bg) -> int |
|
72 { |
43 { |
73 return COLOR_PAIR ((int (fg) * NUM_COLORS) + int (bg)); |
44 return COLOR_PAIR ((int (fg) * NUM_COLORS) + int (bg)); |
74 } |
45 } |
75 |
46 |
76 // ------------------------------------------------------------------------------------------------- |
47 // ------------------------------------------------------------------------------------------------- |
77 // |
48 // |
78 static FUNCTION |
49 const String& Interface::current_input() |
79 current_input() -> const String& |
|
80 { |
50 { |
81 return InputHistory[InputCursor]; |
51 return InputHistory[InputCursor]; |
82 } |
52 } |
83 |
53 |
84 // ------------------------------------------------------------------------------------------------- |
54 // ------------------------------------------------------------------------------------------------- |
85 // |
55 // |
86 // Makes current_input() the lastmost input (so that we won't modify history) |
56 // Makes current_input() the lastmost input (so that we won't modify history) |
87 // |
57 // |
88 static FUNCTION |
58 void Interface::detach_input() |
89 detach_input() -> void |
|
90 { |
59 { |
91 if (InputCursor > 0) |
60 if (InputCursor > 0) |
92 { |
61 { |
93 InputHistory[0] = current_input(); |
62 InputHistory[0] = current_input(); |
94 InputCursor = 0; |
63 InputCursor = 0; |
96 } |
65 } |
97 |
66 |
98 // ------------------------------------------------------------------------------------------------- |
67 // ------------------------------------------------------------------------------------------------- |
99 // A version of current_input() that allows changing the contents of it. |
68 // A version of current_input() that allows changing the contents of it. |
100 // |
69 // |
101 static FUNCTION |
70 String& Interface::mutable_current_input() |
102 mutable_current_input() -> String& |
|
103 { |
71 { |
104 detach_input(); |
72 detach_input(); |
105 return InputHistory[InputCursor]; |
73 return InputHistory[InputCursor]; |
106 } |
74 } |
107 |
75 |
108 // ------------------------------------------------------------------------------------------------- |
76 // ------------------------------------------------------------------------------------------------- |
109 // |
77 // |
110 static FUNCTION |
78 void Interface::move_input_cursor (int delta) |
111 move_input_cursor (int delta) -> void |
|
112 { |
79 { |
113 // No input history when inputting addresses or passwords |
80 // No input history when inputting addresses or passwords |
114 if (CurrentInputState != INPUTSTATE_NORMAL) |
81 if (CurrentInputState != INPUTSTATE_NORMAL) |
115 { |
82 { |
116 InputCursor = 0; |
83 InputCursor = 0; |
145 return prompt; |
111 return prompt; |
146 } |
112 } |
147 |
113 |
148 // ------------------------------------------------------------------------------------------------- |
114 // ------------------------------------------------------------------------------------------------- |
149 // |
115 // |
150 static FUNCTION |
116 void Interface::set_input_state (InputState newstate) |
151 set_input_state (InputState newstate) -> void |
|
152 { |
117 { |
153 // Clear the input row (unless going to or from confirm state) |
118 // Clear the input row (unless going to or from confirm state) |
154 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION |
119 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION |
155 and CurrentInputState != INPUTSTATE_CONFIRM_DISCONNECTION) |
120 and CurrentInputState != INPUTSTATE_CONFIRM_DISCONNECTION) |
156 { |
121 { |
205 NeedRefresh = false; |
170 NeedRefresh = false; |
206 } |
171 } |
207 |
172 |
208 // ------------------------------------------------------------------------------------------------- |
173 // ------------------------------------------------------------------------------------------------- |
209 // |
174 // |
210 static FUNCTION |
175 void Interface::render_titlebar() |
211 interface_render_titlebar() -> void |
|
212 { |
176 { |
213 if (Title.length() <= COLS) |
177 if (Title.length() <= COLS) |
214 { |
178 { |
215 int pair = interface_color_pair (WHITE, BLUE); |
179 int pair = color_pair (WHITE, BLUE); |
216 int startx = (COLS - Title.length()) / 2; |
180 int startx = (COLS - Title.length()) / 2; |
217 int endx = startx + Title.length(); |
181 int endx = startx + Title.length(); |
218 attron (pair); |
182 attron (pair); |
219 mvprintw (0, startx, "%s", Title.chars()); |
183 mvprintw (0, startx, "%s", Title.chars()); |
220 mvhline (0, 0, ' ', startx); |
184 mvhline (0, 0, ' ', startx); |
225 NeedRefresh = true; |
189 NeedRefresh = true; |
226 } |
190 } |
227 |
191 |
228 // ------------------------------------------------------------------------------------------------- |
192 // ------------------------------------------------------------------------------------------------- |
229 // |
193 // |
230 FUNCTION |
194 void Interface::set_title (const String& title) |
231 Interface::set_title (const String& title) -> void |
|
232 { |
195 { |
233 Title = title; |
196 Title = title; |
234 interface_render_titlebar(); |
197 render_titlebar(); |
235 } |
198 } |
236 |
199 |
237 // ------------------------------------------------------------------------------------------------- |
200 // ------------------------------------------------------------------------------------------------- |
238 // |
201 // |
239 static FUNCTION |
202 void Interface::safe_disconnect (Function<void()> afterwards) |
240 safe_disconnect (Function<void()> afterwards) -> void |
203 { |
241 { |
204 if (Session.is_active()) |
242 if (RCONSession::get_session()->is_active()) |
|
243 { |
205 { |
244 DisconnectConfirmFunction = afterwards; |
206 DisconnectConfirmFunction = afterwards; |
245 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); |
207 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); |
246 } |
208 } |
247 else |
209 else |
248 afterwards(); |
210 afterwards(); |
249 } |
211 } |
250 |
212 |
251 // ------------------------------------------------------------------------------------------------- |
213 // ------------------------------------------------------------------------------------------------- |
252 // |
214 // |
253 static FUNCTION |
215 int Interface::nicklist_width() |
254 interface_nicklist_width() -> int |
|
255 { |
216 { |
256 // Allocate at least 12 characters, at most 24 characters, for the nicklist. If we cannot |
217 // Allocate at least 12 characters, at most 24 characters, for the nicklist. If we cannot |
257 // afford that (o_O) then we probably shouldn't draw the nicklist at all I think. |
218 // afford that (o_O) then we probably shouldn't draw the nicklist at all I think. |
258 int nicklistWidth = COLS / 4; |
219 int nicklistWidth = COLS / 4; |
259 |
220 |
265 |
226 |
266 // ------------------------------------------------------------------------------------------------- |
227 // ------------------------------------------------------------------------------------------------- |
267 // Renders the given colored line onto the screen. Will wrap if allowWrap is true. Returns the |
228 // Renders the given colored line onto the screen. Will wrap if allowWrap is true. Returns the |
268 // 'y' value for the next line. |
229 // 'y' value for the next line. |
269 // |
230 // |
270 static FUNCTION |
231 int Interface::render_colorline (int y, int x0, int width, const ColoredLine& line, bool allowWrap) |
271 interface_render_colorline (int y, int x0, int width, |
|
272 const ColoredLine& line, bool allowWrap) -> int |
|
273 { |
232 { |
274 int x = x0; |
233 int x = x0; |
275 |
234 |
276 for (int byte : line.data()) |
235 for (int byte : line.data()) |
277 { |
236 { |
297 case RLINE_ON_YELLOW: |
256 case RLINE_ON_YELLOW: |
298 case RLINE_ON_BLUE: |
257 case RLINE_ON_BLUE: |
299 case RLINE_ON_MAGENTA: |
258 case RLINE_ON_MAGENTA: |
300 case RLINE_ON_CYAN: |
259 case RLINE_ON_CYAN: |
301 case RLINE_ON_WHITE: |
260 case RLINE_ON_WHITE: |
302 attron (interface_color_pair (Color (byte - RLINE_ON_BLACK), DEFAULT)); |
261 attron (color_pair (Color (byte - RLINE_ON_BLACK), DEFAULT)); |
303 break; |
262 break; |
304 |
263 |
305 case RLINE_OFF_BLACK: |
264 case RLINE_OFF_BLACK: |
306 case RLINE_OFF_RED: |
265 case RLINE_OFF_RED: |
307 case RLINE_OFF_GREEN: |
266 case RLINE_OFF_GREEN: |
308 case RLINE_OFF_YELLOW: |
267 case RLINE_OFF_YELLOW: |
309 case RLINE_OFF_BLUE: |
268 case RLINE_OFF_BLUE: |
310 case RLINE_OFF_MAGENTA: |
269 case RLINE_OFF_MAGENTA: |
311 case RLINE_OFF_CYAN: |
270 case RLINE_OFF_CYAN: |
312 case RLINE_OFF_WHITE: |
271 case RLINE_OFF_WHITE: |
313 attroff (interface_color_pair (Color (byte - RLINE_OFF_BLACK), DEFAULT)); |
272 attroff (color_pair (Color (byte - RLINE_OFF_BLACK), DEFAULT)); |
314 break; |
273 break; |
315 |
274 |
316 case RLINE_ON_BOLD: |
275 case RLINE_ON_BOLD: |
317 attron (A_BOLD); |
276 attron (A_BOLD); |
318 break; |
277 break; |
326 return y + 1; |
285 return y + 1; |
327 } |
286 } |
328 |
287 |
329 // ------------------------------------------------------------------------------------------------- |
288 // ------------------------------------------------------------------------------------------------- |
330 // |
289 // |
331 static FUNCTION |
290 void Interface::render_output() |
332 interface_render_output() -> void |
|
333 { |
291 { |
334 if (OutputLines.size() == 1) |
292 if (OutputLines.size() == 1) |
335 return; |
293 return; |
336 |
294 |
337 OutputScroll = clamp (OutputScroll, 0, OutputLines.size() - 1); |
295 OutputScroll = clamp (OutputScroll, 0, OutputLines.size() - 1); |
338 |
296 |
339 int height = LINES - 3; |
297 int height = LINES - 3; |
340 int width = COLS - interface_nicklist_width(); |
298 int width = COLS - nicklist_width(); |
341 int printOffset = 0; |
299 int printOffset = 0; |
342 int end = OutputLines.size() - 1 - OutputScroll; |
300 int end = OutputLines.size() - 1 - OutputScroll; |
343 int start = end; |
301 int start = end; |
344 int usedHeight = 0; |
302 int usedHeight = 0; |
345 int y = 1; |
303 int y = 1; |
395 |
353 |
396 // Print the lines |
354 // Print the lines |
397 y += printOffset; |
355 y += printOffset; |
398 |
356 |
399 for (int i = start; i < end; ++i) |
357 for (int i = start; i < end; ++i) |
400 y = interface_render_colorline (y, 0, width, OutputLines[i], true); |
358 y = render_colorline (y, 0, width, OutputLines[i], true); |
401 |
359 |
402 NeedOutputRender = false; |
360 NeedOutputRender = false; |
403 NeedRefresh = true; |
361 NeedRefresh = true; |
404 } |
362 } |
405 |
363 |
406 // ------------------------------------------------------------------------------------------------- |
364 // ------------------------------------------------------------------------------------------------- |
407 // |
365 // |
408 static FUNCTION |
366 void Interface::render_nicklist() |
409 interface_render_nicklist() -> void |
367 { |
410 { |
368 int width = nicklist_width(); |
411 int width = interface_nicklist_width(); |
|
412 int height = LINES- 3; |
369 int height = LINES- 3; |
413 int y = 1; |
370 int y = 1; |
414 int x = COLS - width; |
371 int x = COLS - width; |
415 |
372 |
416 if (width == 0) |
373 if (width == 0) |
440 NeedRefresh = true; |
397 NeedRefresh = true; |
441 } |
398 } |
442 |
399 |
443 // ------------------------------------------------------------------------------------------------- |
400 // ------------------------------------------------------------------------------------------------- |
444 // |
401 // |
445 static FUNCTION |
402 void Interface::render_input() |
446 interface_render_input() -> void |
403 { |
447 { |
404 int promptColor = color_pair (WHITE, BLUE); |
448 int promptColor = interface_color_pair (WHITE, BLUE); |
|
449 |
405 |
450 // If we're asking the user if they want to disconnect, we don't render any input strings, |
406 // If we're asking the user if they want to disconnect, we don't render any input strings, |
451 // just the confirmation message. |
407 // just the confirmation message. |
452 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
408 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
453 { |
409 { |
457 attroff (promptColor); |
413 attroff (promptColor); |
458 NeedRefresh = true; |
414 NeedRefresh = true; |
459 return; |
415 return; |
460 } |
416 } |
461 |
417 |
462 String prompt = interface_prompt_string(); |
418 String prompt = prompt_string(); |
463 int displayLength = COLS - prompt.length() - 2; |
419 int displayLength = COLS - prompt.length() - 2; |
464 String displayString = current_input(); |
420 String displayString = current_input(); |
465 int y = LINES - 2; |
421 int y = LINES - 2; |
466 |
422 |
467 // If we're inputting a password, replace it with asterisks |
423 // If we're inputting a password, replace it with asterisks |
502 NeedInputRender = false; |
458 NeedInputRender = false; |
503 } |
459 } |
504 |
460 |
505 // ------------------------------------------------------------------------------------------------- |
461 // ------------------------------------------------------------------------------------------------- |
506 // |
462 // |
507 static FUNCTION |
463 void Interface::render_statusbar() |
508 interface_render_statusbar() -> void |
464 { |
509 { |
465 int color = color_pair (WHITE, BLUE); |
510 int color = interface_color_pair (WHITE, BLUE); |
|
511 int y = LINES - 1; |
466 int y = LINES - 1; |
512 attron (color); |
467 attron (color); |
513 mvhline (y, 0, ' ', COLS); |
468 mvhline (y, 0, ' ', COLS); |
514 mvprintw (y, 0, "%s", StatusBarText.chars()); |
469 mvprintw (y, 0, "%s", StatusBarText.chars()); |
515 attroff (color); |
470 attroff (color); |
517 NeedStatusBarRender = false; |
472 NeedStatusBarRender = false; |
518 } |
473 } |
519 |
474 |
520 // ------------------------------------------------------------------------------------------------- |
475 // ------------------------------------------------------------------------------------------------- |
521 // |
476 // |
522 FUNCTION |
477 void Interface::update_statusbar() |
523 Interface::update_statusbar() -> void |
|
524 { |
478 { |
525 String text; |
479 String text; |
526 RCONSession* session = RCONSession::get_session(); |
480 |
527 |
481 switch (Session.state()) |
528 switch (session->state()) |
|
529 { |
482 { |
530 case RCON_DISCONNECTED: |
483 case RCON_DISCONNECTED: |
531 text = "Disconnected."; |
484 text = "Disconnected."; |
532 break; |
485 break; |
533 |
486 |
534 case RCON_CONNECTING: |
487 case RCON_CONNECTING: |
535 case RCON_AUTHENTICATING: |
488 case RCON_AUTHENTICATING: |
536 text = "Connecting to " + session->address().to_string (IP_WITH_PORT) + "..."; |
489 text = "Connecting to " + Session.address().to_string (IP_WITH_PORT) + "..."; |
537 break; |
490 break; |
538 |
491 |
539 case RCON_CONNECTED: |
492 case RCON_CONNECTED: |
540 { |
493 { |
541 String adminText = (session->num_admins() == 0) ? "No other admins" |
494 String adminText; |
542 : format ("%1 other admin%s1", session->num_admins()); |
495 |
543 text = format ("%1 | %2 | %3", session->address().to_string (IP_WITH_PORT), |
496 if (Session.num_admins() == 0) |
544 session->level(), adminText); |
497 adminText = "No other admins"; |
|
498 else |
|
499 adminText = format ("%1 other admin%s1", Session.num_admins()); |
|
500 |
|
501 text = format ("%1 | %2 | %3", Session.address().to_string (IP_WITH_PORT), |
|
502 Session.level(), adminText); |
545 } |
503 } |
546 break; |
504 break; |
547 } |
505 } |
548 |
506 |
549 if (not text.is_empty()) |
507 if (not text.is_empty()) |
558 } |
516 } |
559 } |
517 } |
560 |
518 |
561 // ------------------------------------------------------------------------------------------------- |
519 // ------------------------------------------------------------------------------------------------- |
562 // |
520 // |
563 FUNCTION |
521 void Interface::render_full() |
564 Interface::render_full() -> void |
|
565 { |
522 { |
566 update_statusbar(); |
523 update_statusbar(); |
567 interface_render_titlebar(); |
524 render_titlebar(); |
568 interface_render_output(); |
525 render_output(); |
569 interface_render_statusbar(); |
526 render_statusbar(); |
570 interface_render_input(); |
527 render_input(); |
571 interface_render_nicklist(); |
528 render_nicklist(); |
572 } |
529 } |
573 |
530 |
574 // ------------------------------------------------------------------------------------------------- |
531 // ------------------------------------------------------------------------------------------------- |
575 // |
532 // |
576 static FUNCTION |
533 void Interface::position_cursor() |
577 interface_position_cursor() -> void |
|
578 { |
534 { |
579 // This is only relevant if the input string is being drawn |
535 // This is only relevant if the input string is being drawn |
580 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
536 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
581 return; |
537 return; |
582 |
538 |
583 int y = LINES - 2; |
539 int y = LINES - 2; |
584 |
540 |
585 if (CursorCharacter.ch != '\0') |
541 if (CursorCharacter.ch != '\0') |
586 mvprintw (y, CursorCharacter.x, "%c", CursorCharacter.ch); |
542 mvprintw (y, CursorCharacter.x, "%c", CursorCharacter.ch); |
587 else |
543 else |
588 mvprintw (y, interface_prompt_string().length(), " "); |
544 mvprintw (y, prompt_string().length(), " "); |
589 } |
545 } |
590 |
546 |
591 // ------------------------------------------------------------------------------------------------- |
547 // ------------------------------------------------------------------------------------------------- |
592 // |
548 // |
593 static FUNCTION |
549 int Interface::find_previous_word() |
594 interface_find_previous_word() -> int |
|
595 { |
550 { |
596 const String& input = current_input(); |
551 const String& input = current_input(); |
597 int pos = CursorPosition; |
552 int pos = CursorPosition; |
598 |
553 |
599 // Move past whitespace |
554 // Move past whitespace |
607 return pos; |
562 return pos; |
608 } |
563 } |
609 |
564 |
610 // ------------------------------------------------------------------------------------------------- |
565 // ------------------------------------------------------------------------------------------------- |
611 // |
566 // |
612 static FUNCTION |
567 int Interface::find_next_word() |
613 interface_find_next_word() -> int |
|
614 { |
568 { |
615 const String& input = current_input(); |
569 const String& input = current_input(); |
616 int pos = CursorPosition; |
570 int pos = CursorPosition; |
617 |
571 |
618 // Move past current whitespace |
572 // Move past current whitespace |
659 |
611 |
660 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
612 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
661 { |
613 { |
662 if (ch == 'y' or ch == 'Y') |
614 if (ch == 'y' or ch == 'Y') |
663 { |
615 { |
664 RCONSession::get_session()->disconnect(); |
616 Session.disconnect(); |
665 DisconnectConfirmFunction(); |
617 DisconnectConfirmFunction(); |
666 } |
618 } |
667 else if (ch == 'n' or ch == 'N') |
619 else if (ch == 'n' or ch == 'N') |
668 set_input_state (INPUTSTATE_NORMAL); |
620 set_input_state (INPUTSTATE_NORMAL); |
669 |
621 |
682 { |
634 { |
683 case INPUTSTATE_CONFIRM_DISCONNECTION: |
635 case INPUTSTATE_CONFIRM_DISCONNECTION: |
684 break; |
636 break; |
685 |
637 |
686 case INPUTSTATE_NORMAL: |
638 case INPUTSTATE_NORMAL: |
687 safe_disconnect ([]() |
639 safe_disconnect ([&]() |
688 { |
640 { |
689 RCONSession* session = RCONSession::get_session(); |
641 if (Session.is_active()) |
690 |
|
691 if (session->is_active()) |
|
692 { |
642 { |
693 session->disconnect(); |
643 Session.disconnect(); |
694 set_input_state (INPUTSTATE_NORMAL); |
644 set_input_state (INPUTSTATE_NORMAL); |
695 } |
645 } |
696 else |
646 else |
697 { |
647 { |
698 endwin(); |
648 endwin(); |
789 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end |
739 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end |
790 yank (CursorPosition, mutable_current_input().length()); |
740 yank (CursorPosition, mutable_current_input().length()); |
791 break; |
741 break; |
792 |
742 |
793 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current |
743 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current |
794 yank (interface_find_previous_word(), CursorPosition); |
744 yank (find_previous_word(), CursorPosition); |
795 break; |
745 break; |
796 |
746 |
797 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text |
747 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text |
798 if (not PasteBuffer.is_empty()) |
748 if (not PasteBuffer.is_empty()) |
799 { |
749 { |
806 case '\t': |
756 case '\t': |
807 { |
757 { |
808 int space = current_input().find (" "); |
758 int space = current_input().find (" "); |
809 |
759 |
810 if (CurrentInputState == INPUTSTATE_NORMAL |
760 if (CurrentInputState == INPUTSTATE_NORMAL |
811 and InputCursor > 0 |
761 and CursorPosition > 0 |
812 and (space == -1 or space >= InputCursor)) |
762 and (space == -1 or space >= CursorPosition)) |
813 { |
763 { |
814 String start = current_input().mid (0, InputCursor); |
764 String start = current_input().mid (0, CursorPosition); |
815 RCONSession::get_session()->request_tab_complete (start); |
765 Session.request_tab_complete (start); |
816 } |
766 } |
817 } |
767 } |
818 break; |
768 break; |
819 |
769 |
820 case '\n': |
770 case '\n': |
842 break; |
792 break; |
843 |
793 |
844 case INPUTSTATE_PASSWORD: |
794 case INPUTSTATE_PASSWORD: |
845 if (CurrentInputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) |
795 if (CurrentInputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) |
846 { |
796 { |
847 RCONSession* session = RCONSession::get_session(); |
797 Session.disconnect(); |
848 session->disconnect(); |
798 Session.set_password (current_input()); |
849 session->set_password (current_input()); |
799 Session.connect (CurrentAddress); |
850 session->connect (CurrentAddress); |
|
851 set_input_state (INPUTSTATE_NORMAL); |
800 set_input_state (INPUTSTATE_NORMAL); |
852 } |
801 } |
853 break; |
802 break; |
854 |
803 |
855 case INPUTSTATE_NORMAL: |
804 case INPUTSTATE_NORMAL: |
856 if (RCONSession::get_session()->send_command (current_input())) |
805 if (Session.send_command (current_input())) |
857 { |
806 { |
858 InputHistory.insert (0, ""); |
807 InputHistory.insert (0, ""); |
859 NeedInputRender = true; |
808 NeedInputRender = true; |
860 } |
809 } |
861 break; |
810 break; |
862 } |
811 } |
863 break; |
812 break; |
864 |
813 |
865 case 'N' - 'A' + 1: // ^N |
814 case 'N' - 'A' + 1: // ^N |
866 if (CurrentInputState == INPUTSTATE_NORMAL) |
815 if (CurrentInputState == INPUTSTATE_NORMAL) |
867 safe_disconnect ([]() {set_input_state (INPUTSTATE_ADDRESS);}); |
816 safe_disconnect ([&]() {set_input_state (INPUTSTATE_ADDRESS);}); |
868 break; |
817 break; |
869 |
818 |
870 case '\e': // Escape |
819 case '\e': // Escape |
871 // We may have an alt key coming |
820 // We may have an alt key coming |
872 ch = ::getch(); |
821 ch = ::getch(); |
876 switch (ch) |
825 switch (ch) |
877 { |
826 { |
878 case 'b': |
827 case 'b': |
879 case 'B': |
828 case 'B': |
880 // readline alt-b - move one word to the left |
829 // readline alt-b - move one word to the left |
881 CursorPosition = interface_find_previous_word(); |
830 CursorPosition = find_previous_word(); |
882 NeedInputRender = true; |
831 NeedInputRender = true; |
883 break; |
832 break; |
884 |
833 |
885 case 'f': |
834 case 'f': |
886 case 'F': |
835 case 'F': |
887 // readline alt-f - move one word to the right |
836 // readline alt-f - move one word to the right |
888 CursorPosition = interface_find_next_word(); |
837 CursorPosition = find_next_word(); |
889 NeedInputRender = true; |
838 NeedInputRender = true; |
890 break; |
839 break; |
891 |
840 |
892 case 'd': |
841 case 'd': |
893 case 'D': |
842 case 'D': |
894 // readline alt-d - delete from here till next word boundary |
843 // readline alt-d - delete from here till next word boundary |
895 yank (CursorPosition, interface_find_next_word()); |
844 yank (CursorPosition, find_next_word()); |
896 break; |
845 break; |
897 } |
846 } |
898 } |
847 } |
899 else |
848 else |
900 { |
849 { |
910 render(); |
859 render(); |
911 } |
860 } |
912 |
861 |
913 // ------------------------------------------------------------------------------------------------- |
862 // ------------------------------------------------------------------------------------------------- |
914 // |
863 // |
915 FUNCTION |
864 void Interface::render() |
916 Interface::render() -> void |
865 { |
917 { |
866 if (NeedStatusBarRender) render_statusbar(); |
918 if (NeedStatusBarRender) interface_render_statusbar(); |
867 if (NeedInputRender) render_input(); |
919 if (NeedInputRender) interface_render_input(); |
868 if (NeedOutputRender) render_output(); |
920 if (NeedOutputRender) interface_render_output(); |
869 if (NeedNicklistRender) render_nicklist(); |
921 if (NeedNicklistRender) interface_render_nicklist(); |
|
922 |
870 |
923 if (NeedRefresh) |
871 if (NeedRefresh) |
924 { |
872 { |
925 interface_position_cursor(); |
873 position_cursor(); |
926 refresh(); |
874 refresh(); |
927 NeedRefresh = false; |
875 NeedRefresh = false; |
928 } |
876 } |
929 } |
877 } |
930 |
878 |
931 // ------------------------------------------------------------------------------------------------- |
879 // ------------------------------------------------------------------------------------------------- |
932 // |
880 // |
933 FUNCTION print_to_console (String a) -> void |
881 void Interface::print_to_console (String a) |
934 { |
882 { |
935 // Zandronum is retarded and SOMETIMES sends color codes as "\\c" and sometimes as "\x1C". |
883 // Zandronum sometimes sends color codes as "\\c" and sometimes as "\x1C". |
936 // Let's correct that on our end and HOPE this won't cause conflicts. |
884 // Let's correct that on our end and hope this won't cause conflicts. |
937 a.replace ("\\c", "\x1C"); |
885 a.replace ("\\c", "\x1C"); |
938 |
886 |
939 for (char ch : a) |
887 for (char ch : a) |
940 { |
888 { |
941 if (ch == '\n') |
889 if (ch == '\n') |
978 } |
925 } |
979 |
926 |
980 if (CurrentAddress.port == 0) |
927 if (CurrentAddress.port == 0) |
981 CurrentAddress.port = 10666; |
928 CurrentAddress.port = 10666; |
982 |
929 |
983 RCONSession* session = RCONSession::get_session(); |
930 Session.disconnect(); |
984 session->disconnect(); |
931 Session.set_password (password); |
985 session->set_password (password); |
932 Session.connect (CurrentAddress); |
986 session->connect (CurrentAddress); |
933 } |
987 } |
934 |
988 |
935 // ------------------------------------------------------------------------------------------------- |
989 // ------------------------------------------------------------------------------------------------- |
936 // |
990 // |
937 void Interface::set_player_names (const StringList& names) |
991 FUNCTION |
|
992 Interface::set_player_names (const StringList& names) -> void |
|
993 { |
938 { |
994 PlayerNames = names; |
939 PlayerNames = names; |
995 NeedNicklistRender = true; |
940 NeedNicklistRender = true; |
996 } |
941 } |
997 |
942 |
998 // ------------------------------------------------------------------------------------------------- |
943 // ------------------------------------------------------------------------------------------------- |
999 // |
944 // |
1000 FUNCTION |
945 void Interface::tab_complete (const String& part, String complete) |
1001 Interface::tab_complete (const String& part, String complete) -> void |
|
1002 { |
946 { |
1003 String& input = mutable_current_input(); |
947 String& input = mutable_current_input(); |
1004 |
948 |
1005 if (input.starts_with (part)) |
949 if (input.starts_with (part)) |
1006 { |
950 { |
1007 if (input[part.length()] != ' ') |
951 if (input[part.length()] != ' ') |
1008 complete += ' '; |
952 complete += ' '; |
1009 |
953 |
1010 input.replace (0, part.length(), complete); |
954 input.replace (0, part.length(), complete); |
1011 InputCursor = complete.length(); |
955 CursorPosition = complete.length(); |
1012 NeedInputRender = true; |
956 NeedInputRender = true; |
1013 } |
957 } |
1014 } |
958 } |