summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCurtis McEnroe2018-09-02 14:04:05 -0400
committerCurtis McEnroe2018-09-02 14:04:05 -0400
commitccb54d36d93d22b00858a167beb6e0f728986b7a (patch)
treece4ebaf6882daed4179489bd7f8fee759efb03a5
parentc58baa84eee3b0d80b1ec62c57ba616da99e3125 (diff)
Add status indicators
-rw-r--r--ui.c234
1 files changed, 139 insertions, 95 deletions
diff --git a/ui.c b/ui.c
index 7cfb417..8b3c1eb 100644
--- a/ui.c
+++ b/ui.c
@@ -37,7 +37,7 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-#define CTRL(c) ((c) & 037)
+#define CTRL(c) ((c) ^ 0100)
static void colorInit(void) {
start_color();
@@ -105,9 +105,7 @@ static void viewRemove(struct View *view) {
views.tags[view->tag.id] = NULL;
}
-static const int LOG_LINES = 256;
-static const int TOPIC_COLS = 512;
-static const int INPUT_COLS = 512;
+static const int LOG_LINES = 256;
static int logHeight(const struct View *view) {
return LINES - (view->topic ? 2 : 0) - 2;
@@ -141,6 +139,13 @@ static struct View *viewTag(struct Tag tag) {
return view;
}
+static void viewResize(void) {
+ for (struct View *view = views.head; view; view = view->next) {
+ wresize(view->log, LOG_LINES, COLS);
+ wmove(view->log, lastLogLine(), lastCol());
+ }
+}
+
static void viewClose(struct View *view) {
viewRemove(view);
if (view->topic) delwin(view->topic);
@@ -157,61 +162,29 @@ static void viewUnmark(struct View *view) {
view->mark = false;
}
+static const int COLS_MAX = 512;
+
static struct {
bool hide;
struct View *view;
+ WINDOW *status;
WINDOW *input;
} ui;
-void uiHide(void) {
- ui.hide = true;
- termMode(TERM_FOCUS, false);
- endwin();
-}
-
static void uiShow(void) {
ui.hide = false;
termMode(TERM_FOCUS, true);
}
-void uiInit(void) {
- setlocale(LC_CTYPE, "");
- initscr();
- cbreak();
- noecho();
-
- colorInit();
- termInit();
-
- ui.input = newpad(2, INPUT_COLS);
- mvwhline(ui.input, 0, 0, ACS_HLINE, INPUT_COLS);
- wmove(ui.input, 1, 0);
- keypad(ui.input, true);
- nodelay(ui.input, true);
-
- ui.view = viewTag(TAG_STATUS);
- termTitle(TAG_STATUS.name);
-
- uiShow();
-}
-
-void uiExit(void) {
- uiHide();
- printf(
- "This program is AGPLv3 free software!\n"
- "The source is available at <" SOURCE_URL ">.\n"
- );
-}
-
-static void uiResize(void) {
- for (struct View *view = views.head; view; view = view->next) {
- wresize(view->log, LOG_LINES, COLS);
- wmove(view->log, lastLogLine(), lastCol());
- }
+void uiHide(void) {
+ ui.hide = true;
+ termMode(TERM_FOCUS, false);
+ endwin();
}
void uiDraw(void) {
if (ui.hide) return;
+
if (ui.view->topic) {
pnoutrefresh(
ui.view->topic,
@@ -220,20 +193,31 @@ void uiDraw(void) {
1, lastCol()
);
}
+
pnoutrefresh(
ui.view->log,
ui.view->scroll - logHeight(ui.view), 0,
(ui.view->topic ? 2 : 0), 0,
lastLine() - 2, lastCol()
);
+
int _, x;
+ getyx(ui.status, _, x);
+ pnoutrefresh(
+ ui.status,
+ 0, MAX(0, x - lastCol() - 1),
+ lastLine() - 1, 0,
+ lastLine() - 1, lastCol()
+ );
+
getyx(ui.input, _, x);
pnoutrefresh(
ui.input,
0, MAX(0, x - lastCol() + 3),
- lastLine() - 1, 0,
+ lastLine(), 0,
lastLine(), lastCol()
);
+
doupdate();
}
@@ -241,52 +225,6 @@ static void uiRedraw(void) {
clearok(curscr, true);
}
-static void uiView(struct View *view) {
- termTitle(view->tag.name);
- if (view->topic) touchwin(view->topic);
- touchwin(view->log);
- viewMark(ui.view);
- viewUnmark(view);
- ui.view = view;
-}
-
-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) {
- if (++num) continue;
- uiView(view);
- break;
- }
- } else {
- for (struct View *view = views.head; view; view = view->next) {
- if (num--) continue;
- uiView(view);
- break;
- }
- }
-}
-
static const short IRC_COLORS[] = {
[IRC_WHITE] = 8 + COLOR_WHITE,
[IRC_BLACK] = 0 + COLOR_BLACK,
@@ -381,11 +319,88 @@ static void addIRC(WINDOW *win, const wchar_t *str) {
}
}
+static void uiStatus(void) {
+ mvwhline(ui.status, 0, 0, ACS_HLINE, COLS);
+ mvwaddch(ui.status, 0, COLS, ACS_RTEE);
+
+ int num = 0;
+ int count = 0;
+ for (const struct View *view = views.head; view; view = view->next, ++num) {
+ if (!view->unread) continue;
+ bool status = (view->tag.id == TAG_STATUS.id);
+
+ int unread;
+ wchar_t *str;
+ int len = aswprintf(
+ &str, L",\3%02d%d\3%s%s%n(%d)",
+ (view->hot ? IRC_YELLOW : IRC_WHITE), num,
+ &status[":"], (status ? "" : view->tag.name),
+ &unread, view->unread
+ );
+ if (len < 0) err(EX_OSERR, "aswprintf");
+ if (view->unread == 1) str[unread] = L'\0';
+
+ addIRC(ui.status, count ? str : &str[1]);
+ free(str);
+ count++;
+ }
+
+ waddch(ui.status, count ? ACS_LTEE : '\b');
+ waddch(ui.status, ACS_HLINE);
+}
+
+static void uiView(struct View *view) {
+ termTitle(view->tag.name);
+ if (view->topic) touchwin(view->topic);
+ touchwin(view->log);
+ viewMark(ui.view);
+ 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) {
+ if (++num) continue;
+ uiView(view);
+ break;
+ }
+ } else {
+ for (struct View *view = views.head; view; view = view->next) {
+ if (num--) continue;
+ uiView(view);
+ break;
+ }
+ }
+}
+
void uiTopic(struct Tag tag, const char *topic) {
struct View *view = viewTag(tag);
if (!view->topic) {
- view->topic = newpad(2, TOPIC_COLS);
- mvwhline(view->topic, 1, 0, ACS_HLINE, TOPIC_COLS);
+ view->topic = newpad(2, COLS_MAX);
+ mvwhline(view->topic, 1, 0, ACS_HLINE, COLS_MAX);
}
wchar_t *wcs = ambstowcs(topic);
if (!wcs) err(EX_DATAERR, "ambstowcs");
@@ -404,6 +419,7 @@ void uiLog(struct Tag tag, enum UIHeat heat, const wchar_t *line) {
view->hot = true;
beep(); // TODO: Notification.
}
+ uiStatus();
}
addIRC(view->log, line);
}
@@ -419,6 +435,34 @@ void uiFmt(struct Tag tag, enum UIHeat heat, const wchar_t *format, ...) {
free(wcs);
}
+void uiInit(void) {
+ setlocale(LC_CTYPE, "");
+ initscr();
+ cbreak();
+ noecho();
+
+ colorInit();
+ termInit();
+
+ ui.status = newpad(1, COLS_MAX);
+ ui.input = newpad(1, COLS_MAX);
+ keypad(ui.input, true);
+ nodelay(ui.input, true);
+
+ ui.view = viewTag(TAG_STATUS);
+ uiViewTag(TAG_STATUS);
+ uiStatus();
+ uiShow();
+}
+
+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;
@@ -505,7 +549,7 @@ static bool keyChar(wchar_t ch) {
static bool keyCode(wchar_t ch) {
switch (ch) {
- break; case KEY_RESIZE: uiResize(); return false;
+ 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;
@@ -537,7 +581,7 @@ void uiRead(void) {
if (!update) return;
int y, x;
- wmove(ui.input, 1, 0);
+ wmove(ui.input, 0, 0);
addIRC(ui.input, editHead());
getyx(ui.input, y, x);
addIRC(ui.input, editTail());