sources/interface.cpp

changeset 24
e651d02802c0
parent 23
f7221183a994
child 25
88b41eea08e0
equal deleted inserted replaced
23:f7221183a994 24:e651d02802c0
29 */ 29 */
30 30
31 #include <string.h> 31 #include <string.h>
32 #include "interface.h" 32 #include "interface.h"
33 #include "network/rconsession.h" 33 #include "network/rconsession.h"
34 #include "network/ipaddress.h"
34 35
35 enum { PAGE_SIZE = 10 }; 36 enum { PAGE_SIZE = 10 };
37
38 enum InputState
39 {
40 INPUTSTATE_NORMAL,
41 INPUTSTATE_ADDRESS,
42 INPUTSTATE_PASSWORD,
43 INPUTSTATE_CONFIRM_DISCONNECTION,
44 };
36 45
37 static String g_input; 46 static String g_input;
38 static int g_cursor = 0; 47 static int g_cursor = 0;
39 static int g_pan = 0; 48 static int g_pan = 0;
40 static bool g_needRefresh = false; 49 static bool g_needRefresh = false;
44 static String g_statusBarText; 53 static String g_statusBarText;
45 static struct { char ch; int x; } g_cursorChar; 54 static struct { char ch; int x; } g_cursorChar;
46 static Vector<String> g_output = {""}; 55 static Vector<String> g_output = {""};
47 static int g_outputScroll = 0; 56 static int g_outputScroll = 0;
48 static String g_title; 57 static String g_title;
58 static InputState g_inputState = INPUTSTATE_NORMAL;
59 static IPAddress g_address;
49 60
50 // ------------------------------------------------------------------------------------------------- 61 // -------------------------------------------------------------------------------------------------
51 // 62 //
52 static FUNCTION 63 static FUNCTION
53 interface_color_pair (Color fg, Color bg) -> int 64 interface_color_pair (Color fg, Color bg) -> int
54 { 65 {
55 return COLOR_PAIR ((int (fg) * NUM_COLORS) + int (bg)); 66 return COLOR_PAIR ((int (fg) * NUM_COLORS) + int (bg));
67 }
68
69 // -------------------------------------------------------------------------------------------------
70 //
71 static FUNCTION
72 interface_prompt_string() -> String
73 {
74 String prompt;
75
76 switch (g_inputState)
77 {
78 case INPUTSTATE_NORMAL: prompt = ">"; break;
79 case INPUTSTATE_ADDRESS: prompt = "address:"; break;
80 case INPUTSTATE_PASSWORD: prompt = "password:"; break;
81 case INPUTSTATE_CONFIRM_DISCONNECTION: break;
82 }
83
84 return prompt;
56 } 85 }
57 86
58 // ------------------------------------------------------------------------------------------------- 87 // -------------------------------------------------------------------------------------------------
59 // 88 //
60 FUNCTION 89 FUNCTION
151 // ------------------------------------------------------------------------------------------------- 180 // -------------------------------------------------------------------------------------------------
152 // 181 //
153 static FUNCTION 182 static FUNCTION
154 interface_render_input() -> void 183 interface_render_input() -> void
155 { 184 {
156 static char prompt[] = ">"; 185 int pair = interface_color_pair (WHITE, BLUE);
157 int displaylength = COLS - strlen (prompt) - 2; 186
187 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
188 {
189 attron (pair);
190 mvhline (LINES - 2, 0, ' ', COLS);
191 mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n");
192 attroff (pair);
193 return;
194 }
195
196 String prompt = interface_prompt_string();
197 int displaylength = COLS - prompt.length() - 2;
158 int y = LINES - 2; 198 int y = LINES - 2;
159 199
160 // Ensure the cursor is within bounds 200 // Ensure the cursor is within bounds
161 g_cursor = clamp (g_cursor, 0, g_input.length()); 201 g_cursor = clamp (g_cursor, 0, g_input.length());
162 202
168 208
169 int start = g_pan; 209 int start = g_pan;
170 int end = min<int> (g_input.length(), start + displaylength); 210 int end = min<int> (g_input.length(), start + displaylength);
171 assert (g_cursor >= start and g_cursor <= end); 211 assert (g_cursor >= start and g_cursor <= end);
172 212
173 // Clear, but only as much as is necessary. I want to avoid clearing the entire line to save
174 // bandwidth over SSH connections. Perhaps needlessly? I'm paranoid.
175 int renderLength = strlen (prompt) + 1 + g_input.length();
176 static int lastRenderLength = 0;
177
178 if (lastRenderLength > renderLength)
179 mvhline (y, renderLength, ' ', lastRenderLength - renderLength);
180
181 lastRenderLength = renderLength;
182
183 // Render the input line, with the part of the input string that's before the cursor written 213 // Render the input line, with the part of the input string that's before the cursor written
184 // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the 214 // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the
185 // position where our cursor is. It looks nice like that. :) 215 // position where our cursor is. It looks nice like that. :)
186 216
187 int pair = interface_color_pair (WHITE, BLUE); 217 mvhline (LINES - 2, 0, ' ', COLS);
218 mvprintw (y, prompt.length() + 1, "%s", g_input.chars());
188 attron (pair); 219 attron (pair);
189 mvprintw (y, 0, "%s", prompt); 220 mvprintw (y, 0, "%s", prompt.chars());
190 attroff (pair); 221 attroff (pair);
191 mvprintw (y, strlen (prompt) + 1, "%s", g_input.chars());
192 g_cursorChar.ch = g_cursor != 0 ? g_input[g_cursor - 1] : '\0'; 222 g_cursorChar.ch = g_cursor != 0 ? g_input[g_cursor - 1] : '\0';
193 g_cursorChar.x = strlen (prompt) + (g_cursor - g_pan); 223 g_cursorChar.x = prompt.length() + (g_cursor - g_pan);
194 g_needRefresh = true; 224 g_needRefresh = true;
195 g_needInputRender = false; 225 g_needInputRender = false;
196 } 226 }
197 227
198 // ------------------------------------------------------------------------------------------------- 228 // -------------------------------------------------------------------------------------------------
235 int y = LINES - 2; 265 int y = LINES - 2;
236 266
237 if (g_cursorChar.ch != '\0') 267 if (g_cursorChar.ch != '\0')
238 mvprintw (y, g_cursorChar.x, "%c", g_cursorChar.ch); 268 mvprintw (y, g_cursorChar.x, "%c", g_cursorChar.ch);
239 else 269 else
240 mvprintw (y, 1, " "); 270 mvprintw (y, interface_prompt_string().length(), " ");
241 } 271 }
242 272
243 // ------------------------------------------------------------------------------------------------- 273 // -------------------------------------------------------------------------------------------------
244 // 274 //
245 FUNCTION 275 FUNCTION
246 Interface::handle_input() -> void 276 Interface::handle_input() -> void
247 { 277 {
248 int ch = ::getch(); 278 int ch = ::getch();
249 set_statusbar_text (String::from_number (ch)); 279 set_statusbar_text (String::from_number (ch));
280
281 if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION)
282 {
283 if (ch == 'y' or ch == 'Y')
284 g_inputState = INPUTSTATE_ADDRESS;
285 else if (ch == 'n' or ch == 'N')
286 g_inputState = INPUTSTATE_NORMAL;
287 return;
288 }
250 289
251 if (ch >= 0x20 and ch <= 0x7E) 290 if (ch >= 0x20 and ch <= 0x7E)
252 { 291 {
253 g_input.insert (g_cursor++, char (ch)); 292 g_input.insert (g_cursor++, char (ch));
254 g_needInputRender = true; 293 g_needInputRender = true;
318 g_needOutputRender = true; 357 g_needOutputRender = true;
319 break; 358 break;
320 359
321 case '\n': 360 case '\n':
322 case KEY_ENTER: 361 case KEY_ENTER:
323 if (RCONSession::get_session()->send_command (g_input)) 362 switch (g_inputState)
324 { 363 {
364 case INPUTSTATE_CONFIRM_DISCONNECTION:
365 break; // handled above
366
367 case INPUTSTATE_ADDRESS:
368 try
369 {
370 g_address = IPAddress::from_string (g_input);
371 }
372 catch (std::exception& e)
373 {
374 print (e.what());
375 return;
376 }
377
378 if (g_address.port == 0)
379 g_address.port = 10666;
380
325 g_input.clear(); 381 g_input.clear();
382 g_inputState = INPUTSTATE_PASSWORD;
383 g_needInputRender = true;
384
385 case INPUTSTATE_PASSWORD:
386 if (g_inputState == INPUTSTATE_PASSWORD and not g_input.is_empty())
387 {
388 RCONSession* session = RCONSession::new_session();
389 session->set_password (g_input);
390 session->connect (g_address);
391 g_input.clear();
392 g_inputState = INPUTSTATE_NORMAL;
393 g_needInputRender = true;
394 }
395 break;
396
397 case INPUTSTATE_NORMAL:
398 if (RCONSession::get_session() != nullptr
399 and RCONSession::get_session()->send_command (g_input))
400 {
401 g_input.clear();
402 g_needInputRender = true;
403 }
404 break;
405 }
406 break;
407
408 case 'N' - 'A' + 1: // ^N
409 if (g_inputState == INPUTSTATE_NORMAL)
410 {
411 if (RCONSession::get_session() != nullptr
412 and RCONSession::get_session()->state() != RCON_DISCONNECTED)
413 {
414 g_inputState = INPUTSTATE_CONFIRM_DISCONNECTION;
415 }
416 else
417 {
418 g_inputState = INPUTSTATE_ADDRESS;
419 }
420
326 g_needInputRender = true; 421 g_needInputRender = true;
327 } 422 }
328 break; 423 break;
329 } 424 }
330 } 425 }

mercurial