48 static int g_pan = 0; |
48 static int g_pan = 0; |
49 static bool g_needRefresh = false; |
49 static bool g_needRefresh = false; |
50 static bool g_needStatusBarRender = false; |
50 static bool g_needStatusBarRender = false; |
51 static bool g_needInputRender = false; |
51 static bool g_needInputRender = false; |
52 static bool g_needOutputRender = false; |
52 static bool g_needOutputRender = false; |
53 static String g_statusBarText; |
|
54 static struct { char ch; int x; } g_cursorChar; |
53 static struct { char ch; int x; } g_cursorChar; |
55 static Vector<String> g_output = {""}; |
54 static Vector<String> g_output = {""}; |
56 static int g_outputScroll = 0; |
55 static int g_outputScroll = 0; |
57 static String g_title; |
56 static String g_title; |
58 static InputState g_inputState = INPUTSTATE_NORMAL; |
57 static InputState g_inputState = INPUTSTATE_NORMAL; |
|
58 static Function<void (void)> g_disconnectConfirmFunction = nullptr; |
59 static IPAddress g_address; |
59 static IPAddress g_address; |
|
60 static String g_statusBarText; |
60 |
61 |
61 // ------------------------------------------------------------------------------------------------- |
62 // ------------------------------------------------------------------------------------------------- |
62 // |
63 // |
63 static FUNCTION |
64 static FUNCTION |
64 interface_color_pair (Color fg, Color bg) -> int |
65 interface_color_pair (Color fg, Color bg) -> int |
80 case INPUTSTATE_PASSWORD: prompt = "password:"; break; |
81 case INPUTSTATE_PASSWORD: prompt = "password:"; break; |
81 case INPUTSTATE_CONFIRM_DISCONNECTION: break; |
82 case INPUTSTATE_CONFIRM_DISCONNECTION: break; |
82 } |
83 } |
83 |
84 |
84 return prompt; |
85 return prompt; |
|
86 } |
|
87 |
|
88 // ------------------------------------------------------------------------------------------------- |
|
89 // |
|
90 static FUNCTION |
|
91 set_input_state (InputState newstate) -> void |
|
92 { |
|
93 // Clear the input row (unless going to or from confirm state) |
|
94 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION |
|
95 and g_inputState != INPUTSTATE_CONFIRM_DISCONNECTION) |
|
96 { |
|
97 g_input.clear(); |
|
98 } |
|
99 |
|
100 switch (newstate) |
|
101 { |
|
102 case INPUTSTATE_ADDRESS: |
|
103 if (g_address.host != 0) |
|
104 g_input = g_address.to_string (IP_WITH_PORT); |
|
105 break; |
|
106 |
|
107 default: |
|
108 break; |
|
109 } |
|
110 |
|
111 g_inputState = newstate; |
|
112 g_needInputRender = true; |
85 } |
113 } |
86 |
114 |
87 // ------------------------------------------------------------------------------------------------- |
115 // ------------------------------------------------------------------------------------------------- |
88 // |
116 // |
89 FUNCTION |
117 FUNCTION |
149 } |
170 } |
150 |
171 |
151 // ------------------------------------------------------------------------------------------------- |
172 // ------------------------------------------------------------------------------------------------- |
152 // |
173 // |
153 static FUNCTION |
174 static FUNCTION |
|
175 safe_disconnect (Function<void()> afterwards) -> void |
|
176 { |
|
177 if (RCONSession::get_session() != nullptr |
|
178 and RCONSession::get_session()->state() != RCON_DISCONNECTED) |
|
179 { |
|
180 g_disconnectConfirmFunction = afterwards; |
|
181 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); |
|
182 } |
|
183 else |
|
184 afterwards(); |
|
185 } |
|
186 |
|
187 // ------------------------------------------------------------------------------------------------- |
|
188 // |
|
189 static FUNCTION |
154 interface_render_output() -> void |
190 interface_render_output() -> void |
155 { |
191 { |
156 int height = LINES - 3; |
192 int height = LINES - 3; |
157 |
193 |
158 // ensure we're within bounds |
194 // ensure we're within bounds |
231 // ------------------------------------------------------------------------------------------------- |
267 // ------------------------------------------------------------------------------------------------- |
232 // |
268 // |
233 static FUNCTION |
269 static FUNCTION |
234 interface_render_statusbar() -> void |
270 interface_render_statusbar() -> void |
235 { |
271 { |
|
272 int color = interface_color_pair (WHITE, BLUE); |
236 int y = LINES - 1; |
273 int y = LINES - 1; |
|
274 attron (color); |
237 mvhline (y, 0, ' ', COLS); |
275 mvhline (y, 0, ' ', COLS); |
238 mvprintw (y, 0, "%s", g_statusBarText.chars()); |
276 mvprintw (y, 0, "%s", g_statusBarText.chars()); |
|
277 attroff (color); |
239 g_needRefresh = true; |
278 g_needRefresh = true; |
240 g_needStatusBarRender = false; |
279 g_needStatusBarRender = false; |
241 } |
280 } |
242 |
281 |
243 // ------------------------------------------------------------------------------------------------- |
282 // ------------------------------------------------------------------------------------------------- |
244 // |
283 // |
245 static FUNCTION |
284 FUNCTION |
246 set_statusbar_text (const String& a) -> void |
285 Interface::update_statusbar() -> void |
247 { |
286 { |
248 g_statusBarText = a; |
287 String text; |
249 g_needStatusBarRender = true; |
288 RCONSession* session = RCONSession::get_session(); |
|
289 |
|
290 if (session == nullptr) |
|
291 { |
|
292 text = "[DISCONNECTED]"; |
|
293 } |
|
294 else |
|
295 { |
|
296 switch (session->state()) |
|
297 { |
|
298 case RCON_DISCONNECTED: |
|
299 text = "[DISCONNECTED]"; |
|
300 break; |
|
301 |
|
302 case RCON_CONNECTING: |
|
303 case RCON_AUTHENTICATING: |
|
304 text = "Connecting to " + session->address().to_string (IP_WITH_PORT) + "..."; |
|
305 break; |
|
306 |
|
307 case RCON_CONNECTED: |
|
308 { |
|
309 String adminText; |
|
310 |
|
311 if (session->num_admins() == 0) |
|
312 adminText = "No other admins"; |
|
313 else |
|
314 adminText = format ("%1 other admin%s1", session->num_admins()); |
|
315 |
|
316 text = format ("%1 | %2 | %3", session->address().to_string (IP_WITH_PORT), |
|
317 session->level(), adminText); |
|
318 } |
|
319 break; |
|
320 } |
|
321 } |
|
322 |
|
323 if (text != g_statusBarText) |
|
324 { |
|
325 g_statusBarText = text; |
|
326 g_needStatusBarRender = true; |
|
327 } |
250 } |
328 } |
251 |
329 |
252 // ------------------------------------------------------------------------------------------------- |
330 // ------------------------------------------------------------------------------------------------- |
253 // |
331 // |
254 FUNCTION |
332 FUNCTION |
255 Interface::render_full() -> void |
333 Interface::render_full() -> void |
256 { |
334 { |
|
335 update_statusbar(); |
257 interface_render_titlebar(); |
336 interface_render_titlebar(); |
258 interface_render_output(); |
337 interface_render_output(); |
259 interface_render_statusbar(); |
338 interface_render_statusbar(); |
260 interface_render_input(); |
339 interface_render_input(); |
261 } |
340 } |
277 mvprintw (y, interface_prompt_string().length(), " "); |
356 mvprintw (y, interface_prompt_string().length(), " "); |
278 } |
357 } |
279 |
358 |
280 // ------------------------------------------------------------------------------------------------- |
359 // ------------------------------------------------------------------------------------------------- |
281 // |
360 // |
282 static FUNCTION |
|
283 set_input_state (InputState newstate) -> void |
|
284 { |
|
285 // Clear the input row (unless going to or from confirm state) |
|
286 if (newstate != INPUTSTATE_CONFIRM_DISCONNECTION |
|
287 and g_inputState != INPUTSTATE_CONFIRM_DISCONNECTION) |
|
288 { |
|
289 g_input.clear(); |
|
290 } |
|
291 |
|
292 switch (newstate) |
|
293 { |
|
294 case INPUTSTATE_ADDRESS: |
|
295 if (g_address.host != 0) |
|
296 g_input = g_address.to_string (IP_WITH_PORT); |
|
297 break; |
|
298 |
|
299 default: |
|
300 break; |
|
301 } |
|
302 |
|
303 g_inputState = newstate; |
|
304 g_needInputRender = true; |
|
305 } |
|
306 |
|
307 // ------------------------------------------------------------------------------------------------- |
|
308 // |
|
309 FUNCTION |
361 FUNCTION |
310 Interface::handle_input() -> void |
362 Interface::handle_input() -> void |
311 { |
363 { |
312 int ch = ::getch(); |
364 int ch = ::getch(); |
313 set_statusbar_text (String::from_number (ch)); |
|
314 |
365 |
315 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
366 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) |
316 { |
367 { |
317 if (ch == 'y' or ch == 'Y') |
368 if (ch == 'y' or ch == 'Y') |
318 set_input_state (INPUTSTATE_ADDRESS); |
369 g_disconnectConfirmFunction(); |
319 else if (ch == 'n' or ch == 'N') |
370 else if (ch == 'n' or ch == 'N') |
320 set_input_state (INPUTSTATE_NORMAL); |
371 set_input_state (INPUTSTATE_NORMAL); |
321 return; |
372 return; |
322 } |
373 } |
323 |
374 |
326 g_input.insert (g_cursor++, char (ch)); |
377 g_input.insert (g_cursor++, char (ch)); |
327 g_needInputRender = true; |
378 g_needInputRender = true; |
328 } |
379 } |
329 else switch (ch) |
380 else switch (ch) |
330 { |
381 { |
331 case KEY_F(1): |
382 case 'Q' - 'A' + 1: // ^Q |
332 endwin(); |
383 switch (g_inputState) |
333 exit (EXIT_SUCCESS); |
384 { |
|
385 case INPUTSTATE_CONFIRM_DISCONNECTION: |
|
386 break; |
|
387 |
|
388 case INPUTSTATE_NORMAL: |
|
389 safe_disconnect ([]() |
|
390 { |
|
391 endwin(); |
|
392 throw Exitception(); |
|
393 }); |
|
394 break; |
|
395 |
|
396 case INPUTSTATE_PASSWORD: |
|
397 set_input_state (INPUTSTATE_ADDRESS); |
|
398 break; |
|
399 |
|
400 case INPUTSTATE_ADDRESS: |
|
401 set_input_state (INPUTSTATE_NORMAL); |
|
402 } |
|
403 break; |
|
404 |
|
405 case '\e': |
|
406 if (g_inputState == INPUTSTATE_PASSWORD) |
|
407 set_input_state (INPUTSTATE_ADDRESS); |
|
408 else if (g_inputState == INPUTSTATE_ADDRESS) |
|
409 set_input_state (INPUTSTATE_NORMAL); |
334 break; |
410 break; |
335 |
411 |
336 case KEY_LEFT: |
412 case KEY_LEFT: |
337 if (g_cursor > 0) |
413 if (g_cursor > 0) |
338 { |
414 { |
436 } |
512 } |
437 break; |
513 break; |
438 |
514 |
439 case 'N' - 'A' + 1: // ^N |
515 case 'N' - 'A' + 1: // ^N |
440 if (g_inputState == INPUTSTATE_NORMAL) |
516 if (g_inputState == INPUTSTATE_NORMAL) |
441 { |
517 safe_disconnect ([]() {set_input_state (INPUTSTATE_ADDRESS);}); |
442 if (RCONSession::get_session() != nullptr |
|
443 and RCONSession::get_session()->state() != RCON_DISCONNECTED) |
|
444 { |
|
445 set_input_state (INPUTSTATE_CONFIRM_DISCONNECTION); |
|
446 } |
|
447 else |
|
448 { |
|
449 set_input_state (INPUTSTATE_ADDRESS); |
|
450 } |
|
451 } |
|
452 break; |
518 break; |
453 } |
519 } |
454 } |
520 } |
455 |
521 |
456 // ------------------------------------------------------------------------------------------------- |
522 // ------------------------------------------------------------------------------------------------- |