sources/interface.cpp

changeset 69
eb4c25284a19
parent 58
d175243ad169
child 71
4f7c2c944637
equal deleted inserted replaced
68:202e74157de5 69:eb4c25284a19
43 INPUTSTATE_ADDRESS, 43 INPUTSTATE_ADDRESS,
44 INPUTSTATE_PASSWORD, 44 INPUTSTATE_PASSWORD,
45 INPUTSTATE_CONFIRM_DISCONNECTION, 45 INPUTSTATE_CONFIRM_DISCONNECTION,
46 }; 46 };
47 47
48 static StringList g_input; 48 static StringList InputHistory;
49 static int g_inputCursor = 0; 49 static int InputCursor = 0;
50 static int g_cursor = 0; 50 static int CursorPosition = 0;
51 static int g_pan = 0; 51 static int InputPanning = 0;
52 static bool g_needRefresh = false; 52 static bool NeedRefresh = false;
53 static bool g_needStatusBarRender = false; 53 static bool NeedStatusBarRender = false;
54 static bool g_needInputRender = false; 54 static bool NeedInputRender = false;
55 static bool g_needOutputRender = false; 55 static bool NeedOutputRender = false;
56 static bool g_needNicklistRender = false; 56 static bool NeedNicklistRender = false;
57 static struct { char ch; int x; } g_cursorChar; 57 static struct { char ch; int x; } CursorCharacter;
58 static Vector<ColoredLine> g_output;; 58 static Vector<ColoredLine> OutputLines;
59 static int g_outputScroll = 0; 59 static int OutputScroll = 0;
60 static String g_title; 60 static String Title;
61 static InputState g_inputState = INPUTSTATE_NORMAL; 61 static InputState CurrentInputState = INPUTSTATE_NORMAL;
62 static Function<void (void)> g_disconnectConfirmFunction = nullptr; 62 static Function<void (void)> DisconnectConfirmFunction = nullptr;
63 static IPAddress g_address; 63 static IPAddress CurrentAddress;
64 static String g_statusBarText; 64 static String StatusBarText;
65 static StringList g_playerNames; 65 static StringList PlayerNames;
66 static String g_pasteBuffer; 66 static String PasteBuffer;
67 67
68 // ------------------------------------------------------------------------------------------------- 68 // -------------------------------------------------------------------------------------------------
69 // 69 //
70 static FUNCTION 70 static FUNCTION
71 interface_color_pair (Color fg, Color bg) -> int 71 interface_color_pair (Color fg, Color bg) -> int
76 // ------------------------------------------------------------------------------------------------- 76 // -------------------------------------------------------------------------------------------------
77 // 77 //
78 static FUNCTION 78 static FUNCTION
79 current_input() -> const String& 79 current_input() -> const String&
80 { 80 {
81 return g_input[g_inputCursor]; 81 return InputHistory[InputCursor];
82 } 82 }
83 83
84 // ------------------------------------------------------------------------------------------------- 84 // -------------------------------------------------------------------------------------------------
85 // 85 //
86 // Makes current_input() the lastmost input (so that we won't modify history) 86 // Makes current_input() the lastmost input (so that we won't modify history)
87 // 87 //
88 static FUNCTION 88 static FUNCTION
89 detach_input() -> void 89 detach_input() -> void
90 { 90 {
91 if (g_inputCursor > 0) 91 if (InputCursor > 0)
92 { 92 {
93 g_input[0] = current_input(); 93 InputHistory[0] = current_input();
94 g_inputCursor = 0; 94 InputCursor = 0;
95 } 95 }
96 } 96 }
97 97
98 // ------------------------------------------------------------------------------------------------- 98 // -------------------------------------------------------------------------------------------------
99 // A version of current_input() that allows changing the contents of it. 99 // A version of current_input() that allows changing the contents of it.
100 // 100 //
101 static FUNCTION 101 static FUNCTION
102 mutable_current_input() -> String& 102 mutable_current_input() -> String&
103 { 103 {
104 detach_input(); 104 detach_input();
105 return g_input[g_inputCursor]; 105 return InputHistory[InputCursor];
106 } 106 }
107 107
108 // ------------------------------------------------------------------------------------------------- 108 // -------------------------------------------------------------------------------------------------
109 // 109 //
110 static FUNCTION 110 static FUNCTION
111 move_input_cursor (int delta) -> void 111 move_input_cursor (int delta) -> void
112 { 112 {
113 // No input history when inputting addresses or passwords 113 // No input history when inputting addresses or passwords
114 if (g_inputState != INPUTSTATE_NORMAL) 114 if (CurrentInputState != INPUTSTATE_NORMAL)
115 { 115 {
116 g_inputCursor = 0; 116 InputCursor = 0;
117 return; 117 return;
118 } 118 }
119 119
120 int oldcursor = g_inputCursor; 120 int oldcursor = InputCursor;
121 g_inputCursor = clamp (g_inputCursor + delta, 0, g_input.size() - 1); 121 InputCursor = clamp (InputCursor + delta, 0, InputHistory.size() - 1);
122 122
123 if (g_inputCursor != oldcursor) 123 if (InputCursor != oldcursor)
124 { 124 {
125 g_cursor = current_input().length(); 125 CursorPosition = current_input().length();
126 g_needInputRender = true; 126 NeedInputRender = true;
127 } 127 }
128 } 128 }
129 129
130 // ------------------------------------------------------------------------------------------------- 130 // -------------------------------------------------------------------------------------------------
131 // 131 //
132 static FUNCTION 132 static FUNCTION
133 interface_prompt_string() -> String 133 interface_prompt_string() -> String
134 { 134 {
135 String prompt; 135 String prompt;
136 136
137 switch (g_inputState) 137 switch (CurrentInputState)
138 { 138 {
139 case INPUTSTATE_NORMAL: prompt = ">"; break; 139 case INPUTSTATE_NORMAL: prompt = ">"; break;
140 case INPUTSTATE_ADDRESS: prompt = "address:"; break; 140 case INPUTSTATE_ADDRESS: prompt = "address:"; break;
141 case INPUTSTATE_PASSWORD: prompt = "password:"; break; 141 case INPUTSTATE_PASSWORD: prompt = "password:"; break;
142 case INPUTSTATE_CONFIRM_DISCONNECTION: break; 142 case INPUTSTATE_CONFIRM_DISCONNECTION: break;
150 static FUNCTION 150 static FUNCTION
151 set_input_state (InputState newstate) -> void 151 set_input_state (InputState newstate) -> void
152 { 152 {
153 // Clear the input row (unless going to or from confirm state) 153 // Clear the input row (unless going to or from confirm state)
154 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION 154 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION
155 and g_inputState != INPUTSTATE_CONFIRM_DISCONNECTION) 155 and CurrentInputState != INPUTSTATE_CONFIRM_DISCONNECTION)
156 { 156 {
157 g_inputCursor = 0; 157 InputCursor = 0;
158 mutable_current_input().clear(); 158 mutable_current_input().clear();
159 } 159 }
160 160
161 switch (newstate) 161 switch (newstate)
162 { 162 {
163 case INPUTSTATE_ADDRESS: 163 case INPUTSTATE_ADDRESS:
164 if (g_address.host != 0) 164 if (CurrentAddress.host != 0)
165 mutable_current_input() = g_address.to_string (IP_WITH_PORT); 165 mutable_current_input() = CurrentAddress.to_string (IP_WITH_PORT);
166 break; 166 break;
167 167
168 default: 168 default:
169 break; 169 break;
170 } 170 }
171 171
172 g_inputState = newstate; 172 CurrentInputState = newstate;
173 g_needInputRender = true; 173 NeedInputRender = true;
174 } 174 }
175 175
176 // ------------------------------------------------------------------------------------------------- 176 // -------------------------------------------------------------------------------------------------
177 // 177 //
178 FUNCTION 178 FUNCTION
184 ::keypad (stdscr, true); 184 ::keypad (stdscr, true);
185 ::noecho(); 185 ::noecho();
186 ::refresh(); 186 ::refresh();
187 ::timeout (0); 187 ::timeout (0);
188 ::use_default_colors(); 188 ::use_default_colors();
189 g_input.clear(); 189 InputHistory.clear();
190 g_input << ""; 190 InputHistory << "";
191 g_output.clear(); 191 OutputLines.clear();
192 g_output << ColoredLine(); 192 OutputLines << ColoredLine();
193 g_title = format (APPNAME " %1 (%2)", full_version_string(), changeset_date_string()); 193 Title = format (APPNAME " %1 (%2)", full_version_string(), changeset_date_string());
194 194
195 for (int i = 0; i < NUM_COLORS; ++i) 195 for (int i = 0; i < NUM_COLORS; ++i)
196 for (int j = 0; j < NUM_COLORS; ++j) 196 for (int j = 0; j < NUM_COLORS; ++j)
197 { 197 {
198 init_pair ((i * NUM_COLORS + j), 198 init_pair ((i * NUM_COLORS + j),
200 (j == DEFAULT) ? -1 : j); 200 (j == DEFAULT) ? -1 : j);
201 } 201 }
202 202
203 render_full(); 203 render_full();
204 refresh(); 204 refresh();
205 g_needRefresh = false; 205 NeedRefresh = false;
206 } 206 }
207 207
208 // ------------------------------------------------------------------------------------------------- 208 // -------------------------------------------------------------------------------------------------
209 // 209 //
210 static FUNCTION 210 static FUNCTION
211 interface_render_titlebar() -> void 211 interface_render_titlebar() -> void
212 { 212 {
213 if (g_title.length() <= COLS) 213 if (Title.length() <= COLS)
214 { 214 {
215 int pair = interface_color_pair (WHITE, BLUE); 215 int pair = interface_color_pair (WHITE, BLUE);
216 int startx = (COLS - g_title.length()) / 2; 216 int startx = (COLS - Title.length()) / 2;
217 int endx = startx + g_title.length(); 217 int endx = startx + Title.length();
218 attron (pair); 218 attron (pair);
219 mvprintw (0, startx, "%s", g_title.chars()); 219 mvprintw (0, startx, "%s", Title.chars());
220 mvhline (0, 0, ' ', startx); 220 mvhline (0, 0, ' ', startx);
221 mvhline (0, endx, ' ', COLS - endx); 221 mvhline (0, endx, ' ', COLS - endx);
222 attroff (pair); 222 attroff (pair);
223 } 223 }
224 224
225 g_needRefresh = true; 225 NeedRefresh = true;
226 } 226 }
227 227
228 // ------------------------------------------------------------------------------------------------- 228 // -------------------------------------------------------------------------------------------------
229 // 229 //
230 FUNCTION 230 FUNCTION
231 Interface::set_title (const String& title) -> void 231 Interface::set_title (const String& title) -> void
232 { 232 {
233 g_title = title; 233 Title = title;
234 interface_render_titlebar(); 234 interface_render_titlebar();
235 } 235 }
236 236
237 // ------------------------------------------------------------------------------------------------- 237 // -------------------------------------------------------------------------------------------------
238 // 238 //
239 static FUNCTION 239 static FUNCTION
240 safe_disconnect (Function<void()> afterwards) -> void 240 safe_disconnect (Function<void()> afterwards) -> void
241 { 241 {
242 if (RCONSession::get_session()->is_active()) 242 if (RCONSession::get_session()->is_active())
243 { 243 {
244 g_disconnectConfirmFunction = afterwards; 244 DisconnectConfirmFunction = afterwards;
245 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); 245 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION);
246 } 246 }
247 else 247 else
248 afterwards(); 248 afterwards();
249 } 249 }
329 // ------------------------------------------------------------------------------------------------- 329 // -------------------------------------------------------------------------------------------------
330 // 330 //
331 static FUNCTION 331 static FUNCTION
332 interface_render_output() -> void 332 interface_render_output() -> void
333 { 333 {
334 if (g_output.size() == 1) 334 if (OutputLines.size() == 1)
335 return; 335 return;
336 336
337 g_outputScroll = clamp (g_outputScroll, 0, g_output.size() - 1); 337 OutputScroll = clamp (OutputScroll, 0, OutputLines.size() - 1);
338 338
339 int height = LINES - 3; 339 int height = LINES - 3;
340 int width = COLS - interface_nicklist_width(); 340 int width = COLS - interface_nicklist_width();
341 int printOffset = 0; 341 int printOffset = 0;
342 int end = g_output.size() - 1 - g_outputScroll; 342 int end = OutputLines.size() - 1 - OutputScroll;
343 int start = end; 343 int start = end;
344 int usedHeight = 0; 344 int usedHeight = 0;
345 int y = 1; 345 int y = 1;
346 bool tightFit = false; 346 bool tightFit = false;
347 347
348 // Where to start? 348 // Where to start?
349 while (start > 0) 349 while (start > 0)
350 { 350 {
351 int rows = g_output[start - 1].rows (width); 351 int rows = OutputLines[start - 1].rows (width);
352 352
353 if (usedHeight + rows > height) 353 if (usedHeight + rows > height)
354 { 354 {
355 // This line won't fit anymore. 355 // This line won't fit anymore.
356 tightFit = true; 356 tightFit = true;
362 } 362 }
363 363
364 // See if there's any more rows to use (end may be too small) 364 // See if there's any more rows to use (end may be too small)
365 if (not tightFit) 365 if (not tightFit)
366 { 366 {
367 while (end < g_output.size()) 367 while (end < OutputLines.size())
368 { 368 {
369 int rows = g_output[end].rows (width); 369 int rows = OutputLines[end].rows (width);
370 370
371 if (usedHeight + rows > height) 371 if (usedHeight + rows > height)
372 { 372 {
373 tightFit = true; 373 tightFit = true;
374 break; 374 break;
380 } 380 }
381 381
382 if (start > 0) 382 if (start > 0)
383 printOffset = height - usedHeight; 383 printOffset = height - usedHeight;
384 384
385 g_outputScroll = g_output.size() - 1 - end; 385 OutputScroll = OutputLines.size() - 1 - end;
386 386
387 if (start < 0 or start == end or printOffset >= height) 387 if (start < 0 or start == end or printOffset >= height)
388 return; 388 return;
389 389
390 assert (start <= end and start - end <= height); 390 assert (start <= end and start - end <= height);
395 395
396 // Print the lines 396 // Print the lines
397 y += printOffset; 397 y += printOffset;
398 398
399 for (int i = start; i < end; ++i) 399 for (int i = start; i < end; ++i)
400 y = interface_render_colorline (y, 0, width, g_output[i], true); 400 y = interface_render_colorline (y, 0, width, OutputLines[i], true);
401 401
402 g_needOutputRender = false; 402 NeedOutputRender = false;
403 g_needRefresh = true; 403 NeedRefresh = true;
404 } 404 }
405 405
406 // ------------------------------------------------------------------------------------------------- 406 // -------------------------------------------------------------------------------------------------
407 // 407 //
408 static FUNCTION 408 static FUNCTION
418 418
419 for (int i = 0; i < height; ++i) 419 for (int i = 0; i < height; ++i)
420 { 420 {
421 mvhline (y, x, ' ', width); 421 mvhline (y, x, ' ', width);
422 422
423 if (i < g_playerNames.size()) 423 if (i < PlayerNames.size())
424 { 424 {
425 String displaynick = g_playerNames[i]; 425 String displaynick = PlayerNames[i];
426 426
427 if (displaynick.length() > width) 427 if (displaynick.length() > width)
428 { 428 {
429 displaynick = displaynick.mid (0, width - 3); 429 displaynick = displaynick.mid (0, width - 3);
430 displaynick += "..."; 430 displaynick += "...";
434 } 434 }
435 435
436 y++; 436 y++;
437 } 437 }
438 438
439 g_needNicklistRender = false; 439 NeedNicklistRender = false;
440 g_needRefresh = true; 440 NeedRefresh = true;
441 } 441 }
442 442
443 // ------------------------------------------------------------------------------------------------- 443 // -------------------------------------------------------------------------------------------------
444 // 444 //
445 static FUNCTION 445 static FUNCTION
447 { 447 {
448 int promptColor = interface_color_pair (WHITE, BLUE); 448 int promptColor = interface_color_pair (WHITE, BLUE);
449 449
450 // If we're asking the user if they want to disconnect, we don't render any input strings, 450 // If we're asking the user if they want to disconnect, we don't render any input strings,
451 // just the confirmation message. 451 // just the confirmation message.
452 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 452 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION)
453 { 453 {
454 attron (promptColor); 454 attron (promptColor);
455 mvhline (LINES - 2, 0, ' ', COLS); 455 mvhline (LINES - 2, 0, ' ', COLS);
456 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n"); 456 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n");
457 attroff (promptColor); 457 attroff (promptColor);
458 g_needRefresh = true; 458 NeedRefresh = true;
459 return; 459 return;
460 } 460 }
461 461
462 String prompt = interface_prompt_string(); 462 String prompt = interface_prompt_string();
463 int displayLength = COLS - prompt.length() - 2; 463 int displayLength = COLS - prompt.length() - 2;
464 String displayString = current_input(); 464 String displayString = current_input();
465 int y = LINES - 2; 465 int y = LINES - 2;
466 466
467 // If we're inputting a password, replace it with asterisks 467 // If we're inputting a password, replace it with asterisks
468 if (g_inputState == INPUTSTATE_PASSWORD) 468 if (CurrentInputState == INPUTSTATE_PASSWORD)
469 { 469 {
470 for (char& ch : displayString) 470 for (char& ch : displayString)
471 ch = '*'; 471 ch = '*';
472 } 472 }
473 473
474 // Ensure the cursor is within bounds 474 // Ensure the cursor is within bounds
475 g_cursor = clamp (g_cursor, 0, displayString.length()); 475 CursorPosition = clamp (CursorPosition, 0, displayString.length());
476 476
477 // Ensure that the cursor is always in view, adjust panning if this is not the case 477 // Ensure that the cursor is always in view, adjust panning if this is not the case
478 if (g_cursor > g_pan + displayLength) 478 if (CursorPosition > InputPanning + displayLength)
479 g_pan = g_cursor - displayLength; // cursor went too far right 479 InputPanning = CursorPosition - displayLength; // cursor went too far right
480 else if (g_cursor < g_pan) 480 else if (CursorPosition < InputPanning)
481 g_pan = g_cursor; // cursor went past the pan value to the left 481 InputPanning = CursorPosition; // cursor went past the pan value to the left
482 482
483 // What part of the string to draw? 483 // What part of the string to draw?
484 int start = g_pan; 484 int start = InputPanning;
485 int end = min<int> (displayString.length(), start + displayLength); 485 int end = min<int> (displayString.length(), start + displayLength);
486 assert (g_cursor >= start and g_cursor <= end); 486 assert (CursorPosition >= start and CursorPosition <= end);
487 487
488 // Render the input string 488 // Render the input string
489 mvhline (LINES - 2, 0, ' ', COLS); 489 mvhline (LINES - 2, 0, ' ', COLS);
490 mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars()); 490 mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars());
491 491
494 mvprintw (y, 0, "%s", prompt.chars()); 494 mvprintw (y, 0, "%s", prompt.chars());
495 attroff (promptColor); 495 attroff (promptColor);
496 496
497 // Store in memory where the cursor is now (so that we can re-draw it to position the terminal 497 // Store in memory where the cursor is now (so that we can re-draw it to position the terminal
498 // cursor). 498 // cursor).
499 g_cursorChar.ch = g_cursor != 0 ? displayString[g_cursor - 1] : '\0'; 499 CursorCharacter.ch = CursorPosition != 0 ? displayString[CursorPosition - 1] : '\0';
500 g_cursorChar.x = prompt.length() + (g_cursor - g_pan); 500 CursorCharacter.x = prompt.length() + (CursorPosition - InputPanning);
501 g_needRefresh = true; 501 NeedRefresh = true;
502 g_needInputRender = false; 502 NeedInputRender = false;
503 } 503 }
504 504
505 // ------------------------------------------------------------------------------------------------- 505 // -------------------------------------------------------------------------------------------------
506 // 506 //
507 static FUNCTION 507 static FUNCTION
509 { 509 {
510 int color = interface_color_pair (WHITE, BLUE); 510 int color = interface_color_pair (WHITE, BLUE);
511 int y = LINES - 1; 511 int y = LINES - 1;
512 attron (color); 512 attron (color);
513 mvhline (y, 0, ' ', COLS); 513 mvhline (y, 0, ' ', COLS);
514 mvprintw (y, 0, "%s", g_statusBarText.chars()); 514 mvprintw (y, 0, "%s", StatusBarText.chars());
515 attroff (color); 515 attroff (color);
516 g_needRefresh = true; 516 NeedRefresh = true;
517 g_needStatusBarRender = false; 517 NeedStatusBarRender = false;
518 } 518 }
519 519
520 // ------------------------------------------------------------------------------------------------- 520 // -------------------------------------------------------------------------------------------------
521 // 521 //
522 FUNCTION 522 FUNCTION
549 if (not text.is_empty()) 549 if (not text.is_empty())
550 text += " | "; 550 text += " | ";
551 551
552 text += "^N to connect, ^Q to quit"; 552 text += "^N to connect, ^Q to quit";
553 553
554 if (text != g_statusBarText) 554 if (text != StatusBarText)
555 { 555 {
556 g_statusBarText = text; 556 StatusBarText = text;
557 g_needStatusBarRender = true; 557 NeedStatusBarRender = true;
558 } 558 }
559 } 559 }
560 560
561 // ------------------------------------------------------------------------------------------------- 561 // -------------------------------------------------------------------------------------------------
562 // 562 //
575 // 575 //
576 static FUNCTION 576 static FUNCTION
577 interface_position_cursor() -> void 577 interface_position_cursor() -> void
578 { 578 {
579 // This is only relevant if the input string is being drawn 579 // This is only relevant if the input string is being drawn
580 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 580 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION)
581 return; 581 return;
582 582
583 int y = LINES - 2; 583 int y = LINES - 2;
584 584
585 if (g_cursorChar.ch != '\0') 585 if (CursorCharacter.ch != '\0')
586 mvprintw (y, g_cursorChar.x, "%c", g_cursorChar.ch); 586 mvprintw (y, CursorCharacter.x, "%c", CursorCharacter.ch);
587 else 587 else
588 mvprintw (y, interface_prompt_string().length(), " "); 588 mvprintw (y, interface_prompt_string().length(), " ");
589 } 589 }
590 590
591 // ------------------------------------------------------------------------------------------------- 591 // -------------------------------------------------------------------------------------------------
592 // 592 //
593 static FUNCTION 593 static FUNCTION
594 interface_find_previous_word() -> int 594 interface_find_previous_word() -> int
595 { 595 {
596 const String& input = current_input(); 596 const String& input = current_input();
597 int pos = g_cursor; 597 int pos = CursorPosition;
598 598
599 // Move past whitespace 599 // Move past whitespace
600 while (pos > 0 and isspace (input[pos - 1])) 600 while (pos > 0 and isspace (input[pos - 1]))
601 pos--; 601 pos--;
602 602
611 // 611 //
612 static FUNCTION 612 static FUNCTION
613 interface_find_next_word() -> int 613 interface_find_next_word() -> int
614 { 614 {
615 const String& input = current_input(); 615 const String& input = current_input();
616 int pos = g_cursor; 616 int pos = CursorPosition;
617 617
618 // Move past current whitespace 618 // Move past current whitespace
619 while (pos < input.length() and isspace (input[pos])) 619 while (pos < input.length() and isspace (input[pos]))
620 pos++; 620 pos++;
621 621
632 yank (int a, int b) -> void 632 yank (int a, int b) -> void
633 { 633 {
634 if (a >= b) 634 if (a >= b)
635 return; 635 return;
636 636
637 if (g_cursor > a and g_cursor <= b) 637 if (CursorPosition > a and CursorPosition <= b)
638 g_cursor = a; 638 CursorPosition = a;
639 639
640 String& input = mutable_current_input(); 640 String& input = mutable_current_input();
641 g_pasteBuffer = input.mid (a, b); 641 PasteBuffer = input.mid (a, b);
642 input.remove (a, b - a); 642 input.remove (a, b - a);
643 g_needInputRender = true; 643 NeedInputRender = true;
644 } 644 }
645 645
646 // ------------------------------------------------------------------------------------------------- 646 // -------------------------------------------------------------------------------------------------
647 // 647 //
648 FUNCTION 648 FUNCTION
655 ::clear(); 655 ::clear();
656 render_full(); 656 render_full();
657 return; 657 return;
658 } 658 }
659 659
660 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 660 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION)
661 { 661 {
662 if (ch == 'y' or ch == 'Y') 662 if (ch == 'y' or ch == 'Y')
663 { 663 {
664 RCONSession::get_session()->disconnect(); 664 RCONSession::get_session()->disconnect();
665 g_disconnectConfirmFunction(); 665 DisconnectConfirmFunction();
666 } 666 }
667 else if (ch == 'n' or ch == 'N') 667 else if (ch == 'n' or ch == 'N')
668 set_input_state (INPUTSTATE_NORMAL); 668 set_input_state (INPUTSTATE_NORMAL);
669 669
670 return; 670 return;
671 } 671 }
672 672
673 if (ch >= 0x20 and ch <= 0x7E) 673 if (ch >= 0x20 and ch <= 0x7E)
674 { 674 {
675 mutable_current_input().insert (g_cursor++, char (ch)); 675 mutable_current_input().insert (CursorPosition++, char (ch));
676 g_needInputRender = true; 676 NeedInputRender = true;
677 } 677 }
678 else switch (ch) 678 else switch (ch)
679 { 679 {
680 case 'Q' - 'A' + 1: // ^Q 680 case 'Q' - 'A' + 1: // ^Q
681 switch (g_inputState) 681 switch (CurrentInputState)
682 { 682 {
683 case INPUTSTATE_CONFIRM_DISCONNECTION: 683 case INPUTSTATE_CONFIRM_DISCONNECTION:
684 break; 684 break;
685 685
686 case INPUTSTATE_NORMAL: 686 case INPUTSTATE_NORMAL:
710 } 710 }
711 break; 711 break;
712 712
713 case KEY_LEFT: 713 case KEY_LEFT:
714 case 'B' - 'A' + 1: // readline ^B 714 case 'B' - 'A' + 1: // readline ^B
715 if (g_cursor > 0) 715 if (CursorPosition > 0)
716 { 716 {
717 g_cursor--; 717 CursorPosition--;
718 g_needInputRender = true; 718 NeedInputRender = true;
719 } 719 }
720 break; 720 break;
721 721
722 case KEY_RIGHT: 722 case KEY_RIGHT:
723 case 'F' - 'A' + 1: // readline ^F 723 case 'F' - 'A' + 1: // readline ^F
724 if (g_cursor < current_input().length()) 724 if (CursorPosition < current_input().length())
725 { 725 {
726 g_cursor++; 726 CursorPosition++;
727 g_needInputRender = true; 727 NeedInputRender = true;
728 } 728 }
729 break; 729 break;
730 730
731 case KEY_DOWN: 731 case KEY_DOWN:
732 case KEY_UP: 732 case KEY_UP:
733 move_input_cursor (ch == KEY_DOWN ? -1 : 1); 733 move_input_cursor (ch == KEY_DOWN ? -1 : 1);
734 break; 734 break;
735 735
736 case KEY_HOME: 736 case KEY_HOME:
737 case 'A' - 'A' + 1: // readline ^A 737 case 'A' - 'A' + 1: // readline ^A
738 if (g_cursor != 0) 738 if (CursorPosition != 0)
739 { 739 {
740 g_cursor = 0; 740 CursorPosition = 0;
741 g_needInputRender = true; 741 NeedInputRender = true;
742 } 742 }
743 break; 743 break;
744 744
745 case KEY_END: 745 case KEY_END:
746 case 'E' - 'A' + 1: // readline ^E 746 case 'E' - 'A' + 1: // readline ^E
747 if (g_cursor != current_input().length()) 747 if (CursorPosition != current_input().length())
748 { 748 {
749 g_cursor = current_input().length(); 749 CursorPosition = current_input().length();
750 g_needInputRender = true; 750 NeedInputRender = true;
751 } 751 }
752 break; 752 break;
753 753
754 case KEY_BACKSPACE: 754 case KEY_BACKSPACE:
755 if (g_cursor > 0) 755 if (CursorPosition > 0)
756 { 756 {
757 mutable_current_input().remove_at (--g_cursor); 757 mutable_current_input().remove_at (--CursorPosition);
758 g_needInputRender = true; 758 NeedInputRender = true;
759 } 759 }
760 break; 760 break;
761 761
762 case KEY_DC: 762 case KEY_DC:
763 case 'D' - 'A' + 1: // readline ^D 763 case 'D' - 'A' + 1: // readline ^D
764 if (g_cursor < current_input().length()) 764 if (CursorPosition < current_input().length())
765 { 765 {
766 mutable_current_input().remove_at (g_cursor); 766 mutable_current_input().remove_at (CursorPosition);
767 g_needInputRender = true; 767 NeedInputRender = true;
768 } 768 }
769 break; 769 break;
770 770
771 case KEY_PPAGE: 771 case KEY_PPAGE:
772 g_outputScroll += min (g_pageSize, LINES / 2); 772 OutputScroll += min (g_pageSize, LINES / 2);
773 g_needOutputRender = true; 773 NeedOutputRender = true;
774 break; 774 break;
775 775
776 case KEY_NPAGE: 776 case KEY_NPAGE:
777 g_outputScroll -= min (g_pageSize, LINES / 2); 777 OutputScroll -= min (g_pageSize, LINES / 2);
778 g_needOutputRender = true; 778 NeedOutputRender = true;
779 break; 779 break;
780 780
781 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor 781 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor
782 if (g_cursor > 0) 782 if (CursorPosition > 0)
783 { 783 {
784 yank (0, g_cursor); 784 yank (0, CursorPosition);
785 g_cursor = 0; 785 CursorPosition = 0;
786 } 786 }
787 break; 787 break;
788 788
789 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end 789 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end
790 yank (g_cursor, mutable_current_input().length()); 790 yank (CursorPosition, mutable_current_input().length());
791 break; 791 break;
792 792
793 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current 793 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current
794 yank (interface_find_previous_word(), g_cursor); 794 yank (interface_find_previous_word(), CursorPosition);
795 break; 795 break;
796 796
797 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text 797 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text
798 if (not g_pasteBuffer.is_empty()) 798 if (not PasteBuffer.is_empty())
799 { 799 {
800 mutable_current_input().insert (g_cursor, g_pasteBuffer); 800 mutable_current_input().insert (CursorPosition, PasteBuffer);
801 g_cursor += g_pasteBuffer.length(); 801 CursorPosition += PasteBuffer.length();
802 g_needInputRender = true; 802 NeedInputRender = true;
803 } 803 }
804 break; 804 break;
805 805
806 case '\n': 806 case '\n':
807 case KEY_ENTER: 807 case KEY_ENTER:
808 switch (g_inputState) 808 switch (CurrentInputState)
809 { 809 {
810 case INPUTSTATE_CONFIRM_DISCONNECTION: 810 case INPUTSTATE_CONFIRM_DISCONNECTION:
811 break; // handled above 811 break; // handled above
812 812
813 case INPUTSTATE_ADDRESS: 813 case INPUTSTATE_ADDRESS:
814 try 814 try
815 { 815 {
816 g_address = IPAddress::from_string (current_input()); 816 CurrentAddress = IPAddress::from_string (current_input());
817 } 817 }
818 catch (std::exception& e) 818 catch (std::exception& e)
819 { 819 {
820 print ("%1\n", e.what()); 820 print ("%1\n", e.what());
821 return; 821 return;
822 } 822 }
823 823
824 if (g_address.port == 0) 824 if (CurrentAddress.port == 0)
825 g_address.port = 10666; 825 CurrentAddress.port = 10666;
826 826
827 set_input_state (INPUTSTATE_PASSWORD); 827 set_input_state (INPUTSTATE_PASSWORD);
828 break; 828 break;
829 829
830 case INPUTSTATE_PASSWORD: 830 case INPUTSTATE_PASSWORD:
831 if (g_inputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) 831 if (CurrentInputState == INPUTSTATE_PASSWORD and not current_input().is_empty())
832 { 832 {
833 RCONSession* session = RCONSession::get_session(); 833 RCONSession* session = RCONSession::get_session();
834 session->disconnect(); 834 session->disconnect();
835 session->set_password (current_input()); 835 session->set_password (current_input());
836 session->connect (g_address); 836 session->connect (CurrentAddress);
837 set_input_state (INPUTSTATE_NORMAL); 837 set_input_state (INPUTSTATE_NORMAL);
838 } 838 }
839 break; 839 break;
840 840
841 case INPUTSTATE_NORMAL: 841 case INPUTSTATE_NORMAL:
842 if (RCONSession::get_session()->send_command (current_input())) 842 if (RCONSession::get_session()->send_command (current_input()))
843 { 843 {
844 g_input.insert (0, ""); 844 InputHistory.insert (0, "");
845 g_needInputRender = true; 845 NeedInputRender = true;
846 } 846 }
847 break; 847 break;
848 } 848 }
849 break; 849 break;
850 850
851 case 'N' - 'A' + 1: // ^N 851 case 'N' - 'A' + 1: // ^N
852 if (g_inputState == INPUTSTATE_NORMAL) 852 if (CurrentInputState == INPUTSTATE_NORMAL)
853 safe_disconnect ([]() {set_input_state (INPUTSTATE_ADDRESS);}); 853 safe_disconnect ([]() {set_input_state (INPUTSTATE_ADDRESS);});
854 break; 854 break;
855 855
856 case '\e': // Escape 856 case '\e': // Escape
857 // We may have an alt key coming 857 // We may have an alt key coming
862 switch (ch) 862 switch (ch)
863 { 863 {
864 case 'b': 864 case 'b':
865 case 'B': 865 case 'B':
866 // readline alt-b - move one word to the left 866 // readline alt-b - move one word to the left
867 g_cursor = interface_find_previous_word(); 867 CursorPosition = interface_find_previous_word();
868 g_needInputRender = true; 868 NeedInputRender = true;
869 break; 869 break;
870 870
871 case 'f': 871 case 'f':
872 case 'F': 872 case 'F':
873 // readline alt-f - move one word to the right 873 // readline alt-f - move one word to the right
874 g_cursor = interface_find_next_word(); 874 CursorPosition = interface_find_next_word();
875 g_needInputRender = true; 875 NeedInputRender = true;
876 break; 876 break;
877 877
878 case 'd': 878 case 'd':
879 case 'D': 879 case 'D':
880 // readline alt-d - delete from here till next word boundary 880 // readline alt-d - delete from here till next word boundary
881 yank (g_cursor, interface_find_next_word()); 881 yank (CursorPosition, interface_find_next_word());
882 break; 882 break;
883 } 883 }
884 } 884 }
885 else 885 else
886 { 886 {
887 // No alt-key, handle pure escape 887 // No alt-key, handle pure escape
888 if (g_inputState == INPUTSTATE_PASSWORD) 888 if (CurrentInputState == INPUTSTATE_PASSWORD)
889 set_input_state (INPUTSTATE_ADDRESS); 889 set_input_state (INPUTSTATE_ADDRESS);
890 else if (g_inputState == INPUTSTATE_ADDRESS) 890 else if (CurrentInputState == INPUTSTATE_ADDRESS)
891 set_input_state (INPUTSTATE_NORMAL); 891 set_input_state (INPUTSTATE_NORMAL);
892 } 892 }
893 break; 893 break;
894 } 894 }
895 } 895 }
897 // ------------------------------------------------------------------------------------------------- 897 // -------------------------------------------------------------------------------------------------
898 // 898 //
899 FUNCTION 899 FUNCTION
900 Interface::render() -> void 900 Interface::render() -> void
901 { 901 {
902 if (g_needStatusBarRender) interface_render_statusbar(); 902 if (NeedStatusBarRender) interface_render_statusbar();
903 if (g_needInputRender) interface_render_input(); 903 if (NeedInputRender) interface_render_input();
904 if (g_needOutputRender) interface_render_output(); 904 if (NeedOutputRender) interface_render_output();
905 if (g_needNicklistRender) interface_render_nicklist(); 905 if (NeedNicklistRender) interface_render_nicklist();
906 906
907 if (g_needRefresh) 907 if (NeedRefresh)
908 { 908 {
909 interface_position_cursor(); 909 interface_position_cursor();
910 refresh(); 910 refresh();
911 g_needRefresh = false; 911 NeedRefresh = false;
912 } 912 }
913 } 913 }
914 914
915 // ------------------------------------------------------------------------------------------------- 915 // -------------------------------------------------------------------------------------------------
916 // 916 //
922 922
923 for (char ch : a) 923 for (char ch : a)
924 { 924 {
925 if (ch == '\n') 925 if (ch == '\n')
926 { 926 {
927 g_output.last().finalize(); 927 OutputLines.last().finalize();
928 g_output << ColoredLine(); 928 OutputLines << ColoredLine();
929 continue; 929 continue;
930 } 930 }
931 931
932 if (g_output.last().length() == 0) 932 if (OutputLines.last().length() == 0)
933 { 933 {
934 time_t now; 934 time_t now;
935 time (&now); 935 time (&now);
936 char timestamp[32]; 936 char timestamp[32];
937 strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now)); 937 strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now));
938 938
939 for (char* cp = timestamp; *cp != '\0'; ++cp) 939 for (char* cp = timestamp; *cp != '\0'; ++cp)
940 g_output.last().add_char (*cp); 940 OutputLines.last().add_char (*cp);
941 } 941 }
942 942
943 g_output.last().add_char (ch); 943 OutputLines.last().add_char (ch);
944 } 944 }
945 945
946 g_needOutputRender = true; 946 NeedOutputRender = true;
947 } 947 }
948 948
949 // ------------------------------------------------------------------------------------------------- 949 // -------------------------------------------------------------------------------------------------
950 // 950 //
951 FUNCTION 951 FUNCTION
952 Interface::connect (String address, String password) -> void 952 Interface::connect (String address, String password) -> void
953 { 953 {
954 try 954 try
955 { 955 {
956 g_address = IPAddress::from_string (address); 956 CurrentAddress = IPAddress::from_string (address);
957 } 957 }
958 catch (std::exception& e) 958 catch (std::exception& e)
959 { 959 {
960 print ("%1\n", e.what()); 960 print ("%1\n", e.what());
961 return; 961 return;
962 } 962 }
963 963
964 if (g_address.port == 0) 964 if (CurrentAddress.port == 0)
965 g_address.port = 10666; 965 CurrentAddress.port = 10666;
966 966
967 RCONSession* session = RCONSession::get_session(); 967 RCONSession* session = RCONSession::get_session();
968 session->disconnect(); 968 session->disconnect();
969 session->set_password (password); 969 session->set_password (password);
970 session->connect (g_address); 970 session->connect (CurrentAddress);
971 } 971 }
972 972
973 // ------------------------------------------------------------------------------------------------- 973 // -------------------------------------------------------------------------------------------------
974 // 974 //
975 FUNCTION 975 FUNCTION
976 Interface::set_player_names (const StringList& names) -> void 976 Interface::set_player_names (const StringList& names) -> void
977 { 977 {
978 g_playerNames = names; 978 PlayerNames = names;
979 g_needNicklistRender = true; 979 NeedNicklistRender = true;
980 } 980 }

mercurial