summary refs log tree commit diff
diff options
context:
space:
mode:
authorCurtis McEnroe2018-09-13 01:03:47 -0400
committerCurtis McEnroe2018-09-13 01:03:47 -0400
commit4c4d91b4499d3a4bdc3850c4ad8a1713ce3a8e65 (patch)
tree6580bc689c9d23dd3676406fa636641456713ffc
parentcd41c2a1ce9178785b1cca126a1cf1f54b6c0274 (diff)
Rewrite UI again
The persistent topic is gone and the status line is now at the top. The
status formatting still needs to be reworked. I also want to try showing
the nick in the input window so it really looks like your next message.
-rw-r--r--chat.h1
-rw-r--r--handle.c2
-rw-r--r--ui.c394
3 files changed, 173 insertions, 224 deletions
diff --git a/chat.h b/chat.h
index 6295ce6..f9ffff3 100644
--- a/chat.h
+++ b/chat.h
@@ -119,7 +119,6 @@ enum UIHeat {
 	UIWarm,
 	UIHot,
 };
-void uiTopic(struct Tag tag, const char *topic);
 void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line);
 void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...);
 
diff --git a/handle.c b/handle.c
index 98b1e50..a34c864 100644
--- a/handle.c
+++ b/handle.c
@@ -260,7 +260,6 @@ static void handleReplyTopic(char *prefix, char *params) {
 	struct Tag tag = tagFor(chan);
 
 	urlScan(tag, topic);
-	uiTopic(tag, topic);
 	uiFmt(
 		tag, UICold,
 		"The sign in \3%d%s\3 reads, \"%s\"",
@@ -277,7 +276,6 @@ static void handleTopic(char *prefix, char *params) {
 	if (!isSelf(nick, user)) tabTouch(tag, nick);
 
 	urlScan(tag, topic);
-	uiTopic(tag, topic);
 	uiFmt(
 		tag, UICold,
 		"\3%d%s\3 places a new sign in \3%d%s\3, \"%s\"",
diff --git a/ui.c b/ui.c
index 72fed6a..c9210c6 100644
--- a/ui.c
+++ b/ui.c
@@ -34,8 +34,6 @@
 #include "chat.h"
 #undef uiFmt
 
-#define CTRL(c)   ((c) ^ 0100)
-
 static void colorInit(void) {
 	start_color();
 	use_default_colors();
@@ -69,101 +67,18 @@ static short pair8(short pair) {
 
 struct View {
 	struct Tag tag;
-	WINDOW *topic;
 	WINDOW *log;
-	int scroll;
-	int unread;
-	bool hot;
-	bool mark;
+	int scroll, unread;
+	bool hot, mark;
 	struct View *prev;
 	struct View *next;
 };
 
 static struct {
-	struct View *head;
-	struct View *tail;
-	struct View *tags[TagsLen];
-} views;
-
-static void viewAppend(struct View *view) {
-	if (views.tail) views.tail->next = view;
-	view->prev = views.tail;
-	view->next = NULL;
-	if (!views.head) views.head = view;
-	views.tail = view;
-	views.tags[view->tag.id] = view;
-}
-
-static void viewRemove(struct View *view) {
-	if (view->prev) view->prev->next = view->next;
-	if (view->next) view->next->prev = view->prev;
-	if (views.head == view) views.head = view->next;
-	if (views.tail == view) views.tail = view->prev;
-	views.tags[view->tag.id] = NULL;
-}
-
-static const int LogLines = 256;
-
-static int logHeight(const struct View *view) {
-	return LINES - (view->topic ? 2 : 0) - 2;
-}
-static int lastLogLine(void) {
-	return LogLines - 1;
-}
-static int lastLine(void) {
-	return LINES - 1;
-}
-static int lastCol(void) {
-	return COLS - 1;
-}
-
-static struct View *viewTag(struct Tag tag) {
-	struct View *view = views.tags[tag.id];
-	if (view) return view;
-
-	view = calloc(1, sizeof(*view));
-	if (!view) err(EX_OSERR, "calloc");
-
-	view->tag = tag;
-	view->log = newpad(LogLines, COLS);
-	wsetscrreg(view->log, 0, lastLogLine());
-	scrollok(view->log, true);
-	wmove(view->log, lastLogLine(), 0);
-	view->scroll = LogLines;
-	view->mark = true;
-
-	viewAppend(view);
-	return view;
-}
-
-static void viewResize(void) {
-	for (struct View *view = views.head; view; view = view->next) {
-		wresize(view->log, LogLines, COLS);
-		wmove(view->log, lastLogLine(), lastCol());
-	}
-}
-
-static void viewClose(struct View *view) {
-	viewRemove(view);
-	if (view->topic) delwin(view->topic);
-	delwin(view->log);
-	free(view);
-}
-
-static void viewMark(struct View *view) {
-	view->mark = true;
-}
-static void viewUnmark(struct View *view) {
-	view->unread = 0;
-	view->hot = false;
-	view->mark = false;
-}
-
-static struct {
 	bool hide;
-	struct View *view;
 	WINDOW *status;
 	WINDOW *input;
+	struct View *view;
 } ui;
 
 static void uiShow(void) {
@@ -177,31 +92,60 @@ void uiHide(void) {
 	endwin();
 }
 
-void uiDraw(void) {
-	if (ui.hide) return;
+static const int ColsMax = 512;
 
-	if (ui.view->topic) {
-		pnoutrefresh(
-			ui.view->topic,
-			0, 0,
-			0, 0,
-			1, lastCol()
-		);
-	}
+void uiInit(void) {
+	setlocale(LC_CTYPE, "");
+	initscr();
+	cbreak();
+	noecho();
 
-	pnoutrefresh(
-		ui.view->log,
-		ui.view->scroll - logHeight(ui.view), 0,
-		(ui.view->topic ? 2 : 0), 0,
-		lastLine() - 2, lastCol()
+	colorInit();
+	termInit();
+
+	ui.status = newpad(1, ColsMax);
+	ui.input = newpad(1, ColsMax);
+	keypad(ui.input, true);
+	nodelay(ui.input, true);
+
+	uiViewTag(TagStatus);
+	uiShow();
+}
+
+void uiExit(void) {
+	uiHide();
+	printf(
+		"This program is AGPLv3 Free Software!\n"
+		"The source is available at <" SOURCE_URL ">.\n"
 	);
+}
+
+static int lastLine(void) {
+	return LINES - 1;
+}
+static int lastCol(void) {
+	return COLS - 1;
+}
+static int logHeight(void) {
+	return LINES - 2;
+}
+
+void uiDraw(void) {
+	if (ui.hide) return;
 
 	int _, x;
 	getyx(ui.status, _, x);
 	pnoutrefresh(
 		ui.status,
 		0, MAX(0, x - lastCol() - 1),
-		lastLine() - 1, 0,
+		0, 0,
+		0, lastCol()
+	);
+
+	pnoutrefresh(
+		ui.view->log,
+		ui.view->scroll - logHeight(), 0,
+		1, 0,
 		lastLine() - 1, lastCol()
 	);
 
@@ -216,10 +160,6 @@ void uiDraw(void) {
 	doupdate();
 }
 
-static void uiRedraw(void) {
-	clearok(curscr, true);
-}
-
 static const short IRCColors[] = {
 	[IRCWhite]      = 8 + COLOR_WHITE,
 	[IRCBlack]      = 0 + COLOR_BLACK,
@@ -257,6 +197,7 @@ static void addFormat(WINDOW *win, const struct Format *format) {
 static int addWrap(WINDOW *win, const wchar_t *str) {
 	struct Format format = { .str = str };
 	formatReset(&format);
+
 	int lines = 0;
 	while (formatParse(&format, NULL)) {
 		int _, x, xMax;
@@ -275,6 +216,12 @@ static int addWrap(WINDOW *win, const wchar_t *str) {
 	return lines;
 }
 
+static struct {
+	struct View *head;
+	struct View *tail;
+	struct View *tags[TagsLen];
+} views;
+
 static void uiStatus(void) {
 	mvwhline(ui.status, 0, 0, ACS_HLINE, COLS);
 	mvwaddch(ui.status, 0, COLS, ACS_RTEE);
@@ -305,37 +252,78 @@ static void uiStatus(void) {
 	waddch(ui.status, ACS_HLINE);
 }
 
+static void viewAppend(struct View *view) {
+	if (views.tail) views.tail->next = view;
+	view->prev = views.tail;
+	view->next = NULL;
+	views.tail = view;
+	if (!views.head) views.head = view;
+	views.tags[view->tag.id] = view;
+}
+
+static void viewRemove(struct View *view) {
+	if (view->prev) view->prev->next = view->next;
+	if (view->next) view->next->prev = view->prev;
+	if (views.head == view) views.head = view->next;
+	if (views.tail == view) views.tail = view->prev;
+	views.tags[view->tag.id] = NULL;
+}
+
+static const int LogLines = 256;
+
+static struct View *viewTag(struct Tag tag) {
+	struct View *view = views.tags[tag.id];
+	if (view) return view;
+
+	view = calloc(1, sizeof(*view));
+	if (!view) err(EX_OSERR, "calloc");
+
+	view->tag = tag;
+
+	view->log = newpad(LogLines, COLS);
+	wsetscrreg(view->log, 0, LogLines - 1);
+	scrollok(view->log, true);
+	wmove(view->log, LogLines - 1, 0);
+
+	view->scroll = LogLines;
+	view->mark = true;
+
+	viewAppend(view);
+	return view;
+}
+
+static void viewClose(struct View *view) {
+	viewRemove(view);
+	delwin(view->log);
+	free(view);
+}
+
+static void uiResize(void) {
+	for (struct View *view = views.head; view; view = view->next) {
+		wresize(view->log, LogLines, COLS);
+		wmove(view->log, LogLines - 1, lastCol());
+	}
+}
+
+static void viewUnmark(struct View *view) {
+	view->mark = false;
+	view->unread = 0;
+	view->hot = false;
+	uiStatus();
+}
+
 static void uiView(struct View *view) {
 	termTitle(view->tag.name);
-	if (view->topic) touchwin(view->topic);
 	touchwin(view->log);
-	viewMark(ui.view);
+	if (ui.view) ui.view->mark = true;
 	viewUnmark(view);
 	ui.view = view;
-	uiStatus();
-}
-
-static void uiClose(struct View *view) {
-	if (ui.view == view) {
-		if (view->next) {
-			uiView(view->next);
-		} else if (view->prev) {
-			uiView(view->prev);
-		} else {
-			return;
-		}
-	}
-	viewClose(view);
 }
 
 void uiViewTag(struct Tag tag) {
 	uiView(viewTag(tag));
 }
 
-void uiCloseTag(struct Tag tag) {
-	uiClose(viewTag(tag));
-}
-
 void uiViewNum(int num) {
 	if (num < 0) {
 		for (struct View *view = views.tail; view; view = view->prev) {
@@ -352,26 +340,25 @@ void uiViewNum(int num) {
 	}
 }
 
-static const int ColsMax = 512;
-
-void uiTopic(struct Tag tag, const char *topic) {
+void uiCloseTag(struct Tag tag) {
 	struct View *view = viewTag(tag);
-	if (!view->topic) {
-		view->topic = newpad(2, ColsMax);
-		mvwhline(view->topic, 1, 0, ACS_HLINE, ColsMax);
+	if (ui.view == view) {
+		if (view->next) {
+			uiView(view->next);
+		} else if (view->prev) {
+			uiView(view->prev);
+		} else {
+			return;
+		}
 	}
-	wchar_t *wcs = ambstowcs(topic);
-	if (!wcs) err(EX_DATAERR, "ambstowcs");
-	wmove(view->topic, 0, 0);
-	addWrap(view->topic, wcs);
-	wclrtoeol(view->topic);
-	free(wcs);
+	viewClose(view);
 }
 
 void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
 	struct View *view = viewTag(tag);
 	int lines = 1;
 	waddch(view->log, '\n');
+
 	if (view->mark && heat > UICold) {
 		if (!view->unread++) {
 			lines++;
@@ -379,83 +366,67 @@ void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
 		}
 		if (heat > UIWarm) {
 			view->hot = true;
-			beep(); // TODO: Notification.
+			beep(); // TODO: Notify.
 		}
 		uiStatus();
 	}
+
 	lines += addWrap(view->log, line);
 	if (view->scroll != LogLines) view->scroll -= lines;
 }
 
 void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...) {
-	wchar_t *wcs;
+	wchar_t *str;
 	va_list ap;
 	va_start(ap, format);
-	vaswprintf(&wcs, format, ap);
+	vaswprintf(&str, format, ap);
 	va_end(ap);
-	if (!wcs) err(EX_OSERR, "vaswprintf");
-	uiLog(tag, heat, wcs);
-	free(wcs);
+	if (!str) err(EX_OSERR, "vaswprintf");
+	uiLog(tag, heat, str);
+	free(str);
 }
 
-void uiInit(void) {
-	setlocale(LC_CTYPE, "");
-	initscr();
-	cbreak();
-	noecho();
-
-	colorInit();
-	termInit();
-
-	ui.status = newpad(1, ColsMax);
-	ui.input = newpad(1, ColsMax);
-	keypad(ui.input, true);
-	nodelay(ui.input, true);
-
-	ui.view = viewTag(TagStatus);
-	uiViewTag(TagStatus);
-	uiStatus();
-	uiShow();
+static void scrollUp(int lines) {
+	if (ui.view->scroll == logHeight()) return;
+	if (ui.view->scroll == LogLines) ui.view->mark = true;
+	ui.view->scroll = MAX(ui.view->scroll - lines, logHeight());
 }
-
-void uiExit(void) {
-	uiHide();
-	printf(
-		"This program is AGPLv3 free software!\n"
-		"The source is available at <" SOURCE_URL ">.\n"
-	);
-}
-
-static void logScrollUp(int lines) {
-	int height = logHeight(ui.view);
-	if (ui.view->scroll == height) return;
-	if (ui.view->scroll == LogLines) viewMark(ui.view);
-	ui.view->scroll = MAX(ui.view->scroll - lines, height);
-}
-static void logScrollDown(int lines) {
+static void scrollDown(int lines) {
 	if (ui.view->scroll == LogLines) return;
 	ui.view->scroll = MIN(ui.view->scroll + lines, LogLines);
 	if (ui.view->scroll == LogLines) viewUnmark(ui.view);
 }
-static void logPageUp(void) {
-	logScrollUp(logHeight(ui.view) / 2);
-}
-static void logPageDown(void) {
-	logScrollDown(logHeight(ui.view) / 2);
+
+static bool keyCode(wchar_t ch) {
+	switch (ch) {
+		break; case KEY_RESIZE:    uiResize(); return false;
+		break; case KEY_SLEFT:     scrollUp(1); return false;
+		break; case KEY_SRIGHT:    scrollDown(1); return false;
+		break; case KEY_PPAGE:     scrollUp(logHeight() / 2); return false;
+		break; case KEY_NPAGE:     scrollDown(logHeight() / 2); return false;
+		break; case KEY_LEFT:      edit(ui.view->tag, EditLeft, 0);
+		break; case KEY_RIGHT:     edit(ui.view->tag, EditRight, 0);
+		break; case KEY_HOME:      edit(ui.view->tag, EditHome, 0);
+		break; case KEY_END:       edit(ui.view->tag, EditEnd, 0);
+		break; case KEY_DC:        edit(ui.view->tag, EditDelete, 0);
+		break; case KEY_BACKSPACE: edit(ui.view->tag, EditBackspace, 0);
+		break; case KEY_ENTER:     edit(ui.view->tag, EditEnter, 0);
+		break; default:            return false;
+	}
+	return true;
 }
 
+#define CTRL(ch) ((ch) ^ 0100)
+
 static bool keyChar(wchar_t ch) {
 	if (ch < 0200) {
 		enum TermEvent event = termEvent((char)ch);
 		switch (event) {
 			break; case TermFocusIn:  viewUnmark(ui.view);
-			break; case TermFocusOut: viewMark(ui.view);
+			break; case TermFocusOut: ui.view->mark = true;
 			break; default: {}
 		}
-		if (event) {
-			uiStatus();
-			return false;
-		}
+		if (event) return false;
 	}
 
 	static bool meta;
@@ -464,26 +435,25 @@ static bool keyChar(wchar_t ch) {
 		return false;
 	}
 
+	if (ch == L'\177') ch = L'\b';
+
 	if (meta) {
-		bool update = true;
+		meta = false;
 		switch (ch) {
 			break; case L'b':  edit(ui.view->tag, EditBackWord, 0);
 			break; case L'f':  edit(ui.view->tag, EditForeWord, 0);
 			break; case L'\b': edit(ui.view->tag, EditKillBackWord, 0);
 			break; case L'd':  edit(ui.view->tag, EditKillForeWord, 0);
 			break; default: {
-				update = false;
-				if (ch < L'0' || ch > L'9') break;
-				uiViewNum(ch - L'0');
+				if (ch >= L'0' && ch <= L'9') uiViewNum(ch - L'0');
+				return false;
 			}
 		}
-		meta = false;
-		return update;
+		return true;
 	}
 
-	if (ch == L'\177') ch = L'\b';
 	switch (ch) {
-		break; case CTRL(L'L'): uiRedraw(); return false;
+		break; case CTRL(L'L'): clearok(curscr, true); return false;
 
 		break; case CTRL(L'A'): edit(ui.view->tag, EditHome, 0);
 		break; case CTRL(L'B'): edit(ui.view->tag, EditLeft, 0);
@@ -513,24 +483,6 @@ static bool keyChar(wchar_t ch) {
 	return true;
 }
 
-static bool keyCode(wchar_t ch) {
-	switch (ch) {
-		break; case KEY_RESIZE:    viewResize(); return false;
-		break; case KEY_SLEFT:     logScrollUp(1); return false;
-		break; case KEY_SRIGHT:    logScrollDown(1); return false;
-		break; case KEY_PPAGE:     logPageUp(); return false;
-		break; case KEY_NPAGE:     logPageDown(); return false;
-		break; case KEY_LEFT:      edit(ui.view->tag, EditLeft, 0);
-		break; case KEY_RIGHT:     edit(ui.view->tag, EditRight, 0);
-		break; case KEY_HOME:      edit(ui.view->tag, EditHome, 0);
-		break; case KEY_END:       edit(ui.view->tag, EditEnd, 0);
-		break; case KEY_DC:        edit(ui.view->tag, EditDelete, 0);
-		break; case KEY_BACKSPACE: edit(ui.view->tag, EditBackspace, 0);
-		break; case KEY_ENTER:     edit(ui.view->tag, EditEnter, 0);
-	}
-	return true;
-}
-
 void uiRead(void) {
 	uiShow();
 
@@ -546,16 +498,16 @@ void uiRead(void) {
 	}
 	if (!update) return;
 
-	int y, x;
-	wmove(ui.input, 0, 0);
-
 	struct Format format = { .str = editHead() };
 	formatReset(&format);
+	wmove(ui.input, 0, 0);
+
+	int _, x;
 	while (formatParse(&format, editTail())) {
-		if (format.split) getyx(ui.input, y, x);
+		if (format.split) getyx(ui.input, _, x);
 		addFormat(ui.input, &format);
 	}
 
 	wclrtoeol(ui.input);
-	wmove(ui.input, y, x);
+	wmove(ui.input, 0, x);
 }