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;
+}