about summary refs log tree commit diff
path: root/ui.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2018-08-10 23:31:20 -0400
committerJune McEnroe <june@causal.agency>2018-08-10 23:31:20 -0400
commit07c750d25cf26883507d46bf319e55d2e35d6a94 (patch)
treedcf7dbc50dd717a1190c2f034ff440badf5a525c /ui.c
parentMove process spawning onto the event loop (diff)
downloadcatgirl-07c750d25cf26883507d46bf319e55d2e35d6a94.tar.gz
catgirl-07c750d25cf26883507d46bf319e55d2e35d6a94.zip
Become multi-channel
There's a lot of UI missing for it, but it technically works.
Diffstat (limited to 'ui.c')
-rw-r--r--ui.c225
1 files changed, 149 insertions, 76 deletions
diff --git a/ui.c b/ui.c
index 9778473..844e777 100644
--- a/ui.c
+++ b/ui.c
@@ -95,13 +95,19 @@ static int logHeight(void) {
 	return LINES - 4;
 }
 
-static struct {
+struct View {
 	WINDOW *topic;
 	WINDOW *log;
-	WINDOW *input;
-	bool hide;
-	bool mark;
 	int scroll;
+	bool mark;
+};
+
+static struct {
+	bool hide;
+	WINDOW *input;
+	struct Tag tag;
+	struct View views[TAGS_LEN];
+	size_t len;
 } ui;
 
 void uiInit(void) {
@@ -113,14 +119,7 @@ void uiInit(void) {
 	focusEnable();
 	colorInit();
 
-	ui.topic = newpad(2, TOPIC_COLS);
-	mvwhline(ui.topic, 1, 0, ACS_HLINE, TOPIC_COLS);
-
-	ui.log = newpad(LOG_LINES, COLS);
-	wsetscrreg(ui.log, 0, LOG_LINES - 1);
-	scrollok(ui.log, true);
-	wmove(ui.log, LOG_LINES - logHeight() - 1, 0);
-	ui.scroll = LOG_LINES;
+	ui.tag = TAG_DEFAULT;
 
 	ui.input = newpad(2, INPUT_COLS);
 	mvwhline(ui.input, 0, 0, ACS_HLINE, INPUT_COLS);
@@ -130,11 +129,6 @@ void uiInit(void) {
 	nodelay(ui.input, true);
 }
 
-static void uiResize(void) {
-	wresize(ui.log, LOG_LINES, COLS);
-	wmove(ui.log, LOG_LINES - 1, COLS - 1);
-}
-
 void uiHide(void) {
 	ui.hide = true;
 	endwin();
@@ -149,17 +143,46 @@ void uiExit(void) {
 	);
 }
 
+static struct View *uiView(struct Tag tag) {
+	struct View *view = &ui.views[tag.id];
+	if (view->log) return view;
+
+	view->topic = newpad(2, TOPIC_COLS);
+	mvwhline(view->topic, 1, 0, ACS_HLINE, TOPIC_COLS);
+
+	view->log = newpad(LOG_LINES, COLS);
+	wsetscrreg(view->log, 0, LOG_LINES - 1);
+	scrollok(view->log, true);
+	wmove(view->log, LOG_LINES - logHeight() - 1, 0);
+
+	view->scroll = LOG_LINES;
+	view->mark = false;
+
+	if (tag.id >= ui.len) ui.len = tag.id + 1;
+	return view;
+}
+
+static void uiResize(void) {
+	for (size_t i = 0; i < ui.len; ++i) {
+		struct View *view = &ui.views[i];
+		if (!view->log) continue;
+		wresize(view->log, LOG_LINES, COLS);
+		wmove(view->log, LOG_LINES - 1, COLS - 1);
+	}
+}
+
 void uiDraw(void) {
 	if (ui.hide) return;
+	struct View *view = uiView(ui.tag);
 	pnoutrefresh(
-		ui.topic,
+		view->topic,
 		0, 0,
 		0, 0,
 		1, lastCol()
 	);
 	pnoutrefresh(
-		ui.log,
-		ui.scroll - logHeight(), 0,
+		view->log,
+		view->scroll - logHeight(), 0,
 		2, 0,
 		lastLine() - 2, lastCol()
 	);
@@ -178,6 +201,16 @@ static void uiRedraw(void) {
 	clearok(curscr, true);
 }
 
+void uiFocus(struct Tag tag) {
+	struct View *view = uiView(ui.tag);
+	view->mark = true;
+	view = uiView(tag);
+	view->mark = false;
+	touchwin(view->topic);
+	touchwin(view->log);
+	ui.tag = tag;
+}
+
 void uiBeep(void) {
 	beep(); // always be beeping
 }
@@ -276,93 +309,133 @@ static void addIRC(WINDOW *win, const wchar_t *str) {
 	}
 }
 
-void uiTopic(const wchar_t *topic) {
-	wmove(ui.topic, 0, 0);
-	addIRC(ui.topic, topic);
-	wclrtoeol(ui.topic);
-}
-
-void uiTopicStr(const char *topic) {
+void uiTopic(struct Tag tag, const char *topic) {
 	wchar_t *wcs = ambstowcs(topic);
 	if (!wcs) err(EX_DATAERR, "ambstowcs");
-	uiTopic(wcs);
+	struct View *view = uiView(tag);
+	wmove(view->topic, 0, 0);
+	addIRC(view->topic, wcs);
+	wclrtoeol(view->topic);
 	free(wcs);
 }
 
-void uiLog(const wchar_t *line) {
-	waddch(ui.log, '\n');
-	if (ui.mark) {
-		waddch(ui.log, '\n');
-		ui.mark = false;
+void uiLog(struct Tag tag, const wchar_t *line) {
+	struct View *view = uiView(tag);
+	waddch(view->log, '\n');
+	if (view->mark) {
+		waddch(view->log, '\n');
+		view->mark = false;
 	}
-	addIRC(ui.log, line);
+	addIRC(view->log, line);
 }
 
-void uiFmt(const wchar_t *format, ...) {
+void uiFmt(struct Tag tag, const wchar_t *format, ...) {
 	wchar_t *buf;
 	va_list ap;
 	va_start(ap, format);
 	vaswprintf(&buf, format, ap);
 	va_end(ap);
 	if (!buf) err(EX_OSERR, "vaswprintf");
-	uiLog(buf);
+	uiLog(tag, buf);
 	free(buf);
 }
 
 static void logUp(void) {
-	if (ui.scroll == logHeight()) return;
-	if (ui.scroll == LOG_LINES) ui.mark = true;
-	ui.scroll = MAX(ui.scroll - logHeight() / 2, logHeight());
+	struct View *view = uiView(ui.tag);
+	if (view->scroll == logHeight()) return;
+	if (view->scroll == LOG_LINES) view->mark = true;
+	view->scroll = MAX(view->scroll - logHeight() / 2, logHeight());
 }
 static void logDown(void) {
-	if (ui.scroll == LOG_LINES) return;
-	ui.scroll = MIN(ui.scroll + logHeight() / 2, LOG_LINES);
-	if (ui.scroll == LOG_LINES) ui.mark = false;
+	struct View *view = uiView(ui.tag);
+	if (view->scroll == LOG_LINES) return;
+	view->scroll = MIN(view->scroll + logHeight() / 2, LOG_LINES);
+	if (view->scroll == LOG_LINES) view->mark = false;
 }
 
-static bool keyChar(wint_t ch) {
+static bool keyChar(wchar_t ch) {
 	static bool esc, csi;
-	bool update = false;
+	if (ch == L'\33') {
+		esc = true;
+		return false;
+	}
+	if (esc && ch == L'[') {
+		esc = false;
+		csi = true;
+		return false;
+	}
+	if (csi) {
+		if (ch == L'O') uiView(ui.tag)->mark = true;
+		if (ch == L'I') uiView(ui.tag)->mark = false;
+		csi = false;
+		return false;
+	}
+	if (ch == L'\177') ch = L'\b';
+
+	bool update = true;
+	if (esc) {
+		switch (ch) {
+			break; case L'b':  edit(ui.tag, EDIT_BACK_WORD, 0);
+			break; case L'f':  edit(ui.tag, EDIT_FORE_WORD, 0);
+			break; case L'\b': edit(ui.tag, EDIT_KILL_BACK_WORD, 0);
+			break; case L'd':  edit(ui.tag, EDIT_KILL_FORE_WORD, 0);
+			break; default: {
+				update = false;
+				if (ch >= L'0' && ch <= L'9') {
+					struct Tag tag = tagNum(ch - L'0');
+					if (tag.name) uiFocus(tag);
+				}
+			}
+		}
+		esc = false;
+		return update;
+	}
+
 	switch (ch) {
-		break; case CTRL('L'): uiRedraw();
-		break; case CTRL('['): esc = true; return false;
-		break; case L'\b':     update = edit(esc, false, L'\b');
-		break; case L'\177':   update = edit(esc, false, L'\b');
-		break; case L'\t':     update = edit(esc, false, L'\t');
-		break; case L'\n':     update = edit(esc, false, L'\n');
+		break; case CTRL(L'L'): uiRedraw(); return false;
+
+		break; case CTRL(L'A'): edit(ui.tag, EDIT_HOME, 0);
+		break; case CTRL(L'B'): edit(ui.tag, EDIT_LEFT, 0);
+		break; case CTRL(L'D'): edit(ui.tag, EDIT_DELETE, 0);
+		break; case CTRL(L'E'): edit(ui.tag, EDIT_END, 0);
+		break; case CTRL(L'F'): edit(ui.tag, EDIT_RIGHT, 0);
+		break; case CTRL(L'K'): edit(ui.tag, EDIT_KILL_LINE, 0);
+		break; case CTRL(L'W'): edit(ui.tag, EDIT_KILL_BACK_WORD, 0);
+
+		break; case CTRL(L'C'): edit(ui.tag, EDIT_INSERT, IRC_COLOR);
+		break; case CTRL(L'N'): edit(ui.tag, EDIT_INSERT, IRC_RESET);
+		break; case CTRL(L'O'): edit(ui.tag, EDIT_INSERT, IRC_BOLD);
+		break; case CTRL(L'R'): edit(ui.tag, EDIT_INSERT, IRC_COLOR);
+		break; case CTRL(L'T'): edit(ui.tag, EDIT_INSERT, IRC_ITALIC);
+		break; case CTRL(L'U'): edit(ui.tag, EDIT_INSERT, IRC_UNDERLINE);
+		break; case CTRL(L'V'): edit(ui.tag, EDIT_INSERT, IRC_REVERSE);
+
+		break; case L'\b': edit(ui.tag, EDIT_BACKSPACE, 0);
+		break; case L'\t': edit(ui.tag, EDIT_COMPLETE, 0);
+		break; case L'\n': edit(ui.tag, EDIT_ENTER, 0);
+
 		break; default: {
-			if (esc && ch == L'[') {
-				csi = true;
-				return false;
-			} else if (csi) {
-				if (ch == L'O') ui.mark = true;
-				if (ch == L'I') ui.mark = false;
-			} else if (iswcntrl(ch)) {
-				update = edit(esc, true, UNCTRL(ch));
-			} else {
-				update = edit(esc, false, ch);
-			}
+			if (!iswprint(ch)) return false;
+			edit(ui.tag, EDIT_INSERT, ch);
 		}
 	}
-	esc = false;
-	csi = false;
-	return update;
+	return true;
 }
 
-static bool keyCode(wint_t ch) {
+static bool keyCode(wchar_t ch) {
 	switch (ch) {
-		break; case KEY_RESIZE:    uiResize();
-		break; case KEY_PPAGE:     logUp();
-		break; case KEY_NPAGE:     logDown();
-		break; case KEY_LEFT:      return edit(false, true, 'B');
-		break; case KEY_RIGHT:     return edit(false, true, 'F');
-		break; case KEY_HOME:      return edit(false, true, 'A');
-		break; case KEY_END:       return edit(false, true, 'E');
-		break; case KEY_DC:        return edit(false, true, 'D');
-		break; case KEY_BACKSPACE: return edit(false, false, '\b');
-		break; case KEY_ENTER:     return edit(false, false, '\n');
+		break; case KEY_RESIZE:    uiResize(); return false;
+		break; case KEY_PPAGE:     logUp(); return false;
+		break; case KEY_NPAGE:     logDown(); return false;
+		break; case KEY_LEFT:      edit(ui.tag, EDIT_LEFT, ch);
+		break; case KEY_RIGHT:     edit(ui.tag, EDIT_RIGHT, ch);
+		break; case KEY_HOME:      edit(ui.tag, EDIT_HOME, ch);
+		break; case KEY_END:       edit(ui.tag, EDIT_END, ch);
+		break; case KEY_DC:        edit(ui.tag, EDIT_DELETE, ch);
+		break; case KEY_BACKSPACE: edit(ui.tag, EDIT_BACKSPACE, ch);
+		break; case KEY_ENTER:     edit(ui.tag, EDIT_ENTER, ch);
 	}
-	return false;
+	return true;
 }
 
 void uiRead(void) {