sources/interface.cpp

branch
protocol5
changeset 141
d9073c13dc98
parent 136
8fb1c657e0b0
parent 140
e49aa4aa98c0
child 150
37db42ad451a
equal deleted inserted replaced
136:8fb1c657e0b0 141:d9073c13dc98
39 39
40 static const int PAGE_SIZE = 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::getColorPair(Color fg, Color bg)
45 { 45 {
46 if (fg == DEFAULT && bg == DEFAULT) 46 if (fg == DEFAULT && bg == DEFAULT)
47 return 0; 47 return 0;
48 else 48 else
49 return COLOR_PAIR (1 + (int (fg) * NUM_COLORS) + int (bg)); 49 return COLOR_PAIR(1 + (int(fg) * NUM_COLORS) + int(bg));
50 } 50 }
51 51
52 // ------------------------------------------------------------------------------------------------- 52 // -------------------------------------------------------------------------------------------------
53 // 53 //
54 const String& Interface::current_input() 54 const String& Interface::getCurrentInput()
55 { 55 {
56 return m_inputHistory[m_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::detachInput()
64 { 64 {
65 if (m_inputCursor > 0) 65 if (m_inputCursor > 0)
66 { 66 {
67 m_inputHistory[0] = current_input(); 67 m_inputHistory[0] = getCurrentInput();
68 m_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::getEditableInput()
76 { 76 {
77 detach_input(); 77 detachInput();
78 return m_inputHistory[m_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::moveInputCursor(int delta)
84 { 84 {
85 // No input history when inputting addresses or passwords 85 // No input history when inputting addresses or passwords
86 if (m_inputState != INPUTSTATE_NORMAL) 86 if (m_inputState != INPUTSTATE_NORMAL)
87 { 87 {
88 m_inputCursor = 0; 88 m_inputCursor = 0;
89 return; 89 return;
90 } 90 }
91 91
92 int oldcursor = m_inputCursor; 92 int oldcursor = m_inputCursor;
93 m_inputCursor = clamp (m_inputCursor + delta, 0, m_inputHistory.size() - 1); 93 m_inputCursor = clamp(m_inputCursor + delta, 0, m_inputHistory.size() - 1);
94 94
95 if (m_inputCursor != oldcursor) 95 if (m_inputCursor != oldcursor)
96 { 96 {
97 m_cursorPosition = current_input().length(); 97 m_cursorPosition = getCurrentInput().length();
98 m_needInputRender = true; 98 m_needInputRender = true;
99 } 99 }
100 } 100 }
101 101
102 // ------------------------------------------------------------------------------------------------- 102 // -------------------------------------------------------------------------------------------------
103 // 103 //
104 String Interface::prompt_string() 104 String Interface::getPromptString()
105 { 105 {
106 String prompt; 106 String prompt;
107 107
108 switch (m_inputState) 108 switch (m_inputState)
109 { 109 {
116 return prompt; 116 return prompt;
117 } 117 }
118 118
119 // ------------------------------------------------------------------------------------------------- 119 // -------------------------------------------------------------------------------------------------
120 // 120 //
121 void Interface::set_input_state (InputState newstate) 121 void Interface::setInputState(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 m_inputState != INPUTSTATE_CONFIRM_DISCONNECTION) 125 and m_inputState != INPUTSTATE_CONFIRM_DISCONNECTION)
126 { 126 {
127 m_inputCursor = 0; 127 m_inputCursor = 0;
128 mutable_current_input().clear(); 128 getEditableInput().clear();
129 } 129 }
130 130
131 switch (newstate) 131 switch (newstate)
132 { 132 {
133 case INPUTSTATE_ADDRESS: 133 case INPUTSTATE_ADDRESS:
134 if (m_remoteAddress.host != 0) 134 if (m_remoteAddress.host != 0)
135 mutable_current_input() = m_remoteAddress.to_string (IPAddress::WITH_PORT); 135 getEditableInput() = m_remoteAddress.to_string(IPAddress::WITH_PORT);
136 break; 136 break;
137 137
138 default: 138 default:
139 break; 139 break;
140 } 140 }
144 } 144 }
145 145
146 // ------------------------------------------------------------------------------------------------- 146 // -------------------------------------------------------------------------------------------------
147 // 147 //
148 Interface::Interface() : 148 Interface::Interface() :
149 m_inputCursor (0), 149 m_inputCursor(0),
150 m_cursorPosition (0), 150 m_cursorPosition(0),
151 m_inputPanning (0), 151 m_inputPanning(0),
152 m_needRefresh (false), 152 m_needRefresh(false),
153 m_needStatusBarRender (false), 153 m_needStatusBarRender(false),
154 m_needInputRender (false), 154 m_needInputRender(false),
155 m_needOutputRender (false), 155 m_needOutputRender(false),
156 m_needNicklistRender (false), 156 m_needNicklistRender(false),
157 m_outputScroll (0), 157 m_outputScroll(0),
158 m_inputState (INPUTSTATE_NORMAL), 158 m_inputState(INPUTSTATE_NORMAL),
159 m_disconnectCallback (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 m_inputHistory.clear(); 167 m_inputHistory.clear();
168 m_inputHistory << ""; 168 m_inputHistory << "";
169 m_outputLines.clear(); 169 m_outputLines.clear();
170 m_outputLines << ColoredLine(); 170 m_outputLines << ColoredLine();
171 m_session.set_interface (this); 171 m_session.set_interface(this);
172 reset_title(); 172 resetTitle();
173 173
174 if (::has_colors()) 174 if (::has_colors())
175 { 175 {
176 ::start_color(); 176 ::start_color();
177 bool hasDefaultColors = (::use_default_colors() == OK); 177 bool hasDefaultColors =(::use_default_colors() == OK);
178 int defaultFg = hasDefaultColors ? -1 : COLOR_WHITE; 178 int defaultFg = hasDefaultColors ? -1 : COLOR_WHITE;
179 int defaultBg = hasDefaultColors ? -1 : COLOR_BLACK; 179 int defaultBg = hasDefaultColors ? -1 : COLOR_BLACK;
180 180
181 // Initialize color pairs 181 // Initialize color pairs
182 for (int i = 0; i < NUM_COLORS; ++i) 182 for (int i : range<int>(NUM_COLORS))
183 for (int j = 0; j < NUM_COLORS; ++j) 183 for (int j : range<int>(NUM_COLORS))
184 { 184 {
185 int pairnum = 1 + (i * NUM_COLORS + j); 185 int pairnum = 1 + (i * NUM_COLORS + j);
186 int fg = (i == DEFAULT) ? defaultFg : i; 186 int fg =(i == DEFAULT) ? defaultFg : i;
187 int bg = (j == DEFAULT) ? defaultBg : j; 187 int bg =(j == DEFAULT) ? defaultBg : j;
188 188
189 if (fg != -1 || bg != -1) 189 if (fg != -1 || bg != -1)
190 { 190 {
191 if (::init_pair (pairnum, fg, bg) == ERR) 191 if (::init_pair(pairnum, fg, bg) == ERR)
192 print_warning ("Unable to initialize color pair %d (%d, %d)\n", pairnum, fg, bg); 192 printWarning("Unable to initialize color pair %d(%d, %d)\n", pairnum, fg, bg);
193 } 193 }
194 } 194 }
195 } 195 }
196 196
197 render_full(); 197 renderFull();
198 refresh(); 198 refresh();
199 m_needRefresh = false; 199 m_needRefresh = false;
200 } 200 }
201 201
202 // ------------------------------------------------------------------------------------------------- 202 // -------------------------------------------------------------------------------------------------
203 // 203 //
204 void Interface::render_titlebar() 204 void Interface::renderTitlebar()
205 { 205 {
206 if (m_title.length() <= COLS) 206 if (m_title.length() <= COLS)
207 { 207 {
208 chtype pair = color_pair (WHITE, BLUE); 208 chtype pair = getColorPair(WHITE, BLUE);
209 int startx = (COLS - m_title.length()) / 2; 209 int startx =(COLS - m_title.length()) / 2;
210 int endx = startx + m_title.length(); 210 int endx = startx + m_title.length();
211 attron (pair); 211 attron(pair);
212 mvprintw (0, startx, "%s", m_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 m_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::setTitle(const String& title)
224 { 224 {
225 m_title = title; 225 m_title = title;
226 render_titlebar(); 226 renderTitlebar();
227 } 227 }
228 228
229 // ------------------------------------------------------------------------------------------------- 229 // -------------------------------------------------------------------------------------------------
230 // 230 //
231 void Interface::safe_disconnect (std::function<void(bool)> afterwards) 231 void Interface::safeDisconnect(std::function<void(bool)> afterwards)
232 { 232 {
233 if (m_session.is_active()) 233 if (m_session.is_active())
234 { 234 {
235 m_disconnectCallback = afterwards; 235 m_disconnectCallback = afterwards;
236 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); 236 setInputState(INPUTSTATE_CONFIRM_DISCONNECTION);
237 } 237 }
238 else 238 else
239 afterwards(false); 239 afterwards(false);
240 } 240 }
241 241
242 // ------------------------------------------------------------------------------------------------- 242 // -------------------------------------------------------------------------------------------------
243 // 243 //
244 int Interface::nicklist_width() 244 int Interface::nicklistWidth()
245 { 245 {
246 // Allocate at least 12 characters, at most 24 characters, for the nicklist. If we cannot 246 // Allocate at least 12 characters, at most 24 characters, for the nicklist. If we cannot
247 // afford that (o_O) then we probably shouldn't draw the nicklist at all I think. 247 // afford that(o_O) then we probably shouldn't draw the nicklist at all I think.
248 int nicklistWidth = COLS / 4; 248 int nicklistWidth = COLS / 4;
249 249
250 if (nicklistWidth < 12) 250 if (nicklistWidth < 12)
251 return 0; 251 return 0;
252 252
253 return min (nicklistWidth, 24); 253 return min(nicklistWidth, 24);
254 } 254 }
255 255
256 // ------------------------------------------------------------------------------------------------- 256 // -------------------------------------------------------------------------------------------------
257 // Renders the given colored line onto the screen. Will wrap if allowWrap is true. Returns the 257 // Renders the given colored line onto the screen. Will wrap if allowWrap is true. Returns the
258 // 'y' value for the next line. 258 // 'y' value for the next line.
259 // 259 //
260 int Interface::render_colorline (int y, int x0, int width, const ColoredLine& line, bool allowWrap) 260 int Interface::renderColorline(int y, int x0, int width, const ColoredLine& line, bool allowWrap)
261 { 261 {
262 int x = x0; 262 int x = x0;
263 263
264 for (int i = 0; i < line.data().size(); ++i) 264 for (int byte : line.data())
265 { 265 {
266 int byte = line.data()[i];
267
268 if (x == x0 + width) 266 if (x == x0 + width)
269 { 267 {
270 if (not allowWrap) 268 if (not allowWrap)
271 return y; 269 return y;
272 270
273 x = x0; 271 x = x0;
274 ++y; 272 ++y;
275 } 273 }
276 274
277 if (byte < 256 && isprint (byte)) 275 if (byte < 256 && isprint(byte))
278 { 276 {
279 mvaddch (y, x, char (byte)); 277 mvaddch(y, x, char(byte));
280 ++x; 278 ++x;
281 } 279 }
282 else if (byte >= RLINE_ON_COLOR and byte < (RLINE_ON_COLOR + 16)) 280 else if (byte >= RLINE_ON_COLOR and byte <(RLINE_ON_COLOR + 16))
283 { 281 {
284 auto attrfunction = (byte < RLINE_OFF_COLOR ? &attron : &attroff); 282 auto attrfunction =(byte < RLINE_OFF_COLOR ? &attron : &attroff);
285 (*attrfunction) (color_pair (Color ((byte - RLINE_ON_COLOR) & 7), DEFAULT)); 283 (*attrfunction)(getColorPair(Color((byte - RLINE_ON_COLOR) & 7), DEFAULT));
286 } 284 }
287 else switch (byte) 285 else switch (byte)
288 { 286 {
289 case RLINE_ON_BOLD: 287 case RLINE_ON_BOLD:
290 attron (A_BOLD); 288 attron(A_BOLD);
291 break; 289 break;
292 290
293 case RLINE_OFF_BOLD: 291 case RLINE_OFF_BOLD:
294 attroff (A_BOLD); 292 attroff(A_BOLD);
295 break; 293 break;
296 } 294 }
297 } 295 }
298 296
299 return y + 1; 297 return y + 1;
300 } 298 }
301 299
302 // ------------------------------------------------------------------------------------------------- 300 // -------------------------------------------------------------------------------------------------
303 // 301 //
304 void Interface::render_output() 302 void Interface::renderOutput()
305 { 303 {
306 if (m_outputLines.size() == 1) 304 if (m_outputLines.size() == 1)
307 return; 305 return;
308 306
309 m_outputScroll = clamp (m_outputScroll, 0, m_outputLines.size() - 1); 307 m_outputScroll = clamp(m_outputScroll, 0, m_outputLines.size() - 1);
310 308
311 int height = LINES - 3; 309 int height = LINES - 3;
312 int width = COLS - nicklist_width(); 310 int width = COLS - nicklistWidth();
313 int printOffset = 0; 311 int printOffset = 0;
314 int end = m_outputLines.size() - 1 - m_outputScroll; 312 int end = m_outputLines.size() - 1 - m_outputScroll;
315 int start = end; 313 int start = end;
316 int usedHeight = 0; 314 int usedHeight = 0;
317 int y = 1; 315 int y = 1;
318 bool tightFit = false; 316 bool tightFit = false;
319 317
320 // Where to start? 318 // Where to start?
321 while (start > 0) 319 while (start > 0)
322 { 320 {
323 int rows = m_outputLines[start - 1].rows (width); 321 int rows = m_outputLines[start - 1].rows(width);
324 322
325 if (usedHeight + rows > height) 323 if (usedHeight + rows > height)
326 { 324 {
327 // This line won't fit anymore. 325 // This line won't fit anymore.
328 tightFit = true; 326 tightFit = true;
331 329
332 start--; 330 start--;
333 usedHeight += rows; 331 usedHeight += rows;
334 } 332 }
335 333
336 // See if there's any more rows to use (end may be too small) 334 // See if there's any more rows to use(end may be too small)
337 if (not tightFit) 335 if (not tightFit)
338 { 336 {
339 while (end < m_outputLines.size()) 337 while (end < m_outputLines.size())
340 { 338 {
341 int rows = m_outputLines[end].rows (width); 339 int rows = m_outputLines[end].rows(width);
342 340
343 if (usedHeight + rows > height) 341 if (usedHeight + rows > height)
344 { 342 {
345 tightFit = true; 343 tightFit = true;
346 break; 344 break;
357 m_outputScroll = m_outputLines.size() - 1 - end; 355 m_outputScroll = m_outputLines.size() - 1 - end;
358 356
359 if (start < 0 or start == end or printOffset >= height) 357 if (start < 0 or start == end or printOffset >= height)
360 return; 358 return;
361 359
362 assert (start <= end and start - end <= height); 360 assert(start <= end and start - end <= height);
363 361
364 // Clear the display 362 // Clear the display
365 for (int i = y; i < y + height; ++i) 363 for (int i : range(height))
366 mvhline (i, 0, ' ', width); 364 mvhline(y + i, 0, ' ', width);
367 365
368 // Print the lines 366 // Print the lines
369 y += printOffset; 367 y += printOffset;
370 368
371 for (int i = start; i < end; ++i) 369 for (int i : range(start, end))
372 y = render_colorline (y, 0, width, m_outputLines[i], true); 370 y = renderColorline(y, 0, width, m_outputLines[i], true);
373 371
374 m_needOutputRender = false; 372 m_needOutputRender = false;
375 m_needRefresh = true; 373 m_needRefresh = true;
376 } 374 }
377 375
378 // ------------------------------------------------------------------------------------------------- 376 // -------------------------------------------------------------------------------------------------
379 // 377 //
380 void Interface::render_nicklist() 378 void Interface::renderNicklist()
381 { 379 {
382 int width = nicklist_width(); 380 int width = nicklistWidth();
383 int height = LINES- 3; 381 int height = LINES- 3;
384 int y = 1; 382 int y = 1;
385 int x = COLS - width; 383 int x = COLS - width;
386 384
387 if (width == 0) 385 if (width > 0)
388 return; 386 return;
389 387
390 for (int i = 0; i < height; ++i) 388 for (int i : range(height))
391 { 389 {
392 mvhline (y, x, ' ', width); 390 mvhline(y, x, ' ', width);
393 391
394 if (i < m_playerNames.size()) 392 if (i < m_playerNames.size())
395 render_colorline (y, x, width, m_playerNames[i], false); 393 renderColorline(y, x, width, m_playerNames[i], false);
396 394
397 y++; 395 y++;
398 } 396 }
399 397
400 m_needNicklistRender = false; 398 m_needNicklistRender = false;
401 m_needRefresh = true; 399 m_needRefresh = true;
402 } 400 }
403 401
404 // ------------------------------------------------------------------------------------------------- 402 // -------------------------------------------------------------------------------------------------
405 // 403 //
406 void Interface::render_input() 404 void Interface::renderInput()
407 { 405 {
408 chtype promptColor = color_pair (WHITE, BLUE); 406 chtype promptColor = getColorPair(WHITE, BLUE);
409 407
410 // If we're asking the user if they want to disconnect, we don't render any input strings, 408 // If we're asking the user if they want to disconnect, we don't render any input strings,
411 // just the confirmation message. 409 // just the confirmation message.
412 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 410 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
413 { 411 {
414 attron (promptColor); 412 attron(promptColor);
415 mvhline (LINES - 2, 0, ' ', COLS); 413 mvhline(LINES - 2, 0, ' ', COLS);
416 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n"); 414 mvprintw(LINES - 2, 0, "Are you sure you want to disconnect? y/n");
417 attroff (promptColor); 415 attroff(promptColor);
418 m_needRefresh = true; 416 m_needRefresh = true;
419 return; 417 return;
420 } 418 }
421 419
422 String prompt = prompt_string(); 420 String prompt = getPromptString();
423 int displayLength = COLS - prompt.length() - 2; 421 int displayLength = COLS - prompt.length() - 2;
424 String displayString = current_input(); 422 String displayString = getCurrentInput();
425 int y = LINES - 2; 423 int y = LINES - 2;
426 424
427 // If we're inputting a password, replace it with asterisks 425 // If we're inputting a password, replace it with asterisks
428 if (m_inputState == INPUTSTATE_PASSWORD) 426 if (m_inputState == INPUTSTATE_PASSWORD)
429 { 427 {
430 for (int i = 0; i < displayString.length(); ++i) 428 for (char &ch : displayString)
431 displayString[i] = '*'; 429 ch = '*';
432 } 430 }
433 431
434 // Ensure the cursor is within bounds 432 // Ensure the cursor is within bounds
435 m_cursorPosition = clamp (m_cursorPosition, 0, displayString.length()); 433 m_cursorPosition = clamp(m_cursorPosition, 0, displayString.length());
436 434
437 // Ensure that the cursor is always in view, adjust panning if this is not the case 435 // Ensure that the cursor is always in view, adjust panning if this is not the case
438 if (m_cursorPosition > m_inputPanning + displayLength) 436 if (m_cursorPosition > m_inputPanning + displayLength)
439 m_inputPanning = m_cursorPosition - displayLength; // cursor went too far right 437 m_inputPanning = m_cursorPosition - displayLength; // cursor went too far right
440 else if (m_cursorPosition < m_inputPanning) 438 else if (m_cursorPosition < m_inputPanning)
441 m_inputPanning = m_cursorPosition; // cursor went past the pan value to the left 439 m_inputPanning = m_cursorPosition; // cursor went past the pan value to the left
442 440
443 // What part of the string to draw? 441 // What part of the string to draw?
444 int start = m_inputPanning; 442 int start = m_inputPanning;
445 int end = min<int> (displayString.length(), start + displayLength); 443 int end = min<int>(displayString.length(), start + displayLength);
446 assert (m_cursorPosition >= start and m_cursorPosition <= end); 444 assert(m_cursorPosition >= start and m_cursorPosition <= end);
447 445
448 // Render the input string 446 // Render the input string
449 mvhline (LINES - 2, 0, ' ', COLS); 447 mvhline(LINES - 2, 0, ' ', COLS);
450 mvprintw (y, prompt.length() + 1, "%s", displayString.mid (start, end).chars()); 448 mvprintw(y, prompt.length() + 1, "%s", displayString.mid(start, end).chars());
451 449
452 // Render the prompt 450 // Render the prompt
453 attron (promptColor); 451 attron(promptColor);
454 mvprintw (y, 0, "%s", prompt.chars()); 452 mvprintw(y, 0, "%s", prompt.chars());
455 attroff (promptColor); 453 attroff(promptColor);
456 454
457 // Store in memory where the cursor is now (so that we can re-draw it to position the terminal 455 // Store in memory where the cursor is now(so that we can re-draw it to position the terminal
458 // cursor). 456 // cursor).
459 m_cursorCharacter.ch = m_cursorPosition != 0 ? displayString[m_cursorPosition - 1] : '\0'; 457 m_cursorCharacter.ch = m_cursorPosition != 0 ? displayString[m_cursorPosition - 1] : '\0';
460 m_cursorCharacter.x = prompt.length() + (m_cursorPosition - m_inputPanning); 458 m_cursorCharacter.x = prompt.length() + (m_cursorPosition - m_inputPanning);
461 m_needRefresh = true; 459 m_needRefresh = true;
462 m_needInputRender = false; 460 m_needInputRender = false;
463 } 461 }
464 462
465 // ------------------------------------------------------------------------------------------------- 463 // -------------------------------------------------------------------------------------------------
466 // 464 //
467 void Interface::render_statusbar() 465 void Interface::renderStatusBar()
468 { 466 {
469 chtype color = color_pair (WHITE, BLUE); 467 chtype color = getColorPair(WHITE, BLUE);
470 int y = LINES - 1; 468 int y = LINES - 1;
471 attron (color); 469 attron(color);
472 mvhline (y, 0, ' ', COLS); 470 mvhline(y, 0, ' ', COLS);
473 mvprintw (y, 0, "%s", m_statusBarText.chars()); 471 mvprintw(y, 0, "%s", m_statusBarText.chars());
474 attroff (color); 472 attroff(color);
475 m_needRefresh = true; 473 m_needRefresh = true;
476 m_needStatusBarRender = false; 474 m_needStatusBarRender = false;
477 } 475 }
478 476
479 // ------------------------------------------------------------------------------------------------- 477 // -------------------------------------------------------------------------------------------------
480 // 478 //
481 void Interface::update_statusbar() 479 void Interface::updateStatusBar()
482 { 480 {
483 String text; 481 String text;
484 482
485 switch (m_session.state()) 483 switch (m_session.state())
486 { 484 {
488 text = "Disconnected."; 486 text = "Disconnected.";
489 break; 487 break;
490 488
491 case RCON_CONNECTING: 489 case RCON_CONNECTING:
492 case RCON_AUTHENTICATING: 490 case RCON_AUTHENTICATING:
493 text = "Connecting to " + m_session.address().to_string (IPAddress::WITH_PORT) + "..."; 491 text = "Connecting to " + m_session.address().to_string(IPAddress::WITH_PORT) + "...";
494 break; 492 break;
495 493
496 case RCON_CONNECTED: 494 case RCON_CONNECTED:
497 { 495 {
498 String adminText; 496 String adminText;
501 { 499 {
502 adminText = "No other admins"; 500 adminText = "No other admins";
503 } 501 }
504 else 502 else
505 { 503 {
506 adminText.sprintf ("%d other admin%s", m_session.num_admins(), 504 adminText.sprintf("%d other admin%s", m_session.num_admins(),
507 m_session.num_admins() != 1 ? "s" : ""); 505 m_session.num_admins() != 1 ? "s" : "");
508 } 506 }
509 507
510 text.sprintf ("%s | %s | %s", 508 text.sprintf("%s | %s | %s",
511 m_session.address().to_string (IPAddress::WITH_PORT).chars(), 509 m_session.address().to_string(IPAddress::WITH_PORT).chars(),
512 m_session.level().chars(), 510 m_session.level().chars(),
513 adminText.chars()); 511 adminText.chars());
514 } 512 }
515 break; 513 break;
516 } 514 }
517 515
518 if (not text.is_empty()) 516 if (not text.is_empty())
519 text += " | "; 517 text += " | ";
520 518
521 text += "Ctrl+N to connect, Ctrl+Q to "; 519 text += "Ctrl+N to connect, Ctrl+Q to ";
522 text += (m_session.state() == RCON_DISCONNECTED) ? "quit" : "disconnect"; 520 text +=(m_session.state() == RCON_DISCONNECTED) ? "quit" : "disconnect";
523 521
524 if (text != m_statusBarText) 522 if (text != m_statusBarText)
525 { 523 {
526 m_statusBarText = text; 524 m_statusBarText = text;
527 m_needStatusBarRender = true; 525 m_needStatusBarRender = true;
528 } 526 }
529 } 527 }
530 528
531 // ------------------------------------------------------------------------------------------------- 529 // -------------------------------------------------------------------------------------------------
532 // 530 //
533 void Interface::render_full() 531 void Interface::renderFull()
534 { 532 {
535 update_statusbar(); 533 updateStatusBar();
536 render_titlebar(); 534 renderTitlebar();
537 render_output(); 535 renderOutput();
538 render_statusbar(); 536 renderStatusBar();
539 render_input(); 537 renderInput();
540 render_nicklist(); 538 renderNicklist();
541 } 539 }
542 540
543 // ------------------------------------------------------------------------------------------------- 541 // -------------------------------------------------------------------------------------------------
544 // 542 //
545 void Interface::position_cursor() 543 void Interface::positionCursor()
546 { 544 {
547 // This is only relevant if the input string is being drawn 545 // This is only relevant if the input string is being drawn
548 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 546 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
549 return; 547 return;
550 548
551 int y = LINES - 2; 549 int y = LINES - 2;
552 550
553 if (m_cursorCharacter.ch != '\0') 551 if (m_cursorCharacter.ch != '\0')
554 mvprintw (y, m_cursorCharacter.x, "%c", m_cursorCharacter.ch); 552 mvprintw(y, m_cursorCharacter.x, "%c", m_cursorCharacter.ch);
555 else 553 else
556 mvprintw (y, prompt_string().length(), " "); 554 mvprintw(y, getPromptString().length(), " ");
557 } 555 }
558 556
559 // ------------------------------------------------------------------------------------------------- 557 // -------------------------------------------------------------------------------------------------
560 // 558 //
561 int Interface::find_previous_word() 559 int Interface::findPreviousWord()
562 { 560 {
563 const String& input = current_input(); 561 const String& input = getCurrentInput();
564 int pos = m_cursorPosition; 562 int pos = m_cursorPosition;
565 563
566 // Move past whitespace 564 // Move past whitespace
567 while (pos > 0 and isspace (input[pos - 1])) 565 while (pos > 0 and isspace(input[pos - 1]))
568 pos--; 566 pos--;
569 567
570 // Move past the word 568 // Move past the word
571 while (pos > 0 and not isspace (input[pos - 1])) 569 while (pos > 0 and not isspace(input[pos - 1]))
572 pos--; 570 pos--;
573 571
574 return pos; 572 return pos;
575 } 573 }
576 574
577 // ------------------------------------------------------------------------------------------------- 575 // -------------------------------------------------------------------------------------------------
578 // 576 //
579 int Interface::find_next_word() 577 int Interface::findNextWord()
580 { 578 {
581 const String& input = current_input(); 579 const String& input = getCurrentInput();
582 int pos = m_cursorPosition; 580 int pos = m_cursorPosition;
583 581
584 // Move past current whitespace 582 // Move past current whitespace
585 while (pos < input.length() and isspace (input[pos])) 583 while (pos < input.length() and isspace(input[pos]))
586 pos++; 584 pos++;
587 585
588 // Move past the word 586 // Move past the word
589 while (input[pos] != '\0' and not isspace (input[pos])) 587 while (input[pos] != '\0' and not isspace(input[pos]))
590 pos++; 588 pos++;
591 589
592 return pos; 590 return pos;
593 } 591 }
594 592
595 // ------------------------------------------------------------------------------------------------- 593 // -------------------------------------------------------------------------------------------------
596 // 594 //
597 void Interface::yank (int a, int b) 595 void Interface::yank(int a, int b)
598 { 596 {
599 if (a >= b) 597 if (a >= b)
600 return; 598 return;
601 599
602 if (m_cursorPosition > a and m_cursorPosition <= b) 600 if (m_cursorPosition > a and m_cursorPosition <= b)
603 m_cursorPosition = a; 601 m_cursorPosition = a;
604 602
605 String& input = mutable_current_input(); 603 String& input = getEditableInput();
606 m_pasteBuffer = input.mid (a, b); 604 m_pasteBuffer = input.mid(a, b);
607 input.remove (a, b - a); 605 input.remove(a, b - a);
608 m_needInputRender = true; 606 m_needInputRender = true;
609 } 607 }
610 608
611 // ------------------------------------------------------------------------------------------------- 609 // -------------------------------------------------------------------------------------------------
612 // 610 //
613 void Interface::handle_input() 611 void Interface::handleInput()
614 { 612 {
615 int ch = ::getch(); 613 int ch = ::getch();
616 614
617 if (ch < 0) 615 if (ch < 0)
618 return; 616 return;
619 617
620 if (ch == KEY_RESIZE) 618 if (ch == KEY_RESIZE)
621 { 619 {
622 ::clear(); 620 ::clear();
623 render_full(); 621 renderFull();
624 return; 622 return;
625 } 623 }
626 624
627 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) 625 if (m_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
628 { 626 {
630 { 628 {
631 m_session.disconnect(); 629 m_session.disconnect();
632 m_disconnectCallback(true); 630 m_disconnectCallback(true);
633 } 631 }
634 else if (ch == 'n' or ch == 'N') 632 else if (ch == 'n' or ch == 'N')
635 set_input_state (INPUTSTATE_NORMAL); 633 setInputState(INPUTSTATE_NORMAL);
636 634
637 return; 635 return;
638 } 636 }
639 637
640 if (ch >= 0x20 and ch <= 0x7E) 638 if (ch >= 0x20 and ch <= 0x7E)
641 { 639 {
642 mutable_current_input().insert (m_cursorPosition++, char (ch)); 640 getEditableInput().insert(m_cursorPosition++, char(ch));
643 m_needInputRender = true; 641 m_needInputRender = true;
644 } 642 }
645 else switch (ch) 643 else switch (ch)
646 { 644 {
647 case 'Q' - 'A' + 1: // ^Q 645 case 'Q' - 'A' + 1: // ^Q
649 { 647 {
650 case INPUTSTATE_CONFIRM_DISCONNECTION: 648 case INPUTSTATE_CONFIRM_DISCONNECTION:
651 break; 649 break;
652 650
653 case INPUTSTATE_NORMAL: 651 case INPUTSTATE_NORMAL:
654 safe_disconnect ([&](bool hadsession) 652 safeDisconnect([&](bool hadsession)
655 { 653 {
656 if (hadsession) 654 if (hadsession)
657 { 655 {
658 set_input_state (INPUTSTATE_NORMAL); 656 setInputState(INPUTSTATE_NORMAL);
659 } 657 }
660 else 658 else
661 { 659 {
662 endwin(); 660 endwin();
663 throw Exitception(); 661 throw Exitception();
664 } 662 }
665 }); 663 });
666 break; 664 break;
667 665
668 case INPUTSTATE_PASSWORD: 666 case INPUTSTATE_PASSWORD:
669 set_input_state (INPUTSTATE_ADDRESS); 667 setInputState(INPUTSTATE_ADDRESS);
670 break; 668 break;
671 669
672 case INPUTSTATE_ADDRESS: 670 case INPUTSTATE_ADDRESS:
673 set_input_state (INPUTSTATE_NORMAL); 671 setInputState(INPUTSTATE_NORMAL);
674 } 672 }
675 break; 673 break;
676 674
677 case KEY_LEFT: 675 case KEY_LEFT:
678 case 'B' - 'A' + 1: // readline ^B 676 case 'B' - 'A' + 1: // readline ^B
683 } 681 }
684 break; 682 break;
685 683
686 case KEY_RIGHT: 684 case KEY_RIGHT:
687 case 'F' - 'A' + 1: // readline ^F 685 case 'F' - 'A' + 1: // readline ^F
688 if (m_cursorPosition < current_input().length()) 686 if (m_cursorPosition < getCurrentInput().length())
689 { 687 {
690 m_cursorPosition++; 688 m_cursorPosition++;
691 m_needInputRender = true; 689 m_needInputRender = true;
692 } 690 }
693 break; 691 break;
694 692
695 case KEY_DOWN: 693 case KEY_DOWN:
696 case KEY_UP: 694 case KEY_UP:
697 move_input_cursor (ch == KEY_DOWN ? -1 : 1); 695 moveInputCursor(ch == KEY_DOWN ? -1 : 1);
698 break; 696 break;
699 697
700 case KEY_HOME: 698 case KEY_HOME:
701 case 'A' - 'A' + 1: // readline ^A 699 case 'A' - 'A' + 1: // readline ^A
702 if (m_cursorPosition != 0) 700 if (m_cursorPosition != 0)
706 } 704 }
707 break; 705 break;
708 706
709 case KEY_END: 707 case KEY_END:
710 case 'E' - 'A' + 1: // readline ^E 708 case 'E' - 'A' + 1: // readline ^E
711 if (m_cursorPosition != current_input().length()) 709 if (m_cursorPosition != getCurrentInput().length())
712 { 710 {
713 m_cursorPosition = current_input().length(); 711 m_cursorPosition = getCurrentInput().length();
714 m_needInputRender = true; 712 m_needInputRender = true;
715 } 713 }
716 break; 714 break;
717 715
718 case KEY_BACKSPACE: 716 case KEY_BACKSPACE:
719 case '\b': 717 case '\b':
720 if (m_cursorPosition > 0) 718 if (m_cursorPosition > 0)
721 { 719 {
722 mutable_current_input().remove_at (--m_cursorPosition); 720 getEditableInput().remove_at(--m_cursorPosition);
723 m_needInputRender = true; 721 m_needInputRender = true;
724 } 722 }
725 break; 723 break;
726 724
727 case KEY_DC: 725 case KEY_DC:
728 case 'D' - 'A' + 1: // readline ^D 726 case 'D' - 'A' + 1: // readline ^D
729 if (m_cursorPosition < current_input().length()) 727 if (m_cursorPosition < getCurrentInput().length())
730 { 728 {
731 mutable_current_input().remove_at (m_cursorPosition); 729 getEditableInput().remove_at(m_cursorPosition);
732 m_needInputRender = true; 730 m_needInputRender = true;
733 } 731 }
734 break; 732 break;
735 733
736 case KEY_PPAGE: 734 case KEY_PPAGE:
737 m_outputScroll += min (PAGE_SIZE, LINES / 2); 735 m_outputScroll += min(PAGE_SIZE, LINES / 2);
738 m_needOutputRender = true; 736 m_needOutputRender = true;
739 break; 737 break;
740 738
741 case KEY_NPAGE: 739 case KEY_NPAGE:
742 m_outputScroll -= min (PAGE_SIZE, LINES / 2); 740 m_outputScroll -= min(PAGE_SIZE, LINES / 2);
743 m_needOutputRender = true; 741 m_needOutputRender = true;
744 break; 742 break;
745 743
746 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor 744 case 'U' - 'A' + 1: // readline ^U - delete from start to cursor
747 if (m_cursorPosition > 0) 745 if (m_cursorPosition > 0)
748 { 746 {
749 yank (0, m_cursorPosition); 747 yank(0, m_cursorPosition);
750 m_cursorPosition = 0; 748 m_cursorPosition = 0;
751 } 749 }
752 break; 750 break;
753 751
754 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end 752 case 'K' - 'A' + 1: // readline ^K - delete from cursor to end
755 yank (m_cursorPosition, mutable_current_input().length()); 753 yank(m_cursorPosition, getEditableInput().length());
756 break; 754 break;
757 755
758 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current 756 case 'W' - 'A' + 1: // readline ^W - delete from previous word bounary to current
759 yank (find_previous_word(), m_cursorPosition); 757 yank(findPreviousWord(), m_cursorPosition);
760 break; 758 break;
761 759
762 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text 760 case 'Y' - 'A' + 1: // readline ^Y - paste previously deleted text
763 if (not m_pasteBuffer.is_empty()) 761 if (not m_pasteBuffer.is_empty())
764 { 762 {
765 mutable_current_input().insert (m_cursorPosition, m_pasteBuffer); 763 getEditableInput().insert(m_cursorPosition, m_pasteBuffer);
766 m_cursorPosition += m_pasteBuffer.length(); 764 m_cursorPosition += m_pasteBuffer.length();
767 m_needInputRender = true; 765 m_needInputRender = true;
768 } 766 }
769 break; 767 break;
770 768
771 case '\t': 769 case '\t':
772 { 770 {
773 int space = current_input().find (" "); 771 int space = getCurrentInput().find(" ");
774 772
775 if (m_inputState == INPUTSTATE_NORMAL 773 if (m_inputState == INPUTSTATE_NORMAL
776 and m_cursorPosition > 0 774 and m_cursorPosition > 0
777 and (space == -1 or space >= m_cursorPosition)) 775 and(space == -1 or space >= m_cursorPosition))
778 { 776 {
779 String start = current_input().mid (0, m_cursorPosition); 777 String start = getCurrentInput().mid(0, m_cursorPosition);
780 m_session.request_tab_complete (start); 778 m_session.request_tab_complete(start);
781 } 779 }
782 } 780 }
783 break; 781 break;
784 782
785 case '\n': 783 case '\n':
791 break; // handled above 789 break; // handled above
792 790
793 case INPUTSTATE_ADDRESS: 791 case INPUTSTATE_ADDRESS:
794 try 792 try
795 { 793 {
796 m_remoteAddress = IPAddress::from_string (current_input()); 794 m_remoteAddress = IPAddress::from_string(getCurrentInput());
797 } 795 }
798 catch (std::exception& e) 796 catch (std::exception& e)
799 { 797 {
800 print ("%s\n", e.what()); 798 print("%s\n", e.what());
801 return; 799 return;
802 } 800 }
803 801
804 if (m_remoteAddress.port == 0) 802 if (m_remoteAddress.port == 0)
805 m_remoteAddress.port = 10666; 803 m_remoteAddress.port = 10666;
806 804
807 set_input_state (INPUTSTATE_PASSWORD); 805 setInputState(INPUTSTATE_PASSWORD);
808 break; 806 break;
809 807
810 case INPUTSTATE_PASSWORD: 808 case INPUTSTATE_PASSWORD:
811 if (m_inputState == INPUTSTATE_PASSWORD and not current_input().is_empty()) 809 if (m_inputState == INPUTSTATE_PASSWORD and not getCurrentInput().is_empty())
812 { 810 {
813 m_session.disconnect(); 811 m_session.disconnect();
814 m_session.set_password (current_input()); 812 m_session.set_password(getCurrentInput());
815 m_session.connect (m_remoteAddress); 813 m_session.connect(m_remoteAddress);
816 set_input_state (INPUTSTATE_NORMAL); 814 setInputState(INPUTSTATE_NORMAL);
817 } 815 }
818 break; 816 break;
819 817
820 case INPUTSTATE_NORMAL: 818 case INPUTSTATE_NORMAL:
821 if (current_input()[0] == '/') 819 if (getCurrentInput()[0] == '/')
822 { 820 {
823 handle_command(current_input()); 821 handleCommand(getCurrentInput());
824 flush_input(); 822 flushInput();
825 } 823 }
826 else if (m_session.send_command (current_input())) 824 else if (m_session.send_command(getCurrentInput()))
827 { 825 {
828 flush_input(); 826 flushInput();
829 } 827 }
830 break; 828 break;
831 } 829 }
832 break; 830 break;
833 831
834 case 'N' - 'A' + 1: // ^N 832 case 'N' - 'A' + 1: // ^N
835 if (m_inputState == INPUTSTATE_NORMAL) 833 if (m_inputState == INPUTSTATE_NORMAL)
836 safe_disconnect ([&](bool){set_input_state (INPUTSTATE_ADDRESS);}); 834 safeDisconnect([&](bool){setInputState(INPUTSTATE_ADDRESS);});
837 break; 835 break;
838 836
839 case '\x1b': // Escape 837 case '\x1b': // Escape
840 // We may have an alt key coming 838 // We may have an alt key coming
841 ch = ::getch(); 839 ch = ::getch();
845 switch (ch) 843 switch (ch)
846 { 844 {
847 case 'b': 845 case 'b':
848 case 'B': 846 case 'B':
849 // readline alt-b - move one word to the left 847 // readline alt-b - move one word to the left
850 m_cursorPosition = find_previous_word(); 848 m_cursorPosition = findPreviousWord();
851 m_needInputRender = true; 849 m_needInputRender = true;
852 break; 850 break;
853 851
854 case 'f': 852 case 'f':
855 case 'F': 853 case 'F':
856 // readline alt-f - move one word to the right 854 // readline alt-f - move one word to the right
857 m_cursorPosition = find_next_word(); 855 m_cursorPosition = findNextWord();
858 m_needInputRender = true; 856 m_needInputRender = true;
859 break; 857 break;
860 858
861 case 'd': 859 case 'd':
862 case 'D': 860 case 'D':
863 // readline alt-d - delete from here till next word boundary 861 // readline alt-d - delete from here till next word boundary
864 yank (m_cursorPosition, find_next_word()); 862 yank(m_cursorPosition, findNextWord());
865 break; 863 break;
866 864
867 case KEY_BACKSPACE: // alt+backspace, remove previous word 865 case KEY_BACKSPACE: // alt+backspace, remove previous word
868 case '\b': 866 case '\b':
869 yank (find_previous_word(), m_cursorPosition); 867 yank(findPreviousWord(), m_cursorPosition);
870 break; 868 break;
871 } 869 }
872 } 870 }
873 else 871 else
874 { 872 {
875 // No alt-key, handle pure escape 873 // No alt-key, handle pure escape
876 if (m_inputState == INPUTSTATE_PASSWORD) 874 if (m_inputState == INPUTSTATE_PASSWORD)
877 set_input_state (INPUTSTATE_ADDRESS); 875 setInputState(INPUTSTATE_ADDRESS);
878 else if (m_inputState == INPUTSTATE_ADDRESS) 876 else if (m_inputState == INPUTSTATE_ADDRESS)
879 set_input_state (INPUTSTATE_NORMAL); 877 setInputState(INPUTSTATE_NORMAL);
880 } 878 }
881 break; 879 break;
882 } 880 }
883 881
884 render(); 882 render();
886 884
887 // ------------------------------------------------------------------------------------------------- 885 // -------------------------------------------------------------------------------------------------
888 // 886 //
889 void Interface::render() 887 void Interface::render()
890 { 888 {
891 if (m_needStatusBarRender) render_statusbar(); 889 if (m_needStatusBarRender) renderStatusBar();
892 if (m_needInputRender) render_input(); 890 if (m_needInputRender) renderInput();
893 if (m_needOutputRender) render_output(); 891 if (m_needOutputRender) renderOutput();
894 if (m_needNicklistRender) render_nicklist(); 892 if (m_needNicklistRender) renderNicklist();
895 893
896 if (m_needRefresh) 894 if (m_needRefresh)
897 { 895 {
898 position_cursor(); 896 positionCursor();
899 refresh(); 897 refresh();
900 m_needRefresh = false; 898 m_needRefresh = false;
901 } 899 }
902 } 900 }
903 901
904 // ------------------------------------------------------------------------------------------------- 902 // -------------------------------------------------------------------------------------------------
905 // 903 //
906 void Interface::vprint (const char* fmtstr, va_list args) 904 void Interface::vprint(const char* fmtstr, va_list args)
907 { 905 {
908 String message; 906 String message;
909 message.vsprintf (fmtstr, args); 907 message.vsprintf(fmtstr, args);
910 print_to_console (message); 908 printToConsole(message);
911 } 909 }
912 910
913 // ------------------------------------------------------------------------------------------------- 911 // -------------------------------------------------------------------------------------------------
914 // 912 //
915 void __cdecl Interface::print_text (const char* fmtstr, ...) 913 void __cdecl Interface::printText(const char* fmtstr, ...)
916 { 914 {
917 va_list args; 915 va_list args;
918 va_start (args, fmtstr); 916 va_start(args, fmtstr);
919 vprint (fmtstr, args); 917 vprint(fmtstr, args);
920 va_end (args); 918 va_end(args);
921 } 919 }
922 920
923 // ------------------------------------------------------------------------------------------------- 921 // -------------------------------------------------------------------------------------------------
924 // 922 //
925 void __cdecl Interface::print (const char* fmtstr, ...) 923 void __cdecl Interface::print(const char* fmtstr, ...)
926 { 924 {
927 va_list args; 925 va_list args;
928 va_start (args, fmtstr); 926 va_start(args, fmtstr);
929 print_to_console (TEXTCOLOR_BrightBlue); 927 printToConsole(TEXTCOLOR_BrightBlue);
930 vprint (fmtstr, args); 928 vprint(fmtstr, args);
931 va_end (args); 929 va_end(args);
932 } 930 }
933 931
934 // ------------------------------------------------------------------------------------------------- 932 // -------------------------------------------------------------------------------------------------
935 // 933 //
936 void __cdecl Interface::print_warning (const char* fmtstr, ...) 934 void __cdecl Interface::printWarning(const char* fmtstr, ...)
937 { 935 {
938 va_list args; 936 va_list args;
939 va_start (args, fmtstr); 937 va_start(args, fmtstr);
940 print_to_console (TEXTCOLOR_BrightYellow "-!- "); 938 printToConsole(TEXTCOLOR_BrightYellow "-!- ");
941 vprint (fmtstr, args); 939 vprint(fmtstr, args);
942 va_end (args); 940 va_end(args);
943 } 941 }
944 942
945 // ------------------------------------------------------------------------------------------------- 943 // -------------------------------------------------------------------------------------------------
946 // 944 //
947 void __cdecl Interface::print_error (const char* fmtstr, ...) 945 void __cdecl Interface::printError(const char* fmtstr, ...)
948 { 946 {
949 va_list args; 947 va_list args;
950 va_start (args, fmtstr); 948 va_start(args, fmtstr);
951 print_to_console (TEXTCOLOR_BrightRed "!!! "); 949 printToConsole(TEXTCOLOR_BrightRed "!!! ");
952 vprint (fmtstr, args); 950 vprint(fmtstr, args);
953 va_end (args); 951 va_end(args);
954 } 952 }
955 953
956 // ------------------------------------------------------------------------------------------------- 954 // -------------------------------------------------------------------------------------------------
957 // 955 //
958 void Interface::print_to_console (String message) 956 void Interface::printToConsole(String message)
959 { 957 {
960 // Zandronum sometimes sends color codes as "\\c" and sometimes as "\x1C". 958 // Zandronum sometimes sends color codes as "\\c" and sometimes as "\x1C".
961 // Let's correct that on our end and hope this won't cause conflicts. 959 // Let's correct that on our end and hope this won't cause conflicts.
962 message.replace ("\\c", "\x1C"); 960 message.replace("\\c", "\x1C");
963 961
964 for (int i = 0; i < message.length(); ++i) 962 for (char ch : message)
965 { 963 {
966 char ch = message[i];
967
968 if (ch == '\n') 964 if (ch == '\n')
969 { 965 {
970 m_outputLines.last().finalize(); 966 m_outputLines.last().finalize();
971 m_outputLines << ColoredLine(); 967 m_outputLines << ColoredLine();
972 continue; 968 continue;
973 } 969 }
974 970
975 if (m_outputLines.last().length() == 0) 971 if (m_outputLines.last().length() == 0)
976 { 972 {
977 time_t now; 973 time_t now;
978 time (&now); 974 time(&now);
979 char timestamp[32]; 975 char timestamp[32];
980 strftime (timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime (&now)); 976 strftime(timestamp, sizeof timestamp, "[%H:%M:%S] ", localtime(&now));
981 977
982 for (char* cp = timestamp; *cp != '\0'; ++cp) 978 for (char ch : String(timestamp))
983 m_outputLines.last().add_char (*cp); 979 m_outputLines.last().add_char(ch);
984 } 980 }
985 981
986 // Remove some lines if there's too many of them. 20,000 should be enough, I hope. 982 // Remove some lines if there's too many of them. 20,000 should be enough, I hope.
987 while (m_outputLines.size() > 20000) 983 while (m_outputLines.size() > 20000)
988 m_outputLines.remove_at(0); 984 m_outputLines.remove_at(0);
989 985
990 m_outputLines.last().add_char (ch); 986 m_outputLines.last().add_char(ch);
991 } 987 }
992 988
993 m_needOutputRender = true; 989 m_needOutputRender = true;
994 } 990 }
995 991
996 // ------------------------------------------------------------------------------------------------- 992 // -------------------------------------------------------------------------------------------------
997 // 993 //
998 void Interface::connect (String address, String password) 994 void Interface::connect(String address, String password)
999 { 995 {
1000 try 996 try
1001 { 997 {
1002 m_remoteAddress = IPAddress::from_string (address); 998 m_remoteAddress = IPAddress::from_string(address);
1003 } 999 }
1004 catch (std::exception& e) 1000 catch (std::exception& e)
1005 { 1001 {
1006 print ("%s\n", e.what()); 1002 print("%s\n", e.what());
1007 return; 1003 return;
1008 } 1004 }
1009 1005
1010 if (m_remoteAddress.port == 0) 1006 if (m_remoteAddress.port == 0)
1011 m_remoteAddress.port = 10666; 1007 m_remoteAddress.port = 10666;
1012 1008
1013 m_session.disconnect(); 1009 m_session.disconnect();
1014 m_session.set_password (password); 1010 m_session.set_password(password);
1015 m_session.connect (m_remoteAddress); 1011 m_session.connect(m_remoteAddress);
1016 } 1012 }
1017 1013
1018 // ------------------------------------------------------------------------------------------------- 1014 // -------------------------------------------------------------------------------------------------
1019 // 1015 //
1020 void Interface::set_player_names (const StringList& names) 1016 void Interface::setPlayerNames(const StringList& names)
1021 { 1017 {
1022 m_playerNames.clear(); 1018 m_playerNames.clear();
1023 1019
1024 for (const String& name : names) 1020 for (const String& name : names)
1025 { 1021 {
1026 ColoredLine coloredname; 1022 ColoredLine coloredname;
1027 coloredname.add_string (name); 1023 coloredname.add_string(name);
1028 coloredname.finalize(); 1024 coloredname.finalize();
1029 m_playerNames.append (coloredname); 1025 m_playerNames.append(coloredname);
1030 } 1026 }
1031 1027
1032 m_needNicklistRender = true; 1028 m_needNicklistRender = true;
1033 } 1029 }
1034 1030
1035 // ------------------------------------------------------------------------------------------------- 1031 // -------------------------------------------------------------------------------------------------
1036 // 1032 //
1037 void Interface::tab_complete (const String& part, String complete) 1033 void Interface::tabComplete(const String& part, String complete)
1038 { 1034 {
1039 String& input = mutable_current_input(); 1035 String& input = getEditableInput();
1040 1036
1041 if (input.starts_with (part)) 1037 if (input.starts_with(part))
1042 { 1038 {
1043 if (input[part.length()] != ' ') 1039 if (input[part.length()] != ' ')
1044 complete += ' '; 1040 complete += ' ';
1045 1041
1046 input.replace (0, part.length(), complete); 1042 input.replace(0, part.length(), complete);
1047 m_cursorPosition = complete.length(); 1043 m_cursorPosition = complete.length();
1048 m_needInputRender = true; 1044 m_needInputRender = true;
1049 } 1045 }
1050 } 1046 }
1051 1047
1052 // ------------------------------------------------------------------------------------------------- 1048 // -------------------------------------------------------------------------------------------------
1053 // 1049 //
1054 void Interface::handle_command(const String& input) 1050 void Interface::handleCommand(const String& input)
1055 { 1051 {
1056 if (input[0] != '/') 1052 if (input[0] != '/')
1057 return; 1053 return;
1058 1054
1059 StringList args = input.right(input.length() - 1).split(" "); 1055 StringList args = input.right(input.length() - 1).split(" ");
1062 1058
1063 if (command == "connect") 1059 if (command == "connect")
1064 { 1060 {
1065 if (args.size() != 2) 1061 if (args.size() != 2)
1066 { 1062 {
1067 print_error("Usage: /connect <address> <password>\n"); 1063 printError("Usage: /connect <address> <password>\n");
1068 } 1064 }
1069 else 1065 else
1070 { 1066 {
1071 IPAddress address; 1067 IPAddress address;
1072 1068
1074 { 1070 {
1075 address = IPAddress::from_string(args[0]); 1071 address = IPAddress::from_string(args[0]);
1076 } 1072 }
1077 catch (std::exception& e) 1073 catch (std::exception& e)
1078 { 1074 {
1079 print_error("%s\n", e.what()); 1075 printError("%s\n", e.what());
1080 return; 1076 return;
1081 } 1077 }
1082 1078
1083 if (address.port == 0) 1079 if (address.port == 0)
1084 address.port = 10666; 1080 address.port = 10666;
1104 m_session.request_watch(args); 1100 m_session.request_watch(args);
1105 else 1101 else
1106 print_error("No CVars to watch.\n"); 1102 print_error("No CVars to watch.\n");
1107 } 1103 }
1108 else 1104 else
1109 print_error("Unknown command: %s\n", command.chars()); 1105 printError("Unknown command: %s\n", command.chars());
1110 } 1106 }
1111 1107
1112 // ------------------------------------------------------------------------------------------------- 1108 // -------------------------------------------------------------------------------------------------
1113 // 1109 //
1114 void Interface::disconnected() 1110 void Interface::disconnected()
1115 { 1111 {
1116 print("Disconnected from %s\n", m_session.address().to_string(IPAddress::WITH_PORT).chars()); 1112 print("Disconnected from %s\n", m_session.address().to_string(IPAddress::WITH_PORT).chars());
1117 reset_title(); 1113 resetTitle();
1118 render_full(); 1114 renderFull();
1119 } 1115 }
1120 1116
1121 // ------------------------------------------------------------------------------------------------- 1117 // -------------------------------------------------------------------------------------------------
1122 // 1118 //
1123 void Interface::reset_title() 1119 void Interface::resetTitle()
1124 { 1120 {
1125 m_title.sprintf ("%s %s (%s)", application_name(), full_version_string(), changeset_date_string()); 1121 m_title.sprintf("%s %s (%s)", application_name(), full_version_string(), changeset_date_string());
1126 } 1122 }
1127 1123
1128 // ------------------------------------------------------------------------------------------------- 1124 // -------------------------------------------------------------------------------------------------
1129 // 1125 //
1130 void Interface::flush_input() 1126 void Interface::flushInput()
1131 { 1127 {
1132 m_inputHistory.insert (0, ""); 1128 m_inputHistory.insert(0, "");
1133 m_inputCursor = 0; 1129 m_inputCursor = 0;
1134 m_needInputRender = true; 1130 m_needInputRender = true;
1135 } 1131 }
1136 1132
1137 END_ZFC_NAMESPACE 1133 END_ZFC_NAMESPACE

mercurial