sources/interface.cpp

branch
protocol5
changeset 106
7b156b764d11
parent 103
b78c0ca832a9
parent 105
b4466472aecd
child 131
4996c8684b93
--- a/sources/interface.cpp	Sat Jan 09 02:35:00 2016 +0200
+++ b/sources/interface.cpp	Sat Jan 09 17:41:21 2016 +0200
@@ -28,18 +28,20 @@
 	SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
+#include <curses.h>
 #include <string.h>
 #include <time.h>
 #include "interface.h"
 #include "network/rconsession.h"
 #include "network/ipaddress.h"
 #include "coloredline.h"
+BEGIN_ZFC_NAMESPACE
 
 static const int g_pageSize = 10;
 
 // -------------------------------------------------------------------------------------------------
 //
-int Interface::color_pair (Color fg, Color bg)
+chtype Interface::color_pair (Color fg, Color bg)
 {
 	return COLOR_PAIR (1 + (int (fg) * NUM_COLORS) + int (bg));
 }
@@ -127,7 +129,7 @@
 	{
 	case INPUTSTATE_ADDRESS:
 		if (CurrentAddress.host != 0)
-			mutable_current_input() = CurrentAddress.to_string (IP_WITH_PORT);
+			mutable_current_input() = CurrentAddress.to_string (IPAddress::WITH_PORT);
 		break;
 
 	default:
@@ -141,15 +143,20 @@
 // -------------------------------------------------------------------------------------------------
 //
 Interface::Interface() :
-	Session (this)
+	InputCursor (0),
+	CursorPosition (0),
+	InputPanning (0),
+	NeedRefresh (false),
+	NeedStatusBarRender (false),
+	NeedInputRender (false),
+	NeedOutputRender (false),
+	NeedNicklistRender (false),
+	OutputScroll (0),
+	CurrentInputState (INPUTSTATE_NORMAL),
+	DisconnectConfirmFunction (nullptr)
 {
-#ifdef XCURSES
-    ::Xinitscr(argc, argv);
-#else
-    ::initscr();
-#endif
-
-	::cbreak();
+	::initscr();
+	::raw();
 	::keypad (stdscr, true);
 	::noecho();
 	::refresh();
@@ -158,7 +165,8 @@
 	InputHistory << "";
 	OutputLines.clear();
 	OutputLines << ColoredLine();
-	Title.sprintf (APPNAME " %s (%d)", full_version_string(), changeset_date_string());
+	Session.set_interface (this);
+	Title.sprintf (APPNAME " %s (%s)", full_version_string(), changeset_date_string());
 
 	if (::has_colors())
 	{
@@ -196,7 +204,7 @@
 {
 	if (Title.length() <= COLS)
 	{
-		int pair = color_pair (WHITE, BLUE);
+		chtype pair = color_pair (WHITE, BLUE);
 		int startx = (COLS - Title.length()) / 2;
 		int endx = startx + Title.length();
 		attron (pair);
@@ -219,7 +227,7 @@
 
 // -------------------------------------------------------------------------------------------------
 //
-void Interface::safe_disconnect (Function<void()> afterwards)
+void Interface::safe_disconnect (std::function<void()> afterwards)
 {
 	if (Session.is_active())
 	{
@@ -252,8 +260,10 @@
 {
 	int x = x0;
 
-	for (int byte : line.data())
+	for (int i = 0; i < line.data().size(); ++i)
 	{
+		int byte = line.data()[i];
+
 		if (x == x0 + width)
 		{
 			if (not allowWrap)
@@ -263,35 +273,18 @@
 			++y;
 		}
 
-		if (isprint (byte))
+		if (byte < 256 && isprint (byte))
 		{
 			mvaddch (y, x, char (byte));
 			++x;
 		}
+		else if (byte >= RLINE_ON_COLOR and byte < (RLINE_ON_COLOR + 16))
+		{
+			auto attrfunction = (byte < RLINE_OFF_COLOR ? &attron : &attroff);
+			(*attrfunction) (color_pair (Color ((byte - RLINE_ON_COLOR) & 7), DEFAULT));
+		}
 		else switch (byte)
 		{
-		case RLINE_ON_BLACK:
-		case RLINE_ON_RED:
-		case RLINE_ON_GREEN:
-		case RLINE_ON_YELLOW:
-		case RLINE_ON_BLUE:
-		case RLINE_ON_MAGENTA:
-		case RLINE_ON_CYAN:
-		case RLINE_ON_WHITE:
-			attron (color_pair (Color (byte - RLINE_ON_BLACK), DEFAULT));
-			break;
-
-		case RLINE_OFF_BLACK:
-		case RLINE_OFF_RED:
-		case RLINE_OFF_GREEN:
-		case RLINE_OFF_YELLOW:
-		case RLINE_OFF_BLUE:
-		case RLINE_OFF_MAGENTA:
-		case RLINE_OFF_CYAN:
-		case RLINE_OFF_WHITE:
-			attroff (color_pair (Color (byte - RLINE_OFF_BLACK), DEFAULT));
-			break;
-
 		case RLINE_ON_BOLD:
 			attron (A_BOLD);
 			break;
@@ -421,7 +414,7 @@
 //
 void Interface::render_input()
 {
-	int promptColor = color_pair (WHITE, BLUE);
+	chtype promptColor = color_pair (WHITE, BLUE);
 
 	// If we're asking the user if they want to disconnect, we don't render any input strings,
 	// just the confirmation message.
@@ -443,8 +436,8 @@
 	// If we're inputting a password, replace it with asterisks
 	if (CurrentInputState == INPUTSTATE_PASSWORD)
 	{
-		for (char& ch : displayString)
-			ch = '*';
+		for (int i = 0; i < displayString.length(); ++i)
+			displayString[i] = '*';
 	}
 
 	// Ensure the cursor is within bounds
@@ -482,7 +475,7 @@
 //
 void Interface::render_statusbar()
 {
-	int color = color_pair (WHITE, BLUE);
+	chtype color = color_pair (WHITE, BLUE);
 	int y = LINES - 1;
 	attron (color);
 	mvhline (y, 0, ' ', COLS);
@@ -506,7 +499,7 @@
 
 	case RCON_CONNECTING:
 	case RCON_AUTHENTICATING:
-		text = "Connecting to " + Session.address().to_string (IP_WITH_PORT) + "...";
+		text = "Connecting to " + Session.address().to_string (IPAddress::WITH_PORT) + "...";
 		break;
 
 	case RCON_CONNECTED:
@@ -523,8 +516,10 @@
 					Session.num_admins() != 1 ? "s" : "");
 			}
 
-			text.sprintf ("%s | %s | %s", Session.address().to_string (IP_WITH_PORT).chars(),
-				Session.level().chars(), adminText.chars());
+			text.sprintf ("%s | %s | %s",
+				Session.address().to_string (IPAddress::WITH_PORT).chars(),
+				Session.level().chars(),
+				adminText.chars());
 		}
 		break;
 	}
@@ -794,6 +789,7 @@
 		break;
 
 	case '\n':
+	case '\r':
 	case KEY_ENTER:
 		switch (CurrentInputState)
 		{
@@ -828,7 +824,13 @@
 			break;
 
 		case INPUTSTATE_NORMAL:
-			if (Session.send_command (current_input()))
+			if (current_input()[0] == '/')
+			{
+				handle_command(current_input());
+				InputHistory.insert (0, "");
+				NeedInputRender = true;
+			}
+			else if (Session.send_command (current_input()))
 			{
 				InputHistory.insert (0, "");
 				NeedInputRender = true;
@@ -842,7 +844,7 @@
 			safe_disconnect ([&]() {set_input_state (INPUTSTATE_ADDRESS);});
 		break;
 
-	case '\e': // Escape
+	case '\x1b': // Escape
 		// We may have an alt key coming
 		ch = ::getch();
 
@@ -947,14 +949,16 @@
 
 // -------------------------------------------------------------------------------------------------
 //
-void Interface::print_to_console (String a)
+void Interface::print_to_console (String message)
 {
 	// Zandronum sometimes sends color codes as "\\c" and sometimes as "\x1C".
 	// Let's correct that on our end and hope this won't cause conflicts.
-	a.replace ("\\c", "\x1C");
+	message.replace ("\\c", "\x1C");
 
-	for (char ch : a)
+	for (int i = 0; i < message.length(); ++i)
 	{
+		char ch = message[i];
+
 		if (ch == '\n')
 		{
 			OutputLines.last().finalize();
@@ -1033,3 +1037,59 @@
 	Session.disconnect();
 	set_input_state (INPUTSTATE_NORMAL);
 }
+
+// -------------------------------------------------------------------------------------------------
+//
+void Interface::handle_command(const String& input)
+{
+	if (input[0] != '/')
+		return;
+
+	StringList args = input.right(input.length() - 1).split(" ");
+	String command = args[0].to_lowercase();
+	args.remove_at(0);
+
+	if (command == "connect")
+	{
+		if (args.size() != 2)
+			print_error("Usage: /connect <address> <password>");
+		else
+		{
+			IPAddress address;
+
+			try
+			{
+				address = IPAddress::from_string(args[0]);
+			}
+			catch (std::exception& e)
+			{
+				print_error("%s\n", e.what());
+				return;
+			}
+
+			if (address.port == 0)
+				address.port = 10666;
+
+			Session.set_password(args[1]);
+			Session.disconnect();
+			Session.connect(CurrentAddress = address);
+		}
+	}
+	else if (command == "quit")
+	{
+		Session.disconnect();
+		endwin();
+		throw Exitception();
+	}
+	else if (command == "watch")
+	{
+		if (not args.is_empty())
+			Session.request_watch(args);
+		else
+			print_error("No CVars to watch.\n");
+	}
+	else
+		print_error("Unknown command %s\n", command.chars());
+}
+
+END_ZFC_NAMESPACE

mercurial