sources/interface.cpp

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

mercurial