--- a/sources/interface.cpp Sun Dec 14 20:47:44 2014 +0200 +++ b/sources/interface.cpp Sun Dec 14 23:21:38 2014 +0200 @@ -31,9 +31,18 @@ #include <string.h> #include "interface.h" #include "network/rconsession.h" +#include "network/ipaddress.h" enum { PAGE_SIZE = 10 }; +enum InputState +{ + INPUTSTATE_NORMAL, + INPUTSTATE_ADDRESS, + INPUTSTATE_PASSWORD, + INPUTSTATE_CONFIRM_DISCONNECTION, +}; + static String g_input; static int g_cursor = 0; static int g_pan = 0; @@ -46,6 +55,8 @@ static Vector<String> g_output = {""}; static int g_outputScroll = 0; static String g_title; +static InputState g_inputState = INPUTSTATE_NORMAL; +static IPAddress g_address; // ------------------------------------------------------------------------------------------------- // @@ -57,6 +68,24 @@ // ------------------------------------------------------------------------------------------------- // +static FUNCTION +interface_prompt_string() -> String +{ + String prompt; + + switch (g_inputState) + { + case INPUTSTATE_NORMAL: prompt = ">"; break; + case INPUTSTATE_ADDRESS: prompt = "address:"; break; + case INPUTSTATE_PASSWORD: prompt = "password:"; break; + case INPUTSTATE_CONFIRM_DISCONNECTION: break; + } + + return prompt; +} + +// ------------------------------------------------------------------------------------------------- +// FUNCTION Interface::initialize() -> void { @@ -153,8 +182,19 @@ static FUNCTION interface_render_input() -> void { - static char prompt[] = ">"; - int displaylength = COLS - strlen (prompt) - 2; + int pair = interface_color_pair (WHITE, BLUE); + + if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) + { + attron (pair); + mvhline (LINES - 2, 0, ' ', COLS); + mvprintw (LINES - 2, 0, "Are you sure you want to disconnect? y/n"); + attroff (pair); + return; + } + + String prompt = interface_prompt_string(); + int displaylength = COLS - prompt.length() - 2; int y = LINES - 2; // Ensure the cursor is within bounds @@ -170,27 +210,17 @@ int end = min<int> (g_input.length(), start + displaylength); assert (g_cursor >= start and g_cursor <= end); - // Clear, but only as much as is necessary. I want to avoid clearing the entire line to save - // bandwidth over SSH connections. Perhaps needlessly? I'm paranoid. - int renderLength = strlen (prompt) + 1 + g_input.length(); - static int lastRenderLength = 0; - - if (lastRenderLength > renderLength) - mvhline (y, renderLength, ' ', lastRenderLength - renderLength); - - lastRenderLength = renderLength; - // Render the input line, with the part of the input string that's before the cursor written // AFTER the part that comes afterwards. This is to ensure that the cursor is placed at the // position where our cursor is. It looks nice like that. :) - int pair = interface_color_pair (WHITE, BLUE); + mvhline (LINES - 2, 0, ' ', COLS); + mvprintw (y, prompt.length() + 1, "%s", g_input.chars()); attron (pair); - mvprintw (y, 0, "%s", prompt); + mvprintw (y, 0, "%s", prompt.chars()); attroff (pair); - mvprintw (y, strlen (prompt) + 1, "%s", g_input.chars()); g_cursorChar.ch = g_cursor != 0 ? g_input[g_cursor - 1] : '\0'; - g_cursorChar.x = strlen (prompt) + (g_cursor - g_pan); + g_cursorChar.x = prompt.length() + (g_cursor - g_pan); g_needRefresh = true; g_needInputRender = false; } @@ -237,7 +267,7 @@ if (g_cursorChar.ch != '\0') mvprintw (y, g_cursorChar.x, "%c", g_cursorChar.ch); else - mvprintw (y, 1, " "); + mvprintw (y, interface_prompt_string().length(), " "); } // ------------------------------------------------------------------------------------------------- @@ -248,6 +278,15 @@ int ch = ::getch(); set_statusbar_text (String::from_number (ch)); + if (g_inputState == INPUTSTATE_CONFIRM_DISCONNECTION) + { + if (ch == 'y' or ch == 'Y') + g_inputState = INPUTSTATE_ADDRESS; + else if (ch == 'n' or ch == 'N') + g_inputState = INPUTSTATE_NORMAL; + return; + } + if (ch >= 0x20 and ch <= 0x7E) { g_input.insert (g_cursor++, char (ch)); @@ -320,9 +359,65 @@ case '\n': case KEY_ENTER: - if (RCONSession::get_session()->send_command (g_input)) + switch (g_inputState) { + case INPUTSTATE_CONFIRM_DISCONNECTION: + break; // handled above + + case INPUTSTATE_ADDRESS: + try + { + g_address = IPAddress::from_string (g_input); + } + catch (std::exception& e) + { + print (e.what()); + return; + } + + if (g_address.port == 0) + g_address.port = 10666; + g_input.clear(); + g_inputState = INPUTSTATE_PASSWORD; + g_needInputRender = true; + + case INPUTSTATE_PASSWORD: + if (g_inputState == INPUTSTATE_PASSWORD and not g_input.is_empty()) + { + RCONSession* session = RCONSession::new_session(); + session->set_password (g_input); + session->connect (g_address); + g_input.clear(); + g_inputState = INPUTSTATE_NORMAL; + g_needInputRender = true; + } + break; + + case INPUTSTATE_NORMAL: + if (RCONSession::get_session() != nullptr + and RCONSession::get_session()->send_command (g_input)) + { + g_input.clear(); + g_needInputRender = true; + } + break; + } + break; + + case 'N' - 'A' + 1: // ^N + if (g_inputState == INPUTSTATE_NORMAL) + { + if (RCONSession::get_session() != nullptr + and RCONSession::get_session()->state() != RCON_DISCONNECTED) + { + g_inputState = INPUTSTATE_CONFIRM_DISCONNECTION; + } + else + { + g_inputState = INPUTSTATE_ADDRESS; + } + g_needInputRender = true; } break;