# HG changeset patch # User Matti Hamalainen # Date 1338004578 -10800 # Node ID 796508f828f6ceb80a1dbb5eb353e13fb5e9714f # Parent c3b3b6d890849494ddfbe64699b2e0f9071d4360 Refactor much of the "windowing" UI code into a new module, ui.[ch] diff -r c3b3b6d89084 -r 796508f828f6 Makefile.gen --- a/Makefile.gen Sat May 26 06:18:19 2012 +0300 +++ b/Makefile.gen Sat May 26 06:56:18 2012 +0300 @@ -17,7 +17,7 @@ THLIBS_A=$(OBJPATH)thlibs.a THLIBS_OBJ=th_util.o th_string.o th_args.o th_config.o -NNCHAT_OBJ=main.o util.o network.o +NNCHAT_OBJ=main.o util.o network.o ui.o NNCHAT_BIN=$(BINPATH)nnchat$(EXEEXT) TARGETS+=$(THLIBS_A) $(NNCHAT_BIN) diff -r c3b3b6d89084 -r 796508f828f6 main.c --- a/main.c Sat May 26 06:18:19 2012 +0300 +++ b/main.c Sat May 26 06:56:18 2012 +0300 @@ -5,6 +5,7 @@ */ #include "util.h" #include "network.h" +#include "ui.h" #include "th_args.h" #include "th_config.h" #include @@ -16,11 +17,6 @@ #else #include #endif -#ifdef HAVE_NCURSES_H -#include -#else -#include -#endif #ifdef __WIN32 #define SET_CONFIG_FILE "nnchat.txt" @@ -37,7 +33,6 @@ #define SET_MAX_HISTORY (16) // Command history length #define SET_KEEPALIVE (15*60) // Ping/keepalive period in seconds -#define SET_MAX_WINDOWS (32) /* Options @@ -63,12 +58,6 @@ BOOL optDebug = FALSE; BOOL optLogEnable = FALSE; -nn_window_t *chatWindows[SET_MAX_WINDOWS], - *currWin = NULL; -WINDOW *mainWin = NULL, - *statusWin = NULL, - *editWin = NULL; - qlist_t *setIgnoreList = NULL, *setIdleMessages = NULL; nn_userhash_t *nnUsers = NULL; @@ -209,268 +198,6 @@ } -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(void) -{ - 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; -} - - -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; -} - - int printFile(FILE *outFile, const char *fmt) { const char *s = fmt; @@ -522,7 +249,7 @@ if (!optDaemon && (flags & LOG_WINDOW)) { - nn_window_t *tmp = win != NULL ? win : chatWindows[0]; + nn_window_t *tmp = (win != NULL) ? win : nnwin_main_window(); if (flags & LOG_STAMP) nnwin_print_buf(tmp, tmpStr); nnwin_print_buf(tmp, buf); } @@ -577,6 +304,7 @@ errorMessages = tmp; } + void errorMsg(const char *fmt, ...) { va_list ap; @@ -586,12 +314,14 @@ va_end(ap); } + void errorFunc(struct _nn_conn_t *conn, const char *fmt, va_list ap) { (void) conn; errorMsgV(fmt, ap); } + void messageFunc(struct _nn_conn_t *conn, const char *fmt, va_list ap) { (void) conn; @@ -1028,10 +758,10 @@ } else { - if (currWin != chatWindows[0]) + if (currWin != nnwin_main_window()) { nnwin_close(currWin); - currWin = chatWindows[0]; + currWin = nnwin_main_window(); } else { @@ -1051,11 +781,9 @@ if (arg[0]) { int val = atoi(arg); - if (val >= 1 && val < SET_MAX_WINDOWS) - { - if (chatWindows[val - 1] != NULL) - currWin = chatWindows[val - 1]; - } + nn_window_t *win = nnwin_get(val); + if (win != NULL) + currWin = win; else { printMsgQ(currWin, "Invalid window number '%s'\n", arg); @@ -1296,7 +1024,7 @@ return nn_handle_command(conn, buf); // If current window is not the main room window, send private - if (currWin != chatWindows[0]) + if (currWin != nnwin_main_window()) { if (currWin->id != NULL) { @@ -1329,41 +1057,6 @@ } -void nnwin_close_windows(void) -{ - if (mainWin) delwin(mainWin); - if (statusWin) delwin(statusWin); - if (editWin) delwin(editWin); -} - - -BOOL nnwin_initialize_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; -} - - -void nnwin_update_all(void) -{ - if (mainWin) redrawwin(mainWin); - if (statusWin) redrawwin(statusWin); - if (editWin) redrawwin(editWin); -} - - static void nn_tabcomplete_replace(nn_editbuf_t *buf, size_t *pi, const size_t startPos, const size_t endPos, char *c) { size_t i; @@ -1578,31 +1271,6 @@ } -char *promptRequester(WINDOW *win, const char *info, BOOL allowEmpty) -{ - char tmpBuf[512], *ptr; - size_t pos; - int curVis = curs_set(1); - - echo(); - waddstr(win, info); - wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1); - noecho(); - if (curVis != ERR) - curs_set(curVis); - - 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; -} - - void printHelp(void) { printMsgQ(currWin, "\n" @@ -1618,11 +1286,10 @@ int main(int argc, char *argv[]) { nn_conn_t *conn = NULL; - int curVis = ERR, updateCount = 0; + int updateCount = 0; BOOL argsOK, isError = FALSE, exitProg = FALSE, colorSet = FALSE, - cursesInit = FALSE, networkInit = FALSE, insertMode = TRUE, firstUpdate = TRUE; @@ -1630,7 +1297,7 @@ char *tmpStr; nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE); nn_editbuf_t *histBuf[SET_MAX_HISTORY+2]; - int histPos = 0, histMax = 0; + int histPos = 0, histMax = 0, index; cfgitem_t *tmpcfg; char *setHomeDir = NULL; @@ -1763,62 +1430,19 @@ else networkInit = TRUE; - // Initialize NCurses - if (!optDaemon) - { - if (LINES < 0 || LINES > 1000) LINES = 24; - if (COLS < 0 || COLS > 1000) COLS = 80; - initscr(); - raw(); - keypad(stdscr, TRUE); - noecho(); - meta(stdscr, TRUE); - timeout(SET_DELAY); - curVis = curs_set(0); - - if (has_colors()) - { - start_color(); + // Initialize curses windowing + if (!optDaemon && !nnwin_init(SET_DELAY)) + goto err_exit; - 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_initialize_windows()) - goto err_exit; - -#ifdef PDCURSES - PDC_set_title("NNChat v" NN_VERSION); -#endif - - memset(chatWindows, 0, sizeof(chatWindows)); - chatWindows[0] = nn_window_new(NULL); - currWin = chatWindows[0]; - nnwin_update_statusline(); - } + if (cursesInit) + nnwin_update_statusline(optUserName, optUserColor); // Check if we have username and password if (cursesInit && (optUserName == NULL || optPassword == NULL)) { nnwin_print(editWin, "You can avoid this prompt by issuing '/save' after logging in.\n"); - optUserName = promptRequester(editWin, "NN username: ", FALSE); - optPassword = promptRequester(editWin, "NN password: ", TRUE); + optUserName = nnwin_prompt_requester(editWin, "NN username: ", FALSE); + optPassword = nnwin_prompt_requester(editWin, "NN password: ", TRUE); } if (optUserName == NULL || optPassword == NULL) @@ -1909,7 +1533,7 @@ // First update of screen nnwin_update_editbuf(editBuf); - nnwin_update_statusline(); + nnwin_update_statusline(optUserName, optUserColor); printMsg(NULL, "%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname); printMsg(NULL, "%s\n", th_prog_author); @@ -2042,10 +1666,10 @@ if (c >= 0x31 && c <= 0x39) { // Chat window switching via Meta/Esc-[1..9] - int win = c - 0x31; - if (win < SET_MAX_WINDOWS && chatWindows[win] != NULL) + nn_window_t *win = nnwin_get(c - 0x30); + if (win != NULL) { - currWin = chatWindows[win]; + currWin = win; update = updateMain = TRUE; } c = ERR; @@ -2078,7 +1702,7 @@ erase(); timeout(SET_DELAY); - if (!nnwin_initialize_windows()) + if (!nnwin_init_windows()) { errorMsg("Error resizing curses chatWindows\n"); isError = TRUE; @@ -2291,7 +1915,7 @@ if (update || firstUpdate) { // Update edit line - nnwin_update_statusline(); + nnwin_update_statusline(optUserName, optUserColor); nnwin_update_editbuf(editBuf); firstUpdate = FALSE; // a nasty hack ... } @@ -2315,7 +1939,7 @@ nn_conn_send_msg_v(conn, optUserNameEnc, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor); } - nnwin_update_statusline(); + nnwin_update_statusline(optUserName, optUserColor); nnwin_update_editbuf(editBuf); updateCount = 0; } @@ -2330,14 +1954,10 @@ nn_userhash_free(nnUsers); nn_editbuf_free(editBuf); - { - int i; - for (i = 0; i <= SET_MAX_HISTORY; i++) - nn_editbuf_free(histBuf[i]); + for (index = 0; index <= SET_MAX_HISTORY; index++) + nn_editbuf_free(histBuf[index]); - for (i = 0; i < SET_MAX_WINDOWS; i++) - nn_window_free(chatWindows[i]); - } + nnwin_shutdown(); #ifdef __WIN32 if (errorMessages) @@ -2349,14 +1969,6 @@ } #endif - if (cursesInit) - { - if (curVis != ERR) - curs_set(curVis); - nnwin_close_windows(); - endwin(); - THMSG(1, "NCurses deinitialized.\n"); - } #ifndef __WIN32 if (errorMessages) diff -r c3b3b6d89084 -r 796508f828f6 ui.c --- /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; +} diff -r c3b3b6d89084 -r 796508f828f6 ui.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui.h Sat May 26 06:56:18 2012 +0300 @@ -0,0 +1,63 @@ +/* + * NNChat - Custom chat client for NewbieNudes.com chatrooms + * Written by Matti 'ccr' Hämäläinen + * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) + */ +#ifndef LIBNNUI_H +#define LIBNNUI_H + +#include "th_types.h" +#include "th_string.h" + +#ifdef HAVE_NCURSES_H +#include +#else +#include +#endif + + +#define SET_MAX_WINDOWS (32) +#define NN_BACKBUF_LEN (512) // Backbuffer size (in lines) + +typedef struct +{ + qringbuf_t *data; // "Backbuffer" data for this window + int pos; // Current position in the window, 0 = real time + BOOL dirty; + + char *id; // Chatter ID, NULL = main window + int num; // Window number + + char *buf; + size_t len, bufsize; + size_t chlen; +} nn_window_t; + + +extern nn_window_t *currWin; +extern BOOL cursesInit; +extern WINDOW *mainWin, *statusWin, *editWin; + +BOOL nnwin_init(int delay); +void nnwin_shutdown(); + +BOOL nnwin_init_windows(void); +void nnwin_close_windows(void); + +nn_window_t *nnwin_main_window(); +nn_window_t *nnwin_get(const int index); +nn_window_t *nnwin_find(const char *id); + +BOOL nnwin_open(const char *name, BOOL curwin); +void nnwin_close(nn_window_t *win); + +void nnwin_update_statusline(char *optUserName, int optUserColor); +void nnwin_update_editbuf(nn_editbuf_t *buf); +int nnwin_print(WINDOW *win, const char *fmt); +int nnwin_print_buf(nn_window_t *win, const char *fmt); +void nnwin_update_all(void); +char * nnwin_prompt_requester(WINDOW *win, const char *info, BOOL allowEmpty); +BOOL nnwin_update_main(BOOL force); + + +#endif diff -r c3b3b6d89084 -r 796508f828f6 util.c --- a/util.c Sat May 26 06:18:19 2012 +0300 +++ b/util.c Sat May 26 06:56:18 2012 +0300 @@ -683,36 +683,6 @@ } -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; -} - - -void nn_window_free(nn_window_t *win) -{ - if (win != NULL) - { - th_ringbuf_free(win->data); - th_free(win->id); - th_free(win); - } -} - - nn_strtuple_t *nn_strtuple_new(size_t len, char *str) { nn_strtuple_t *tuple = th_calloc(1, sizeof(nn_strtuple_t)); diff -r c3b3b6d89084 -r 796508f828f6 util.h --- a/util.h Sat May 26 06:18:19 2012 +0300 +++ b/util.h Sat May 26 06:56:18 2012 +0300 @@ -15,7 +15,6 @@ #define NN_TMPBUF_SIZE (4096) #define NN_ALLOC_SIZE (128) #define NN_NUM_BUCKETS (256) -#define NN_BACKBUF_LEN (512) // Backbuffer size (in lines) typedef struct _nn_user_t @@ -72,24 +71,6 @@ typedef struct { - qringbuf_t *data; // "Backbuffer" data for this window - int pos; // Current position in the window, 0 = real time - BOOL dirty; - - char *id; // Chatter ID, NULL = main window - int num; // Window number - - char *buf; - size_t len, bufsize; - size_t chlen; -} nn_window_t; - -nn_window_t *nn_window_new(const char *); -void nn_window_free(nn_window_t *); - - -typedef struct -{ size_t len; char *str; } nn_strtuple_t;