Mercurial > hg > nnchat
diff ui.c @ 466:796508f828f6
Refactor much of the "windowing" UI code into a new module, ui.[ch]
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 26 May 2012 06:56:18 +0300 |
parents | |
children | 56689f94e827 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui.c Sat May 26 06:56:18 2012 +0300 @@ -0,0 +1,461 @@ +/* + * NNChat - Custom chat client for NewbieNudes.com chatrooms + * Written by Matti 'ccr' Hämäläinen + * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) + */ +#include "util.h" +#include "ui.h" + +nn_window_t *chatWindows[SET_MAX_WINDOWS], + *currWin = NULL; + +BOOL cursesInit = FALSE; +int cursorVisible = ERR; +WINDOW *mainWin = NULL, + *statusWin = NULL, + *editWin = NULL; + + +static nn_window_t *nn_window_new(const char *id) +{ + nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); + + if (res == NULL) return NULL; + + res->data = th_ringbuf_new(NN_BACKBUF_LEN, th_free); + if (res->data == NULL) + { + th_free(res); + return NULL; + } + + res->id = th_strdup(id); + + return res; +} + + +static void nn_window_free(nn_window_t *win) +{ + if (win != NULL) + { + th_ringbuf_free(win->data); + th_free(win->id); + th_free(win); + } +} + + +nn_window_t *nnwin_main_window() +{ + return chatWindows[0]; +} + + +nn_window_t *nnwin_get(const int index) +{ + if (index >= 1 && index <= SET_MAX_WINDOWS) + return chatWindows[index - 1]; + else + return 0; + +} + + +BOOL nnwin_init(int delay) +{ + if (LINES < 0 || LINES > 1000) LINES = 24; + if (COLS < 0 || COLS > 1000) COLS = 80; + + initscr(); + raw(); + keypad(stdscr, TRUE); + noecho(); + meta(stdscr, TRUE); + timeout(delay); + cursorVisible = curs_set(0); + + if (has_colors()) + { + start_color(); + + init_pair( 1, COLOR_RED, COLOR_BLACK); + init_pair( 2, COLOR_GREEN, COLOR_BLACK); + init_pair( 3, COLOR_YELLOW, COLOR_BLACK); + init_pair( 4, COLOR_BLUE, COLOR_BLACK); + init_pair( 5, COLOR_MAGENTA, COLOR_BLACK); + init_pair( 6, COLOR_CYAN, COLOR_BLACK); + init_pair( 7, COLOR_WHITE, COLOR_BLACK); + init_pair( 8, COLOR_BLACK, COLOR_BLACK); + + init_pair(10, COLOR_BLACK, COLOR_RED); + init_pair(11, COLOR_WHITE, COLOR_RED); + init_pair(12, COLOR_GREEN, COLOR_RED); + init_pair(13, COLOR_YELLOW, COLOR_RED); + init_pair(14, COLOR_BLUE, COLOR_RED); + init_pair(15, COLOR_MAGENTA, COLOR_RED); + init_pair(16, COLOR_CYAN, COLOR_RED); + } + + cursesInit = TRUE; + + if (!nnwin_init_windows()) + return FALSE; + +#ifdef PDCURSES + PDC_set_title("NNChat v" NN_VERSION); +#endif + + memset(chatWindows, 0, sizeof(chatWindows)); + chatWindows[0] = nn_window_new(NULL); + currWin = chatWindows[0]; + + return TRUE; +} + + +void nnwin_shutdown() +{ + int i; + + for (i = 0; i < SET_MAX_WINDOWS; i++) + nn_window_free(chatWindows[i]); + + if (cursesInit) + { + if (cursorVisible != ERR) + curs_set(cursorVisible); + + nnwin_close_windows(); + + endwin(); + THMSG(1, "NCurses deinitialized.\n"); + } +} + + +nn_window_t *nnwin_find(const char *id) +{ + int i; + + for (i = 0; i < SET_MAX_WINDOWS; i++) + { + if (chatWindows[i] != NULL && + chatWindows[i]->id != NULL && + th_strcasecmp(id, chatWindows[i]->id) == 0) + return chatWindows[i]; + } + + return NULL; +} + + +BOOL nnwin_open(const char *name, BOOL curwin) +{ + int i; + nn_window_t *res; + if (name == NULL) + return FALSE; + + if ((res = nn_window_new(name)) == NULL) + return FALSE; + + for (i = 1; i < SET_MAX_WINDOWS; i++) + if (chatWindows[i] == NULL) + { + res->num = i; + chatWindows[i] = res; + if (curwin) + currWin = res; + return TRUE; + } + + return FALSE; +} + + +void nnwin_close(nn_window_t *win) +{ + int i; + if (win == NULL) return; + + for (i = 1; i < SET_MAX_WINDOWS; i++) + if (chatWindows[i] == win) + { + chatWindows[i] = NULL; + nn_window_free(win); + return; + } +} + + +void nnwin_update_statusline(char *optUserName, int optUserColor) +{ + char tmpStr[128]; + int i; + + if (statusWin == NULL) return; + + str_get_timestamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); + + wbkgdset(statusWin, COLOR_PAIR(10)); + werase(statusWin); + + wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); + mvwaddstr(statusWin, 0, 1, tmpStr); + + wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); + waddstr(statusWin, " | "); + wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); + waddstr(statusWin, optUserName); + wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); + + wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); + waddstr(statusWin, " | "); + wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); + snprintf(tmpStr, sizeof(tmpStr), "#%06x", optUserColor); + waddstr(statusWin, tmpStr); + + wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); + waddstr(statusWin, " | WIN: "); + snprintf(tmpStr, sizeof(tmpStr), "%d: %s / %d", + currWin->num + 1, + currWin->id != NULL ? currWin->id : "MAIN", + currWin->pos); + waddstr(statusWin, tmpStr); + + wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); + waddstr(statusWin, " | "); + wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); + + for (i = 0; i < SET_MAX_WINDOWS; i++) + { + if (chatWindows[i] != NULL && chatWindows[i]->dirty) + { + snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1); + waddstr(statusWin, tmpStr); + } + } + + wrefresh(statusWin); +} + + +void nnwin_update_editbuf(nn_editbuf_t *buf) +{ + char *tmp; + if (editWin == NULL || buf == NULL) return; + + buf->data[buf->len] = 0; + tmp = nn_username_decode(th_strdup(buf->data)); + + werase(editWin); + + wattrset(editWin, A_NORMAL); + + if (buf->pos < buf->len) + { + waddnstr(editWin, tmp, buf->pos); + wattrset(editWin, A_REVERSE); + waddch(editWin, tmp[buf->pos]); + wattrset(editWin, A_NORMAL); + waddnstr(editWin, tmp + buf->pos + 1, buf->len - buf->pos - 1); + } + else + { + waddnstr(editWin, tmp, buf->len); + wattrset(editWin, A_REVERSE); + waddch(editWin, ' '); + wattrset(editWin, A_NORMAL); + } + wrefresh(editWin); + th_free(tmp); +} + + +int nnwin_print(WINDOW *win, const char *fmt) +{ + const char *s = fmt; + int col = 0; + + while (*s) + { + if (*s == '½') + { + s++; + if (*s == '½') + { + waddch(win, ((unsigned char) *s) | col); + s++; + } + else + { + memcpy(&col, s, sizeof(int)); + s += sizeof(int); + } + } + else + { + waddch(win, ((unsigned char) *s) | col); + s++; + } + } + return 0; +} + + +#define QPUTCH(ch) th_vputch(&(win->buf), &(win->bufsize), &(win->len), ch) + +int nnwin_print_buf(nn_window_t *win, const char *fmt) +{ + const char *s = fmt; + int col = 0; + while (*s) + { + if (*s == '½') + { + s++; + if (*s == '½') + { + QPUTCH(*s); + QPUTCH(*s); + win->chlen++; + } + else + { + int val = 0; + while (*s >= '0' && *s <= '9') + { + val *= 10; + val += (*s - '0'); + s++; + } + if (*s != '½') return -1; + + if (val < 9) + col = A_DIM | COLOR_PAIR(val); + else if (val < 30) + col = A_BOLD | COLOR_PAIR(val - 9); + + QPUTCH('½'); + + if (!th_growbuf(&(win->buf), &(win->bufsize), &(win->len), sizeof(int))) + return -2; + + memcpy(win->buf + win->len, &col, sizeof(int)); + win->len += sizeof(int); + } + } + else if (*s == '\n') + { + QPUTCH('\n'); + QPUTCH(0); + th_ringbuf_add(win->data, win->buf); + win->buf = NULL; + win->chlen = 0; + win->dirty = TRUE; + } + else if (*s != '\r') + { + QPUTCH((unsigned char) *s == 255 ? ' ' : *s); + win->chlen++; + } + + s++; + } + + return 0; +} + + +void nnwin_update_all(void) +{ + if (mainWin) redrawwin(mainWin); + if (statusWin) redrawwin(statusWin); + if (editWin) redrawwin(editWin); +} + + +char *nnwin_prompt_requester(WINDOW *win, const char *info, BOOL allowEmpty) +{ + char tmpBuf[512], *ptr; + size_t pos; + int curSave = curs_set(1); + + echo(); + waddstr(win, info); + wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1); + noecho(); + + if (curSave != ERR) + curs_set(curSave); + + for (pos = strlen(tmpBuf) - 1; pos > 0 && th_isspace(tmpBuf[pos]); pos--) + tmpBuf[pos] = 0; + + ptr = str_trim_left(tmpBuf); + + if (allowEmpty || strlen(ptr) > 0) + return th_strdup(ptr); + else + return NULL; +} + + +BOOL nnwin_update_main(BOOL force) +{ + int h, offs; + qringbuf_t *buf; + + // Check pointers + if (mainWin == NULL || currWin == NULL) + return FALSE; + + // Check if update is forced or if the window is dirty + if (!force && !currWin->dirty) + return FALSE; + + // Compute how many lines from backbuffer fit on the screen + buf = currWin->data; + h = getmaxy(mainWin); + + // Clear and redraw window + werase(mainWin); + scrollok(mainWin, 1); + for (offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size; offs++) + { + if (buf->data[offs] != NULL) + nnwin_print(mainWin, buf->data[offs]); + } + + currWin->dirty = FALSE; + wrefresh(mainWin); + return TRUE; +} + + +void nnwin_close_windows(void) +{ + if (mainWin) delwin(mainWin); + if (statusWin) delwin(statusWin); + if (editWin) delwin(editWin); +} + + +BOOL nnwin_init_windows(void) +{ + int w, h; + + getmaxyx(stdscr, h, w); + + nnwin_close_windows(); + + mainWin = subwin(stdscr, h - 4, w, 0, 0); + statusWin = subwin(stdscr, 1, w, h - 4, 0); + editWin = subwin(stdscr, 3, w, h - 3, 0); + + if (mainWin == NULL || statusWin == NULL || editWin == NULL) + return FALSE; + + return TRUE; +}