sources/interface.cpp

changeset 24
e651d02802c0
parent 23
f7221183a994
child 25
88b41eea08e0
--- 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;

mercurial