ncdc/ncdc/src/mainwindow.c

383 lines
8.6 KiB
C

#include <ncdc/mainwindow.h>
#include <ncdc/input.h>
#include <ncdc/textview.h>
#include <ncdc/cmds.h>
#include <ncdc/ncdc.h>
typedef enum {
FOCUS_GUILDS = 0,
FOCUS_CHAT,
FOCUS_INPUT,
} focus_t;
struct ncdc_mainwindow_
{
dc_refable_t ref;
WINDOW *guilds;
int guilds_w;
int guilds_h;
int guilds_y;
int guilds_x;
WINDOW *chat;
int chat_h;
int chat_w;
int chat_y;
int chat_x;
WINDOW *input;
int input_w;
int input_h;
int input_y;
int input_x;
int input_curs_x;
WINDOW *sep1;
WINDOW *sep2;
ncdc_input_t in;
GPtrArray *views;
int curview;
ncdc_textview_t log;
int focus;
};
static void ncdc_mainwindow_resize(ncdc_mainwindow_t n);
static void ncdc_mainwindow_update_focus(ncdc_mainwindow_t n);
static bool ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
size_t len, void *arg);
static void ncdc_mainwindow_free(ncdc_mainwindow_t n)
{
return_if_true(n == NULL,);
delwin(n->guilds);
delwin(n->chat);
delwin(n->input);
delwin(n->sep1);
delwin(n->sep2);
dc_unref(n->in);
if (n->views != NULL) {
g_ptr_array_unref(n->views);
n->views = NULL;
}
free(n);
}
ncdc_mainwindow_t ncdc_mainwindow_new(void)
{
ncdc_mainwindow_t ptr = calloc(1, sizeof(struct ncdc_mainwindow_));
return_if_true(ptr == NULL, NULL);
ptr->ref.cleanup = (dc_cleanup_t)ncdc_mainwindow_free;
ptr->in = ncdc_input_new();
ncdc_input_set_callback(ptr->in, ncdc_mainwindow_callback, ptr);
ptr->views = g_ptr_array_new_with_free_func(
(GDestroyNotify)dc_unref
);
ptr->log = ncdc_textview_new();
ncdc_textview_set_title(ptr->log, L"status");
g_ptr_array_add(ptr->views, ptr->log);
ptr->guilds = newwin(5, 5, 1, 1);
ptr->chat = newwin(5, 5, 4, 4);
ptr->input = newwin(5, 5, 8, 8);
keypad(ptr->input, TRUE);
ptr->sep1 = newwin(5, 5, 10, 10);
ptr->sep2 = newwin(5, 5, 12, 12);
ncdc_mainwindow_resize(ptr);
ptr->focus = FOCUS_INPUT;
ncdc_mainwindow_update_focus(ptr);
return ptr;
}
static bool
ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
size_t len, void *arg)
{
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
bool ret = false;
if (s == NULL || s[0] == '\0') {
return false;
}
if (s[0] == '/') {
ret = ncdc_dispatch(mainwin, s);
} else {
wchar_t *post = calloc(wcslen(s)+7, sizeof(wchar_t));
wcscat(post, L"/post ");
wcscat(post, s);
ret = ncdc_dispatch(mainwin, post);
free(post);
}
return ret;
}
static void ncdc_mainwindow_resize(ncdc_mainwindow_t n)
{
n->guilds_h = LINES - 2;
n->guilds_w = (COLS / 5);
n->guilds_y = 0;
n->guilds_x = 0;
wresize(n->guilds, n->guilds_h, n->guilds_w);
mvwin(n->guilds, n->guilds_y, n->guilds_x);
wnoutrefresh(n->guilds);
n->input_h = 1;
n->input_w = COLS;
n->input_y = LINES - n->input_h;
n->input_x = 0;
wresize(n->input, n->input_h, n->input_w);
mvwin(n->input, n->input_y, n->input_x);
wnoutrefresh(n->input);
wresize(n->sep1, 1, COLS);
mvwin(n->sep1, LINES - 2, 0);
wbkgd(n->sep1, COLOR_PAIR(1));
wnoutrefresh(n->sep1);
n->chat_h = LINES - n->input_h - 1;
n->chat_w = COLS - n->guilds_w - 2;
n->chat_y = 0;
n->chat_x = n->guilds_w + 2;
wresize(n->chat, n->chat_h, n->chat_w);
mvwin(n->chat, n->chat_y, n->chat_x);
wnoutrefresh(n->chat);
wresize(n->sep2, LINES - 2, 1);
mvwin(n->sep2, 0, n->guilds_w + 1);
wnoutrefresh(n->sep2);
ncdc_mainwindow_update_focus(n);
}
static void ncdc_mainwindow_update_focus(ncdc_mainwindow_t n)
{
switch (n->focus) {
case FOCUS_GUILDS:
{
} break;
case FOCUS_CHAT:
{
} break;
case FOCUS_INPUT:
{
wmove(n->input, 0, ncdc_input_cursor(n->in));
wrefresh(n->input);
} break;
}
}
static void ncdc_mainwindow_render_status(ncdc_mainwindow_t n)
{
wchar_t *status = NULL;
size_t statuslen = 0;
wchar_t timestr[100] = {0};
time_t tm = time(NULL);
struct tm *t = localtime(&tm);
FILE *f = open_wmemstream(&status, &statuslen);
wchar_t const *wintitle = NULL;
ncdc_textview_t view = NULL;
size_t i = 0;
dc_channel_t channel = NULL;
werase(n->sep1);
return_if_true(f == NULL,);
wcsftime(timestr, 99, L"[%H:%M]", t);
fwprintf(f, L"%ls", timestr);
if (!is_logged_in()) {
fwprintf(f, L" [not logged in]");
} else {
dc_account_t current_account = dc_session_me(current_session);
fwprintf(f, L" [%s]", dc_account_fullname(current_account));
}
view = g_ptr_array_index(n->views, n->curview);
wintitle = ncdc_textview_title(view);
fwprintf(f, L" [%d: %ls]", n->curview,
(wintitle != NULL ? wintitle : L"n/a")
);
fwprintf(f, L" [Act:");
for (i = 0; i < n->views->len; i++) {
view = g_ptr_array_index(n->views, i);
channel = ncdc_textview_channel(view);
if (channel != NULL && dc_channel_has_new_messages(channel)) {
fwprintf(f, L" %d", i);
}
}
fwprintf(f, L"]");
fclose(f);
mvwaddwstr(n->sep1, 0, 0, status);
free(status);
}
void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n)
{
wint_t i = 0;
wchar_t *key = NULL;
size_t keylen = 0;
WINDOW *win = NULL;
ncdc_keybinding_t *k = NULL;
switch (n->focus) {
case FOCUS_INPUT: win = n->input; break;
case FOCUS_CHAT: win = n->chat; break;
case FOCUS_GUILDS: win = n->guilds; break;
}
if (wget_wch(win, &i) == ERR) {
return;
}
if (i == KEY_RESIZE) {
ncdc_mainwindow_resize(n);
return;
}
if (i == KEY_ESCAPE) {
if ((key = util_readkey(i, n->input)) == NULL) {
return;
}
keylen = wcslen(key);
}
FILE *f = fopen("keys.txt", "a+");
fwprintf(f, L"%d - %ls\n", i, (key == NULL ? L"n/a" : &key[1]));
fclose(f);
if (key != NULL &&
(k = ncdc_find_keybinding(keys_mainwin, key, keylen)) != NULL) {
k->handler(n);
return;
}
if (n->focus == FOCUS_INPUT) {
if (key == NULL) {
ncdc_input_feed(n->in, (wchar_t const *)&i, sizeof(wchar_t));
} else {
ncdc_input_feed(n->in, key, wcslen(key));
}
}
free(key);
}
GPtrArray *ncdc_mainwindow_views(ncdc_mainwindow_t n)
{
return n->views;
}
void ncdc_mainwindow_switchview(ncdc_mainwindow_t n, int idx)
{
return_if_true(n == NULL || n->views == NULL,);
return_if_true(idx >= n->views->len,);
n->curview = idx;
}
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n)
{
ncdc_textview_t v = 0;
wnoutrefresh(n->guilds);
/* render active text view
*/
v = g_ptr_array_index(n->views, n->curview);
ncdc_textview_render(v, n->chat, n->chat_h, n->chat_w);
wnoutrefresh(n->chat);
ncdc_input_draw(n->in, n->input);
wnoutrefresh(n->input);
wbkgd(n->sep1, COLOR_PAIR(1));
ncdc_mainwindow_render_status(n);
wnoutrefresh(n->sep1);
wbkgd(n->sep2, COLOR_PAIR(1));
wnoutrefresh(n->sep2);
ncdc_mainwindow_update_focus(n);
}
void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...)
{
va_list lst;
wchar_t buf[256] = {0};
return_if_true(w == NULL || fmt == NULL,);
va_start(lst, fmt);
vswprintf(buf, 255, fmt, lst);
va_end(lst);
ncdc_textview_append(w->log, buf);
}
static void ncdc_mainwindow_ack_view(ncdc_mainwindow_t n)
{
#if 0
dc_channel_t c = ncdc_mainwindow_current_channel(n);
return_if_true(c == NULL,);
return_if_true(dc_channel_messages(c) == 0,);
dc_message_t m = dc_channel_nth_message(c, dc_channel_messages(c)-1);
dc_api_channel_ack(dc_session_api(current_session),
dc_session_me(current_session),
c, m
);
#endif
}
void ncdc_mainwindow_rightview(ncdc_mainwindow_t n)
{
return_if_true(n == NULL,);
n->curview = (n->curview + 1) % n->views->len;
ncdc_mainwindow_ack_view(n);
}
void ncdc_mainwindow_leftview(ncdc_mainwindow_t n)
{
return_if_true(n == NULL,);
n->curview = (n->curview - 1) % n->views->len;
ncdc_mainwindow_ack_view(n);
}
dc_channel_t ncdc_mainwindow_current_channel(ncdc_mainwindow_t n)
{
return_if_true(n == NULL, NULL);
ncdc_textview_t view = g_ptr_array_index(n->views, n->curview);
/* can't post to the log channel, that's for internal use only
*/
return_if_true(view == n->log, NULL);
return ncdc_textview_channel(view);
}