diff options
author | June McEnroe <june@causal.agency> | 2018-08-04 20:54:50 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2018-08-04 20:54:50 -0400 |
commit | 8fdf2c402d23b52868b9208c9d450281c3772c11 (patch) | |
tree | abfd8f19c10f1f55283f17b81bc95e8960363974 | |
parent | Handle /topic (diff) | |
download | catgirl-8fdf2c402d23b52868b9208c9d450281c3772c11.tar.gz catgirl-8fdf2c402d23b52868b9208c9d450281c3772c11.zip |
Implement line editing, scrolling
Don't really have a way to implement the M-* keys, and currently missing C-w.
-rw-r--r-- | ui.c | 171 |
1 files changed, 138 insertions, 33 deletions
diff --git a/ui.c b/ui.c index b014668..0e24510 100644 --- a/ui.c +++ b/ui.c @@ -33,8 +33,10 @@ #define A_ITALIC A_NORMAL #endif -#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CTRL(c) ((c) & 037) + #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) static const int TOPIC_COLS = 512; static const int INPUT_COLS = 512; @@ -44,15 +46,25 @@ static struct { WINDOW *topic; WINDOW *log; WINDOW *input; + int scroll; size_t cursor; } ui; +static int lastLine(void) { + return LINES - 1; +} +static int lastCol(void) { + return COLS - 1; +} +static int logHeight(void) { + return LINES - 4; +} + void uiInit(void) { setlocale(LC_CTYPE, ""); initscr(); cbreak(); noecho(); - keypad(stdscr, true); start_color(); use_default_colors(); @@ -70,11 +82,14 @@ void uiInit(void) { ui.log = newpad(LOG_LINES, COLS); wsetscrreg(ui.log, 0, LOG_LINES - 1); scrollok(ui.log, true); - wmove(ui.log, LOG_LINES - (LINES - 4) - 1, 0); + wmove(ui.log, LOG_LINES - logHeight() - 1, 0); + ui.scroll = LOG_LINES; ui.input = newpad(2, INPUT_COLS); mvwhline(ui.input, 0, 0, ACS_HLINE, INPUT_COLS); wmove(ui.input, 1, ui.cursor); + + keypad(ui.input, true); nodelay(ui.input, true); } @@ -88,26 +103,23 @@ void uiHide(void) { } void uiDraw(void) { - int lastCol = COLS - 1; - int lastLine = LINES - 1; - pnoutrefresh( ui.topic, 0, 0, 0, 0, - 1, lastCol + 1, lastCol() ); pnoutrefresh( ui.log, - LOG_LINES - (LINES - 4), 0, + ui.scroll - logHeight(), 0, 2, 0, - lastLine - 2, lastCol + lastLine() - 2, lastCol() ); pnoutrefresh( ui.input, - 0, MAX(0, ui.cursor - lastCol), - lastLine - 1, 0, - lastLine, lastCol + 0, MAX(0, ui.cursor - lastCol() + 1), + lastLine() - 1, 0, + lastLine(), lastCol() ); doupdate(); } @@ -210,31 +222,124 @@ void uiFmt(const char *format, ...) { free(buf); } -void uiRead(void) { - static wchar_t buf[512]; - static size_t len; +static void scrollUp(void) { + if (ui.scroll == logHeight()) return; + ui.scroll = MAX(ui.scroll - logHeight() / 2, logHeight()); +} +static void scrollDown(void) { + if (ui.scroll == LOG_LINES) return; + ui.scroll = MIN(ui.scroll + logHeight() / 2, LOG_LINES); +} + +static struct { + wchar_t buf[512]; + size_t len; +} line; +static const size_t BUF_LEN = sizeof(line.buf) / sizeof(line.buf[0]); + +static void moveLeft(void) { + if (ui.cursor) ui.cursor--; +} +static void moveRight(void) { + if (ui.cursor < line.len) ui.cursor++; +} +static void moveHome(void) { + ui.cursor = 0; +} +static void moveEnd(void) { + ui.cursor = line.len; +} + +static void insert(wchar_t ch) { + if (!iswprint(ch)) return; + if (line.len == BUF_LEN - 1) return; + if (ui.cursor == line.len) { + line.buf[line.len] = ch; + } else { + wmemmove( + &line.buf[ui.cursor + 1], + &line.buf[ui.cursor], + line.len - ui.cursor + ); + line.buf[ui.cursor] = ch; + } + line.len++; + ui.cursor++; +} + +static void backspace(void) { + if (!ui.cursor) return; + if (ui.cursor != line.len) { + wmemmove( + &line.buf[ui.cursor - 1], + &line.buf[ui.cursor], + line.len - ui.cursor + ); + } + line.len--; + ui.cursor--; +} + +static void delete(void) { + if (ui.cursor == line.len) return; + moveRight(); + backspace(); +} + +static void kill(void) { + line.len = ui.cursor; +} + +static void enter(void) { + if (!line.len) return; + line.buf[line.len] = '\0'; + input(line.buf); + line.len = 0; + ui.cursor = 0; +} + +static void keyChar(wint_t ch) { + switch (ch) { + break; case CTRL('B'): moveLeft(); + break; case CTRL('F'): moveRight(); + break; case CTRL('A'): moveHome(); + break; case CTRL('E'): moveEnd(); + break; case CTRL('D'): delete(); + break; case CTRL('K'): kill(); + break; case '\b': backspace(); + break; case '\177': backspace(); + break; case '\n': enter(); + break; default: insert(ch); + } +} + +static void keyCode(wint_t ch) { + switch (ch) { + break; case KEY_RESIZE: uiResize(); + break; case KEY_PPAGE: scrollUp(); + break; case KEY_NPAGE: scrollDown(); + break; case KEY_LEFT: moveLeft(); + break; case KEY_RIGHT: moveRight(); + break; case KEY_HOME: moveHome(); + break; case KEY_END: moveEnd(); + break; case KEY_BACKSPACE: backspace(); + break; case KEY_DC: delete(); + break; case KEY_ENTER: enter(); + } +} +void uiRead(void) { + int ret; wint_t ch; - while (wget_wch(ui.input, &ch) != ERR) { - switch (ch) { - break; case KEY_RESIZE: uiResize(); - break; case '\b': case '\177': { - if (len) len--; - } - break; case '\n': { - if (!len) break; - buf[len] = '\0'; - input(buf); - len = 0; - } - break; default: { - // TODO: Check overflow - if (iswprint(ch)) buf[len++] = ch; - } + while (ERR != (ret = wget_wch(ui.input, &ch))) { + if (ret == KEY_CODE_YES) { + keyCode(ch); + } else { + keyChar(ch); } } wmove(ui.input, 1, 0); - waddnwstr(ui.input, buf, len); + waddnwstr(ui.input, line.buf, line.len); wclrtoeol(ui.input); - ui.cursor = len; + wmove(ui.input, 1, ui.cursor); } |