sources/interface.cpp

changeset 127
6610b8b29848
parent 126
6a0d6bddf2ab
child 128
e5d185b62b7f
equal deleted inserted replaced
126:6a0d6bddf2ab 127:6610b8b29848
51 51
52 // ------------------------------------------------------------------------------------------------- 52 // -------------------------------------------------------------------------------------------------
53 // 53 //
54 const String& Interface::current_input() 54 const String& Interface::current_input()
55 { 55 {
56 return InputHistory[InputCursor]; 56 return m_inputHistory[m_inputCursor];
57 } 57 }
58 58
59 // ------------------------------------------------------------------------------------------------- 59 // -------------------------------------------------------------------------------------------------
60 // 60 //
61 // Makes current_input() the lastmost input (so that we won't modify history) 61 // Makes current_input() the lastmost input (so that we won't modify history)
62 // 62 //
63 void Interface::detach_input() 63 void Interface::detach_input()
64 { 64 {
65 if (InputCursor > 0) 65 if (m_inputCursor > 0)
66 { 66 {
67 InputHistory[0] = current_input(); 67 m_inputHistory[0] = current_input();
68 InputCursor = 0; 68 m_inputCursor = 0;
69 } 69 }
70 } 70 }
71 71
72 // ------------------------------------------------------------------------------------------------- 72 // -------------------------------------------------------------------------------------------------
73 // A version of current_input() that allows changing the contents of it. 73 // A version of current_input() that allows changing the contents of it.
74 // 74 //
75 String& Interface::mutable_current_input() 75 String& Interface::mutable_current_input()
76 { 76 {
77 detach_input(); 77 detach_input();
78 return InputHistory[InputCursor]; 78 return m_inputHistory[m_inputCursor];
79 } 79 }
80 80
81 // ------------------------------------------------------------------------------------------------- 81 // -------------------------------------------------------------------------------------------------
82 // 82 //
83 void Interface::move_input_cursor (int delta) 83 void Interface::move_input_cursor (int delta)
84 { 84 {
85 // No input history when inputting addresses or passwords 85 // No input history when inputting addresses or passwords
86 if (CurrentInputState != INPUTSTATE_NORMAL) 86 if (m_inputState != INPUTSTATE_NORMAL)
87 { 87 {
88 InputCursor = 0; 88 m_inputCursor = 0;
89 return; 89 return;
90 } 90 }
91 91
92 int oldcursor = InputCursor; 92 int oldcursor = m_inputCursor;
93 InputCursor = clamp (InputCursor + delta, 0, InputHistory.size() - 1); 93 m_inputCursor = clamp (m_inputCursor + delta, 0, m_inputHistory.size() - 1);
94 94
95 if (InputCursor != oldcursor) 95 if (m_inputCursor != oldcursor)
96 { 96 {
97 CursorPosition = current_input().length(); 97 m_cursorPosition = current_input().length();
98 NeedInputRender = true; 98 m_needInputRender = true;
99 } 99 }
100 } 100 }
101 101
102 // ------------------------------------------------------------------------------------------------- 102 // -------------------------------------------------------------------------------------------------
103 // 103 //
104 String Interface::prompt_string() 104 String Interface::prompt_string()
105 { 105 {
106 String prompt; 106 String prompt;
107 107
108 switch (CurrentInputState) 108 switch (m_inputState)
109 { 109 {
110 case INPUTSTATE_NORMAL: prompt = ">"; break; 110 case INPUTSTATE_NORMAL: prompt = ">"; break;
111 case INPUTSTATE_ADDRESS: prompt = "address:"; break; 111 case INPUTSTATE_ADDRESS: prompt = "address:"; break;
112 case INPUTSTATE_PASSWORD: prompt = "password:"; break; 112 case INPUTSTATE_PASSWORD: prompt = "password:"; break;
113 case INPUTSTATE_CONFIRM_DISCONNECTION: break; 113 case INPUTSTATE_CONFIRM_DISCONNECTION: break;
120 // 120 //
121 void Interface::set_input_state (InputState newstate) 121 void Interface::set_input_state (InputState newstate)
122 { 122 {
123 // Clear the input row (unless going to or from confirm state) 123 // Clear the input row (unless going to or from confirm state)
124 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION 124 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION
125 and CurrentInputState != INPUTSTATE_CONFIRM_DISCONNECTION) 125 and m_inputState != INPUTSTATE_CONFIRM_DISCONNECTION)
126 { 126 {
127 InputCursor = 0; 127 m_inputCursor = 0;
128 mutable_current_input().clear(); 128 mutable_current_input().clear();
129 } 129 }
130 130
131 switch (newstate) 131 switch (newstate)
132 { 132 {
133 case INPUTSTATE_ADDRESS: 133 case INPUTSTATE_ADDRESS:
134 if (CurrentAddress.host != 0) 134 if (m_remoteAddress.host != 0)
135 mutable_current_input() = CurrentAddress.to_string (IPAddress::WITH_PORT); 135 mutable_current_input() = m_remoteAddress.to_string (IPAddress::WITH_PORT);
136 break; 136 break;
137 137
138 default: 138 default:
139 break; 139 break;
140 } 140 }
141 141
142 CurrentInputState = newstate; 142 m_inputState = newstate;
143 NeedInputRender = true; 143 m_needInputRender = true;
144 } 144 }
145 145
146 // ------------------------------------------------------------------------------------------------- 146 // -------------------------------------------------------------------------------------------------
147 // 147 //
148 Interface::Interface() : 148 Interface::Interface() :
149 InputCursor (0), 149 m_inputCursor (0),
150 CursorPosition (0), 150 m_cursorPosition (0),
151 InputPanning (0), 151 m_inputPanning (0),
152 NeedRefresh (false), 152 m_needRefresh (false),
153 NeedStatusBarRender (false), 153 m_needStatusBarRender (false),
154 NeedInputRender (false), 154 m_needInputRender (false),
155 NeedOutputRender (false), 155 m_needOutputRender (false),
156 NeedNicklistRender (false), 156 m_needNicklistRender (false),
157 OutputScroll (0), 157 m_outputScroll (0),
158 CurrentInputState (INPUTSTATE_NORMAL), 158 m_inputState (INPUTSTATE_NORMAL),
159 DisconnectConfirmFunction (nullptr) 159 m_disconnectCallback (nullptr)
160 { 160 {
161 ::initscr(); 161 ::initscr();
162 ::raw(); 162 ::raw();
163 ::keypad (stdscr, true); 163 ::keypad (stdscr, true);
164 ::noecho(); 164 ::noecho();
165 ::refresh(); 165 ::refresh();
166 ::timeout (0); 166 ::timeout (0);
167 InputHistory.clear(); 167 m_inputHistory.clear();
168 InputHistory << ""; 168 m_inputHistory << "";
169 OutputLines.clear(); 169 m_outputLines.clear();
170 OutputLines << ColoredLine(); 170 m_outputLines << ColoredLine();
171 Session.set_interface (this); 171 m_session.set_interface (this);
172 reset_title(); 172 reset_title();
173 173
174 if (::has_colors()) 174 if (::has_colors())
175 { 175 {
176 ::start_color(); 176 ::start_color();
194 } 194 }
195 } 195 }
196 196
197 render_full(); 197 render_full();
198 refresh(); 198 refresh();
199 NeedRefresh = false; 199 m_needRefresh = false;
200 } 200 }
201 201
202 // ------------------------------------------------------------------------------------------------- 202 // -------------------------------------------------------------------------------------------------
203 // 203 //
204 void Interface::render_titlebar() 204 void Interface::render_titlebar()
205 { 205 {
206 if (Title.length() <= COLS) 206 if (m_title.length() <= COLS)
207 { 207 {
208 chtype pair = color_pair (WHITE, BLUE); 208 chtype pair = color_pair (WHITE, BLUE);
209 int startx = (COLS - Title.length()) / 2; 209 int startx = (COLS - m_title.length()) / 2;
210 int endx = startx + Title.length(); 210 int endx = startx + m_title.length();
211 attron (pair); 211 attron (pair);
212 mvprintw (0, startx, "%s", Title.chars()); 212 mvprintw (0, startx, "%s", m_title.chars());
213 mvhline (0, 0, ' ', startx); 213 mvhline (0, 0, ' ', startx);
214 mvhline (0, endx, ' ', COLS - endx); 214 mvhline (0, endx, ' ', COLS - endx);
215 attroff (pair); 215 attroff (pair);
216 } 216 }
217 217
218 NeedRefresh = true; 218 m_needRefresh = true;
219 } 219 }
220 220
221 // ------------------------------------------------------------------------------------------------- 221 // -------------------------------------------------------------------------------------------------
222 // 222 //
223 void Interface::set_title (const String& title) 223 void Interface::set_title (const String& title)
224 { 224 {
225 Title = title; 225 m_title = title;
226 render_titlebar(); 226 render_titlebar();
227 } 227 }
228 228
229 // ------------------------------------------------------------------------------------------------- 229 // -------------------------------------------------------------------------------------------------
230 // 230 //
231 void Interface::safe_disconnect (std::function<void(bool)> afterwards) 231 void Interface::safe_disconnect (std::function<void(bool)> afterwards)
232 { 232 {
233 if (Session.is_active()) 233 if (m_session.is_active())
234 { 234 {
235 DisconnectConfirmFunction = afterwards; 235 m_disconnectCallback = afterwards;
236 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); 236 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION);
237 } 237 }
238 else 238 else
239 afterwards(false); 239 afterwards(false);
240 } 240 }
301 301
302 // ------------------------------------------------------------------------------------------------- 302 // -------------------------------------------------------------------------------------------------
303 // 303 //
304 void Interface::render_output() 304 void Interface::render_output()
305 { 305 {
306 if (OutputLines.size() == 1) 306 if (m_outputLines.size() == 1)
307 return; 307 return;
308 308
309 OutputScroll = clamp (OutputScroll, 0, OutputLines.size() - 1); 309 m_outputScroll = clamp (m_outputScroll, 0, m_outputLines.size() - 1);
310 310
311 int height = LINES - 3; 311 int height = LINES - 3;
312 int width = COLS - nicklist_width(); 312 int width = COLS - nicklist_width();
313 int printOffset = 0; 313 int printOffset = 0;
314 int end = OutputLines.size() - 1 - OutputScroll; 314 int end = m_outputLines.size() - 1 - m_outputScroll;
315 int start = end; 315 int start = end;
316 int usedHeight = 0; 316 int usedHeight = 0;
317 int y = 1; 317 int y = 1;
318 bool tightFit = false; 318 bool tightFit = false;
319 319
320 // Where to start? 320 // Where to start?
321 while (start > 0) 321 while (start > 0)
322 { 322 {
323 int rows = OutputLines[start - 1].rows (width); 323 int rows = m_outputLines[start - 1].rows (width);
324 324
325 if (usedHeight + rows > height) 325 if (usedHeight + rows > height)
326 { 326 {
327 // This line won't fit anymore. 327 // This line won't fit anymore.
328 tightFit = true; 328 tightFit = true;
334 } 334 }
335 335
336 // See if there's any more rows to use (end may be too small) 336 // See if there's any more rows to use (end may be too small)
337 if (not tightFit) 337 if (not tightFit)
338 { 338 {
339 while (end < OutputLines.size()) 339 while (end < m_outputLines.size())
340 { 340 {
341 int rows = OutputLines[end].rows (width); 341 int rows = m_outputLines[end].rows (width);
342 342
343 if (usedHeight + rows > height) 343 if (usedHeight + rows > height)
344 { 344 {
345 tightFit = true; 345 tightFit = true;
346 break; 346 break;
352 } 352 }
353 353
354 if (start > 0) 354 if (start > 0)
355 printOffset = height - usedHeight; 355 printOffset = height - usedHeight;
356 356
357 OutputScroll = OutputLines.size() - 1 - end; 357 m_outputScroll = m_outputLines.size() - 1 - end;
358 358
359 if (start < 0 or start == end or printOffset >= height) 359 if (start < 0 or start == end or printOffset >= height)
360 return; 360 return;
361 361
362 assert (start <= end and start - end <= height); 362 assert (start <= end and start - end <= height);
367 367
368 // Print the lines 368 // Print the lines
369 y += printOffset; 369 y += printOffset;
370 370
371 for (int i = start; i < end; ++i) 371 for (int i = start; i < end; ++i)
372 y = render_colorline (y, 0, width, OutputLines[i], true); 372 y = render_colorline (y, 0, width, m_outputLines[i], true);
373 373
374 NeedOutputRender = false; 374 m_needOutputRender = false;
375 NeedRefresh = true; 375 m_needRefresh = true;
376 } 376 }
377 377
378 // ------------------------------------------------------------------------------------------------- 378 // -------------------------------------------------------------------------------------------------
379 // 379 //
380 void Interface::render_nicklist() 380 void Interface::render_nicklist()
389 389
390 for (int i = 0; i < height; ++i) 390 for (int i = 0; i < height; ++i)
391 { 391 {
392 mvhline (y, x, ' ', width); 392 mvhline (y, x, ' ', width);
393 393
394 if (i < PlayerNames.size()) 394 if (i < m_playerNames.size())
395 { 395 {
396 String displaynick = PlayerNames[i]; 396 String displaynick = m_playerNames[i];
397 397
398 if (displaynick.length() > width) 398 if (displaynick.length() > width)
399 { 399 {
400 displaynick = displaynick.mid (0, width - 3); 400 displaynick = displaynick.mid (0, width - 3);
401 displaynick += "..."; 401 displaynick += "...";
405 } 405 }
406 406
407 y++; 407 y++;
408 } 408 }
409 409
410 NeedNicklistRender = false; 410 m_needNicklistRender = false;
411 NeedRefresh = true; 411 m_needRefresh = true;
412 } 412 }
413 413
414 // ------------------------------------------------------------------------------------------------- 414 // -------------------------------------------------------------------------------------------------
415 // 415 //
416 void Interface::render_input() 416 void Interface::render_input()
417 { 417 {
418 chtype promptColor = color_pair (WHITE, BLUE); 418 chtype promptColor = color_pair (WHITE, BLUE);
419 419
420 // If we're asking the user if they want to disconnect, we don't render any input strings, 420 // If we're asking the user if they want to disconnect, we don't render any input strings,
421 // just the confirmation message. 421 // just the confirmation message.
422 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) 422 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
423 { 423 {
424 attron (promptColor); 424 attron (promptColor);
425 mvhline (LINES - 2, 0, ' ', COLS); 425 mvhline (LINES - 2, 0, ' ', COLS);
426 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n"); 426 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n");
427 attroff (promptColor); 427 attroff (promptColor);
428 NeedRefresh = true; 428 m_needRefresh = true;
429 return; 429 return;
430 } 430 }
431 431
432 String prompt = prompt_string(); 432 String prompt = prompt_string();
433 int displayLength = COLS - prompt.length() - 2; 433 int displayLength = COLS - prompt.length() - 2;
434 String displayString = current_input(); 434 String displayString = current_input();
435 int y = LINES - 2; 435 int y = LINES - 2;
436 436
437 // If we're inputting a password, replace it with asterisks 437 // If we're inputting a password, replace it with asterisks
438 if (CurrentInputState == INPUTSTATE_PASSWORD) 438 if (m_inputState == INPUTSTATE_PASSWORD)
439 { 439 {
440 for (int i = 0; i < displayString.length(); ++i) 440 for (int i = 0; i < displayString.length(); ++i)
441 displayString[i] = '*'; 441 displayString[i] = '*';
442 } 442 }
443 443
444 // Ensure the cursor is within bounds 444 // Ensure the cursor is within bounds
445 CursorPosition = clamp (CursorPosition, 0, displayString.length()); 445 m_cursorPosition = clamp (m_cursorPosition, 0, displayString.length());
446 446
447 // Ensure that the cursor is always in view, adjust panning if this is not the case 447 // Ensure that the cursor is always in view, adjust panning if this is not the case
448 if (CursorPosition > InputPanning + displayLength) 448 if (m_cursorPosition > m_inputPanning + displayLength)
449 InputPanning = CursorPosition - displayLength; // cursor went too far right 449 m_inputPanning = m_cursorPosition - displayLength; // cursor went too far right
450 else if (CursorPosition < InputPanning) 450 else if (m_cursorPosition < m_inputPanning)
451 InputPanning = CursorPosition; // cursor went past the pan value to the left 451 m_inputPanning = m_cursorPosition; // cursor went past the pan value to the left
452 452
453 // What part of the string to draw? 453 // What part of the string to draw?
454 int start = InputPanning; 454 int start = m_inputPanning;
455 int end = min<int> (displayString.length(), start + displayLength); 455 int end = min<int> (displayString.length(), start + displayLength);
456 assert (CursorPosition >= start and CursorPosition <= end); 456 assert (m_cursorPosition >= start and m_cursorPosition <= end);
457 457
458 // Render the input string 458 // Render the input string
459 mvhline (LINES - 2, 0, ' ', COLS); 459 mvhline (LINES - 2, 0, ' ', COLS);
460 mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars()); 460 mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars());
461 461
464 mvprintw (y, 0, "%s", prompt.chars()); 464 mvprintw (y, 0, "%s", prompt.chars());
465 attroff (promptColor); 465 attroff (promptColor);
466 466
467 // Store in memory where the cursor is now (so that we can re-draw it to position the terminal 467 // Store in memory where the cursor is now (so that we can re-draw it to position the terminal
468 // cursor). 468 // cursor).
469 CursorCharacter.ch = CursorPosition != 0 ? displayString[CursorPosition - 1] : '\0'; 469 m_cursorCharacter.ch = m_cursorPosition != 0 ? displayString[m_cursorPosition - 1] : '\0';
470 CursorCharacter.x = prompt.length() + (CursorPosition - InputPanning); 470 m_cursorCharacter.x = prompt.length() + (m_cursorPosition - m_inputPanning);
471 NeedRefresh = true; 471 m_needRefresh = true;
472 NeedInputRender = false; 472 m_needInputRender = false;
473 } 473 }
474 474
475 // ------------------------------------------------------------------------------------------------- 475 // -------------------------------------------------------------------------------------------------
476 // 476 //
477 void Interface::render_statusbar() 477 void Interface::render_statusbar()
478 { 478 {
479 chtype color = color_pair (WHITE, BLUE); 479 chtype color = color_pair (WHITE, BLUE);
480 int y = LINES - 1; 480 int y = LINES - 1;
481 attron (color); 481 attron (color);
482 mvhline (y, 0, ' ', COLS); 482 mvhline (y, 0, ' ', COLS);
483 mvprintw (y, 0, "%s", StatusBarText.chars()); 483 mvprintw (y, 0, "%s", m_statusBarText.chars());
484 attroff (color); 484 attroff (color);
485 NeedRefresh = true; 485 m_needRefresh = true;
486 NeedStatusBarRender = false; 486 m_needStatusBarRender = false;
487 } 487 }
488 488
489 // ------------------------------------------------------------------------------------------------- 489 // -------------------------------------------------------------------------------------------------
490 // 490 //
491 void Interface::update_statusbar() 491 void Interface::update_statusbar()
492 { 492 {
493 String text; 493 String text;
494 494
495 switch (Session.state()) 495 switch (m_session.state())
496 { 496 {
497 case RCON_DISCONNECTED: 497 case RCON_DISCONNECTED:
498 text = "Disconnected."; 498 text = "Disconnected.";
499 break; 499 break;
500 500
501 case RCON_CONNECTING: 501 case RCON_CONNECTING:
502 case RCON_AUTHENTICATING: 502 case RCON_AUTHENTICATING:
503 text = "Connecting to " + Session.address().to_string (IPAddress::WITH_PORT) + "..."; 503 text = "Connecting to " + m_session.address().to_string (IPAddress::WITH_PORT) + "...";
504 break; 504 break;
505 505
506 case RCON_CONNECTED: 506 case RCON_CONNECTED:
507 { 507 {
508 String adminText; 508 String adminText;
509 509
510 if (Session.num_admins() == 0) 510 if (m_session.num_admins() == 0)
511 { 511 {
512 adminText = "No other admins"; 512 adminText = "No other admins";
513 } 513 }
514 else 514 else
515 { 515 {
516 adminText.sprintf ("%d other admin%s", Session.num_admins(), 516 adminText.sprintf ("%d other admin%s", m_session.num_admins(),
517 Session.num_admins() != 1 ? "s" : ""); 517 m_session.num_admins() != 1 ? "s" : "");
518 } 518 }
519 519
520 text.sprintf ("%s | %s | %s", 520 text.sprintf ("%s | %s | %s",
521 Session.address().to_string (IPAddress::WITH_PORT).chars(), 521 m_session.address().to_string (IPAddress::WITH_PORT).chars(),
522 Session.level().chars(), 522 m_session.level().chars(),
523 adminText.chars()); 523 adminText.chars());
524 } 524 }
525 break; 525 break;
526 } 526 }
527 527
528 if (not text.is_empty()) 528 if (not text.is_empty())
529 text += " | "; 529 text += " | ";
530 530
531 text += "Ctrl+N to connect, Ctrl+Q to "; 531 text += "Ctrl+N to connect, Ctrl+Q to ";
532 text += (Session.state() == RCON_DISCONNECTED) ? "quit" : "disconnect"; 532 text += (m_session.state() == RCON_DISCONNECTED) ? "quit" : "disconnect";
533 533
534 if (text != StatusBarText) 534 if (text != m_statusBarText)
535 { 535 {
536 StatusBarText = text; 536 m_statusBarText = text;
537 NeedStatusBarRender = true; 537 m_needStatusBarRender = true;
538 } 538 }
539 } 539 }
540 540
541 // ------------------------------------------------------------------------------------------------- 541 // -------------------------------------------------------------------------------------------------
542 // 542 //
553 // ------------------------------------------------------------------------------------------------- 553 // -------------------------------------------------------------------------------------------------
554 // 554 //
555 void Interface::position_cursor() 555 void Interface::position_cursor()
556 { 556 {
557 // This is only relevant if the input string is being drawn 557 // This is only relevant if the input string is being drawn
558 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) 558 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
559 return; 559 return;
560 560
561 int y = LINES - 2; 561 int y = LINES - 2;
562 562
563 if (CursorCharacter.ch != '\0') 563 if (m_cursorCharacter.ch != '\0')
564 mvprintw (y, CursorCharacter.x, "%c", CursorCharacter.ch); 564 mvprintw (y, m_cursorCharacter.x, "%c", m_cursorCharacter.ch);
565 else 565 else
566 mvprintw (y, prompt_string().length(), " "); 566 mvprintw (y, prompt_string().length(), " ");
567 } 567 }
568 568
569 // ------------------------------------------------------------------------------------------------- 569 // -------------------------------------------------------------------------------------------------
570 // 570 //
571 int Interface::find_previous_word() 571 int Interface::find_previous_word()
572 { 572 {
573 const String& input = current_input(); 573 const String& input = current_input();
574 int pos = CursorPosition; 574 int pos = m_cursorPosition;
575 575
576 // Move past whitespace 576 // Move past whitespace
577 while (pos > 0 and isspace (input[pos - 1])) 577 while (pos > 0 and isspace (input[pos - 1]))
578 pos--; 578 pos--;
579 579
587 // ------------------------------------------------------------------------------------------------- 587 // -------------------------------------------------------------------------------------------------
588 // 588 //
589 int Interface::find_next_word() 589 int Interface::find_next_word()
590 { 590 {
591 const String& input = current_input(); 591 const String& input = current_input();
592 int pos = CursorPosition; 592 int pos = m_cursorPosition;
593 593
594 // Move past current whitespace 594 // Move past current whitespace
595 while (pos < input.length() and isspace (input[pos])) 595 while (pos < input.length() and isspace (input[pos]))
596 pos++; 596 pos++;
597 597
607 void Interface::yank (int a, int b) 607 void Interface::yank (int a, int b)
608 { 608 {
609 if (a >= b) 609 if (a >= b)
610 return; 610 return;
611 611
612 if (CursorPosition > a and CursorPosition <= b) 612 if (m_cursorPosition > a and m_cursorPosition <= b)
613 CursorPosition = a; 613 m_cursorPosition = a;
614 614
615 String& input = mutable_current_input(); 615 String& input = mutable_current_input();
616 PasteBuffer = input.mid (a, b); 616 m_pasteBuffer = input.mid (a, b);
617 input.remove (a, b - a); 617 input.remove (a, b - a);
618 NeedInputRender = true; 618 m_needInputRender = true;
619 } 619 }
620 620
621 // ------------------------------------------------------------------------------------------------- 621 // -------------------------------------------------------------------------------------------------
622 // 622 //
623 void Interface::handle_input() 623 void Interface::handle_input()
632 ::clear(); 632 ::clear();
633 render_full(); 633 render_full();
634 return; 634 return;
635 } 635 }
636 636
637 if (CurrentInputState == INPUTSTATE_CONFIRM_DISCONNECTION) 637 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
638 { 638 {
639 if (ch == 'y' or ch == 'Y') 639 if (ch == 'y' or ch == 'Y')
640 { 640 {
641 Session.disconnect(); 641 m_session.disconnect();
642 DisconnectConfirmFunction(true); 642 m_disconnectCallback(true);
643 } 643 }
644 else if (ch == 'n' or ch == 'N') 644 else if (ch == 'n' or ch == 'N')
645 set_input_state (INPUTSTATE_NORMAL); 645 set_input_state (INPUTSTATE_NORMAL);
646 646
647 return; 647 return;
648 } 648 }
649 649
650 if (ch >= 0x20 and ch <= 0x7E) 650 if (ch >= 0x20 and ch <= 0x7E)
651 { 651 {
652 mutable_current_input().insert (CursorPosition++, char (ch)); 652 mutable_current_input().insert (m_cursorPosition++, char (ch));
653 NeedInputRender = true; 653 m_needInputRender = true;
654 } 654 }
655 else switch (ch) 655 else switch (ch)
656 { 656 {
657 case 'Q' - 'A' + 1: // ^Q 657 case 'Q' - 'A' + 1: // ^Q
658 switch (CurrentInputState) 658 switch (m_inputState)
659 { 659 {
660 case INPUTSTATE_CONFIRM_DISCONNECTION: 660 case INPUTSTATE_CONFIRM_DISCONNECTION:
661 break; 661 break;
662 662
663 case INPUTSTATE_NORMAL: 663 case INPUTSTATE_NORMAL:
684 } 684 }
685 break; 685 break;
686 686
687 case KEY_LEFT: 687 case KEY_LEFT:
688 case 'B' - 'A' + 1: // readline ^B 688 case 'B' - 'A' + 1: // readline ^B
689 if (CursorPosition > 0) 689 if (m_cursorPosition > 0)
690 { 690 {
691 CursorPosition--; 691 m_cursorPosition--;
692 NeedInputRender = true; 692 m_needInputRender = true;
693 } 693 }
694 break; 694 break;
695 695
696 case KEY_RIGHT: 696 case KEY_RIGHT:
697 case 'F' - 'A' + 1: // readline ^F 697 case 'F' - 'A' + 1: // readline ^F
698 if (CursorPosition < current_input().length()) 698 if (m_cursorPosition < current_input().length())
699 { 699 {
700 CursorPosition++; 700 m_cursorPosition++;
701 NeedInputRender = true; 701 m_needInputRender = true;
702 } 702 }
703 break; 703 break;
704 704
705 case KEY_DOWN: 705 case KEY_DOWN:
706 case KEY_UP: 706 case KEY_UP:
707 move_input_cursor (ch == KEY_DOWN ? -1 : 1); 707 move_input_cursor (ch == KEY_DOWN ? -1 : 1);
708 break; 708 break;
709 709
710 case KEY_HOME: 710 case KEY_HOME:
711 case 'A' - 'A' + 1: // readline ^A 711 case 'A' - 'A' + 1: // readline ^A
712 if (CursorPosition != 0) 712 if (m_cursorPosition != 0)
713 { 713 {
714 CursorPosition = 0; 714 m_cursorPosition = 0;
715 NeedInputRender = true; 715 m_needInputRender = true;
716 } 716 }
717 break; 717 break;
718 718
719 case KEY_END: 719 case KEY_END:
720 case 'E' - 'A' + 1: // readline ^E 720 case 'E' - 'A' + 1: // readline ^E
721 if (CursorPosition != current_input().length()) 721 if (m_cursorPosition != current_input().length())
722 { 722 {
723 CursorPosition = current_input().length(); 723 m_cursorPosition = current_input().length();
724 NeedInputRender = true; 724 m_needInputRender = true;
725 } 725 }
726 break; 726 break;
727 727
728 case KEY_BACKSPACE: 728 case KEY_BACKSPACE:
729 case '\b': 729 case '\b':
730 if (CursorPosition > 0) 730 if (m_cursorPosition > 0)
731 { 731 {
732 mutable_current_input().remove_at (--CursorPosition); 732 mutable_current_input().remove_at (--m_cursorPosition);
733 NeedInputRender = true; 733 m_needInputRender = true;
734 } 734 }
735 break; 735 break;
736 736
737 case KEY_DC: 737 case KEY_DC:
738 case 'D' - 'A' + 1: // readline ^D 738 case 'D' - 'A' + 1: // readline ^D
739 if (CursorPosition < current_input().length()) 739 if (m_cursorPosition < current_input().length())
740 { 740 {
741 mutable_current_input().remove_at (CursorPosition); 741 mutable_current_input().remove_at (m_cursorPosition);
742 NeedInputRender = true; 742 m_needInputRender = true;
743 } 743 }
744 break; 744 break;
745 745
746 case KEY_PPAGE: 746 case KEY_PPAGE:
747 OutputScroll += min (g_pageSize, LINES / 2); 747 m_outputScroll += min (g_pageSize, LINES / 2);
748 NeedOutputRender = true; 748 m_needOutputRender = true;
749 break; 749 break;
750 750
751 case KEY_NPAGE: 751 case KEY_NPAGE:
752 OutputScroll -= min (g_pageSize, LINES / 2); 752 m_outputScroll -= min (g_pageSize, LINES / 2);
753 NeedOutputRender = true; 753 m_needOutputRender = true;
754 break; 754 break;
755 755
756 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor 756 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor
757 if (CursorPosition > 0) 757 if (m_cursorPosition > 0)
758 { 758 {
759 yank (0, CursorPosition); 759 yank (0, m_cursorPosition);
760 CursorPosition = 0; 760 m_cursorPosition = 0;
761 } 761 }
762 break; 762 break;
763 763
764 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end 764 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end
765 yank (CursorPosition, mutable_current_input().length()); 765 yank (m_cursorPosition, mutable_current_input().length());
766 break; 766 break;
767 767
768 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current 768 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current
769 yank (find_previous_word(), CursorPosition); 769 yank (find_previous_word(), m_cursorPosition);
770 break; 770 break;
771 771
772 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text 772 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text
773 if (not PasteBuffer.is_empty()) 773 if (not m_pasteBuffer.is_empty())
774 { 774 {
775 mutable_current_input().insert (CursorPosition, PasteBuffer); 775 mutable_current_input().insert (m_cursorPosition, m_pasteBuffer);
776 CursorPosition += PasteBuffer.length(); 776 m_cursorPosition += m_pasteBuffer.length();
777 NeedInputRender = true; 777 m_needInputRender = true;
778 } 778 }
779 break; 779 break;
780 780
781 case '\t': 781 case '\t':
782 { 782 {
783 int space = current_input().find (" "); 783 int space = current_input().find (" ");
784 784
785 if (CurrentInputState == INPUTSTATE_NORMAL 785 if (m_inputState == INPUTSTATE_NORMAL
786 and CursorPosition > 0 786 and m_cursorPosition > 0
787 and (space == -1 or space >= CursorPosition)) 787 and (space == -1 or space >= m_cursorPosition))
788 { 788 {
789 String start = current_input().mid (0, CursorPosition); 789 String start = current_input().mid (0, m_cursorPosition);
790 Session.request_tab_complete (start); 790 m_session.request_tab_complete (start);
791 } 791 }
792 } 792 }
793 break; 793 break;
794 794
795 case '\n': 795 case '\n':
796 case '\r': 796 case '\r':
797 case KEY_ENTER: 797 case KEY_ENTER:
798 switch (CurrentInputState) 798 switch (m_inputState)
799 { 799 {
800 case INPUTSTATE_CONFIRM_DISCONNECTION: 800 case INPUTSTATE_CONFIRM_DISCONNECTION:
801 break; // handled above 801 break; // handled above
802 802
803 case INPUTSTATE_ADDRESS: 803 case INPUTSTATE_ADDRESS:
804 try 804 try
805 { 805 {
806 CurrentAddress = IPAddress::from_string (current_input()); 806 m_remoteAddress = IPAddress::from_string (current_input());
807 } 807 }
808 catch (std::exception& e) 808 catch (std::exception& e)
809 { 809 {
810 print ("%s\n", e.what()); 810 print ("%s\n", e.what());
811 return; 811 return;
812 } 812 }
813 813
814 if (CurrentAddress.port == 0) 814 if (m_remoteAddress.port == 0)
815 CurrentAddress.port = 10666; 815 m_remoteAddress.port = 10666;
816 816
817 set_input_state (INPUTSTATE_PASSWORD); 817 set_input_state (INPUTSTATE_PASSWORD);
818 break; 818 break;
819 819
820 case INPUTSTATE_PASSWORD: 820 case INPUTSTATE_PASSWORD:
821 if (CurrentInputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) 821 if (m_inputState == INPUTSTATE_PASSWORD and not current_input().is_empty())
822 { 822 {
823 Session.disconnect(); 823 m_session.disconnect();
824 Session.set_password (current_input()); 824 m_session.set_password (current_input());
825 Session.connect (CurrentAddress); 825 m_session.connect (m_remoteAddress);
826 set_input_state (INPUTSTATE_NORMAL); 826 set_input_state (INPUTSTATE_NORMAL);
827 } 827 }
828 break; 828 break;
829 829
830 case INPUTSTATE_NORMAL: 830 case INPUTSTATE_NORMAL:
831 if (current_input()[0] == '/') 831 if (current_input()[0] == '/')
832 { 832 {
833 handle_command(current_input()); 833 handle_command(current_input());
834 flush_input(); 834 flush_input();
835 } 835 }
836 else if (Session.send_command (current_input())) 836 else if (m_session.send_command (current_input()))
837 { 837 {
838 flush_input(); 838 flush_input();
839 } 839 }
840 break; 840 break;
841 } 841 }
842 break; 842 break;
843 843
844 case 'N' - 'A' + 1: // ^N 844 case 'N' - 'A' + 1: // ^N
845 if (CurrentInputState == INPUTSTATE_NORMAL) 845 if (m_inputState == INPUTSTATE_NORMAL)
846 safe_disconnect ([&](bool){set_input_state (INPUTSTATE_ADDRESS);}); 846 safe_disconnect ([&](bool){set_input_state (INPUTSTATE_ADDRESS);});
847 break; 847 break;
848 848
849 case '\x1b': // Escape 849 case '\x1b': // Escape
850 // We may have an alt key coming 850 // We may have an alt key coming
855 switch (ch) 855 switch (ch)
856 { 856 {
857 case 'b': 857 case 'b':
858 case 'B': 858 case 'B':
859 // readline alt-b - move one word to the left 859 // readline alt-b - move one word to the left
860 CursorPosition = find_previous_word(); 860 m_cursorPosition = find_previous_word();
861 NeedInputRender = true; 861 m_needInputRender = true;
862 break; 862 break;
863 863
864 case 'f': 864 case 'f':
865 case 'F': 865 case 'F':
866 // readline alt-f - move one word to the right 866 // readline alt-f - move one word to the right
867 CursorPosition = find_next_word(); 867 m_cursorPosition = find_next_word();
868 NeedInputRender = true; 868 m_needInputRender = true;
869 break; 869 break;
870 870
871 case 'd': 871 case 'd':
872 case 'D': 872 case 'D':
873 // readline alt-d - delete from here till next word boundary 873 // readline alt-d - delete from here till next word boundary
874 yank (CursorPosition, find_next_word()); 874 yank (m_cursorPosition, find_next_word());
875 break; 875 break;
876 876
877 case KEY_BACKSPACE: // alt+backspace, remove previous word 877 case KEY_BACKSPACE: // alt+backspace, remove previous word
878 case '\b': 878 case '\b':
879 yank (find_previous_word(), CursorPosition); 879 yank (find_previous_word(), m_cursorPosition);
880 break; 880 break;
881 } 881 }
882 } 882 }
883 else 883 else
884 { 884 {
885 // No alt-key, handle pure escape 885 // No alt-key, handle pure escape
886 if (CurrentInputState == INPUTSTATE_PASSWORD) 886 if (m_inputState == INPUTSTATE_PASSWORD)
887 set_input_state (INPUTSTATE_ADDRESS); 887 set_input_state (INPUTSTATE_ADDRESS);
888 else if (CurrentInputState == INPUTSTATE_ADDRESS) 888 else if (m_inputState == INPUTSTATE_ADDRESS)
889 set_input_state (INPUTSTATE_NORMAL); 889 set_input_state (INPUTSTATE_NORMAL);
890 } 890 }
891 break; 891 break;
892 } 892 }
893 893
896 896
897 // ------------------------------------------------------------------------------------------------- 897 // -------------------------------------------------------------------------------------------------
898 // 898 //
899 void Interface::render() 899 void Interface::render()
900 { 900 {
901 if (NeedStatusBarRender) render_statusbar(); 901 if (m_needStatusBarRender) render_statusbar();
902 if (NeedInputRender) render_input(); 902 if (m_needInputRender) render_input();
903 if (NeedOutputRender) render_output(); 903 if (m_needOutputRender) render_output();
904 if (NeedNicklistRender) render_nicklist(); 904 if (m_needNicklistRender) render_nicklist();
905 905
906 if (NeedRefresh) 906 if (m_needRefresh)
907 { 907 {
908 position_cursor(); 908 position_cursor();
909 refresh(); 909 refresh();
910 NeedRefresh = false; 910 m_needRefresh = false;
911 } 911 }
912 } 912 }
913 913
914 // ------------------------------------------------------------------------------------------------- 914 // -------------------------------------------------------------------------------------------------
915 // 915 //
975 { 975 {
976 char ch = message[i]; 976 char ch = message[i];
977 977
978 if (ch == '\n') 978 if (ch == '\n')
979 { 979 {
980 OutputLines.last().finalize(); 980 m_outputLines.last().finalize();
981 OutputLines << ColoredLine(); 981 m_outputLines << ColoredLine();
982 continue; 982 continue;
983 } 983 }
984 984
985 if (OutputLines.last().length() == 0) 985 if (m_outputLines.last().length() == 0)
986 { 986 {
987 time_t now; 987 time_t now;
988 time (&now); 988 time (&now);
989 char timestamp[32]; 989 char timestamp[32];
990 strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now)); 990 strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now));
991 991
992 for (char* cp = timestamp; *cp != '\0'; ++cp) 992 for (char* cp = timestamp; *cp != '\0'; ++cp)
993 OutputLines.last().add_char (*cp); 993 m_outputLines.last().add_char (*cp);
994 } 994 }
995 995
996 // Remove some lines if there's too many of them. 20,000 should be enough, I hope. 996 // Remove some lines if there's too many of them. 20,000 should be enough, I hope.
997 while (OutputLines.size() > 20000) 997 while (m_outputLines.size() > 20000)
998 OutputLines.remove_at(0); 998 m_outputLines.remove_at(0);
999 999
1000 OutputLines.last().add_char (ch); 1000 m_outputLines.last().add_char (ch);
1001 } 1001 }
1002 1002
1003 NeedOutputRender = true; 1003 m_needOutputRender = true;
1004 } 1004 }
1005 1005
1006 // ------------------------------------------------------------------------------------------------- 1006 // -------------------------------------------------------------------------------------------------
1007 // 1007 //
1008 void Interface::connect (String address, String password) 1008 void Interface::connect (String address, String password)
1009 { 1009 {
1010 try 1010 try
1011 { 1011 {
1012 CurrentAddress = IPAddress::from_string (address); 1012 m_remoteAddress = IPAddress::from_string (address);
1013 } 1013 }
1014 catch (std::exception& e) 1014 catch (std::exception& e)
1015 { 1015 {
1016 print ("%s\n", e.what()); 1016 print ("%s\n", e.what());
1017 return; 1017 return;
1018 } 1018 }
1019 1019
1020 if (CurrentAddress.port == 0) 1020 if (m_remoteAddress.port == 0)
1021 CurrentAddress.port = 10666; 1021 m_remoteAddress.port = 10666;
1022 1022
1023 Session.disconnect(); 1023 m_session.disconnect();
1024 Session.set_password (password); 1024 m_session.set_password (password);
1025 Session.connect (CurrentAddress); 1025 m_session.connect (m_remoteAddress);
1026 } 1026 }
1027 1027
1028 // ------------------------------------------------------------------------------------------------- 1028 // -------------------------------------------------------------------------------------------------
1029 // 1029 //
1030 void Interface::set_player_names (const StringList& names) 1030 void Interface::set_player_names (const StringList& names)
1031 { 1031 {
1032 PlayerNames = names; 1032 m_playerNames = names;
1033 NeedNicklistRender = true; 1033 m_needNicklistRender = true;
1034 } 1034 }
1035 1035
1036 // ------------------------------------------------------------------------------------------------- 1036 // -------------------------------------------------------------------------------------------------
1037 // 1037 //
1038 void Interface::tab_complete (const String& part, String complete) 1038 void Interface::tab_complete (const String& part, String complete)
1043 { 1043 {
1044 if (input[part.length()] != ' ') 1044 if (input[part.length()] != ' ')
1045 complete += ' '; 1045 complete += ' ';
1046 1046
1047 input.replace (0, part.length(), complete); 1047 input.replace (0, part.length(), complete);
1048 CursorPosition = complete.length(); 1048 m_cursorPosition = complete.length();
1049 NeedInputRender = true; 1049 m_needInputRender = true;
1050 } 1050 }
1051 } 1051 }
1052 1052
1053 // ------------------------------------------------------------------------------------------------- 1053 // -------------------------------------------------------------------------------------------------
1054 // 1054 //
1082 } 1082 }
1083 1083
1084 if (address.port == 0) 1084 if (address.port == 0)
1085 address.port = 10666; 1085 address.port = 10666;
1086 1086
1087 Session.set_password(args[1]); 1087 m_session.set_password(args[1]);
1088 Session.disconnect(); 1088 m_session.disconnect();
1089 Session.connect(CurrentAddress = address); 1089 m_session.connect(m_remoteAddress = address);
1090 } 1090 }
1091 } 1091 }
1092 else if (command == "disconnect") 1092 else if (command == "disconnect")
1093 { 1093 {
1094 Session.disconnect(); 1094 m_session.disconnect();
1095 } 1095 }
1096 else if (command == "quit") 1096 else if (command == "quit")
1097 { 1097 {
1098 Session.disconnect(); 1098 m_session.disconnect();
1099 endwin(); 1099 endwin();
1100 throw Exitception(); 1100 throw Exitception();
1101 } 1101 }
1102 else 1102 else
1103 print_error("Unknown command: %s\n", command.chars()); 1103 print_error("Unknown command: %s\n", command.chars());
1105 1105
1106 // ------------------------------------------------------------------------------------------------- 1106 // -------------------------------------------------------------------------------------------------
1107 // 1107 //
1108 void Interface::disconnected() 1108 void Interface::disconnected()
1109 { 1109 {
1110 print("Disconnected from %s\n", Session.address().to_string(IPAddress::WITH_PORT).chars()); 1110 print("Disconnected from %s\n", m_session.address().to_string(IPAddress::WITH_PORT).chars());
1111 reset_title(); 1111 reset_title();
1112 render_full(); 1112 render_full();
1113 } 1113 }
1114 1114
1115 // ------------------------------------------------------------------------------------------------- 1115 // -------------------------------------------------------------------------------------------------
1116 // 1116 //
1117 void Interface::reset_title() 1117 void Interface::reset_title()
1118 { 1118 {
1119 Title.sprintf ("%s %s (%s)", application_name(), full_version_string(), changeset_date_string()); 1119 m_title.sprintf ("%s %s (%s)", application_name(), full_version_string(), changeset_date_string());
1120 } 1120 }
1121 1121
1122 // ------------------------------------------------------------------------------------------------- 1122 // -------------------------------------------------------------------------------------------------
1123 // 1123 //
1124 void Interface::flush_input() 1124 void Interface::flush_input()
1125 { 1125 {
1126 InputHistory.insert (0, ""); 1126 m_inputHistory.insert (0, "");
1127 InputCursor = 0; 1127 m_inputCursor = 0;
1128 NeedInputRender = true; 1128 m_needInputRender = true;
1129 } 1129 }
1130 1130
1131 END_ZFC_NAMESPACE 1131 END_ZFC_NAMESPACE

mercurial