diff options
author | June McEnroe <june@causal.agency> | 2018-09-02 14:04:05 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2018-09-02 14:04:05 -0400 |
commit | ccb54d36d93d22b00858a167beb6e0f728986b7a (patch) | |
tree | ce4ebaf6882daed4179489bd7f8fee759efb03a5 | |
parent | Write terminating null in allocating wcs/mbs conversions (diff) | |
download | catgirl-ccb54d36d93d22b00858a167beb6e0f728986b7a.tar.gz catgirl-ccb54d36d93d22b00858a167beb6e0f728986b7a.zip |
Add status indicators
-rw-r--r-- | ui.c | 234 |
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()); |