From 09badaa9ee6b4d2ff8a5b136dc1b1481739ae264 Mon Sep 17 00:00:00 2001 From: Jfreegman Date: Thu, 26 Jun 2014 02:33:09 -0400 Subject: [PATCH] refactor chat window input code, misc fixes --- build/Makefile | 4 +- src/chat.c | 245 ++++++++++---------------------------- src/friendlist.c | 2 +- src/groupchat.c | 258 +++++++++++----------------------------- src/input.c | 278 ++++++++++++++++++++++++++++++++++++++++++++ src/input.h | 33 ++++++ src/misc_tools.c | 7 -- src/misc_tools.h | 3 - src/prompt.c | 4 +- src/toxic.h | 7 +- src/toxic_strings.c | 6 +- src/windows.h | 6 +- 12 files changed, 449 insertions(+), 404 deletions(-) create mode 100644 src/input.c create mode 100644 src/input.h diff --git a/build/Makefile b/build/Makefile index 53947ba..b812f47 100644 --- a/build/Makefile +++ b/build/Makefile @@ -12,14 +12,14 @@ DATAFILES = $(MISC_DIR)/DHTnodes $(MISC_DIR)/toxic.conf LIBS = libtoxcore ncursesw -CFLAGS = -std=gnu99 -pthread -Wimplicit-function-declaration -Wreturn-type +CFLAGS = -std=gnu99 -pthread -Wimplicit-function-declaration -Wreturn-type -Werror CFLAGS += -DTOXICVER="\"$(VERSION)\"" -DHAVE_WIDECHAR -D_XOPEN_SOURCE_EXTENDED CFLAGS += -DPACKAGE_DATADIR="\"$(DATADIR)\"" CFLAGS += $(USER_CFLAGS) LDFLAGS = $(USER_LDFLAGS) OBJ = chat.o chat_commands.o configdir.o dns.o execute.o -OBJ += file_senders.o friendlist.o global_commands.o groupchat.o line_info.o +OBJ += file_senders.o friendlist.o global_commands.o groupchat.o line_info.o input.o OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o # Variables for audio support diff --git a/src/chat.c b/src/chat.c index b4fc07b..869c920 100644 --- a/src/chat.c +++ b/src/chat.c @@ -20,10 +20,6 @@ * */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE /* needed for strcasestr() and wcwidth() */ -#endif - #include #include #include @@ -38,6 +34,7 @@ #include "log.h" #include "line_info.h" #include "settings.h" +#include "input.h" #ifdef _SUPPORT_AUDIO #include "audio_call.h" @@ -105,12 +102,15 @@ static void set_typingstatus(ToxWindow *self, Tox *m, uint8_t is_typing) ctx->self_is_typing = is_typing; } -void kill_chat_window(ToxWindow *self) +void kill_chat_window(ToxWindow *self, Tox *m) { set_active_window(0); ChatContext *ctx = self->chatwin; StatusBar *statusbar = self->stb; + if (ctx->self_is_typing) + set_typingstatus(self, m, 0); + log_disable(ctx->log); line_info_cleanup(ctx->hst); @@ -659,192 +659,75 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (x2 <= 0) return; - int cur_len = 0; /* widechar size of current char */ - int x2_is_odd = x2 % 2 != 0; - - if (ltr) { /* char is printable */ - if (ctx->len < MAX_STR_SIZE - 1) { - add_char_to_buf(ctx, key); - cur_len = MAX(1, wcwidth(key)); - wmove(self->window, y, x + cur_len); + input_new_char(self, key, x, y, x2, y2); - if (x + cur_len >= x2) - ctx->start += cur_len; - } - - if (!ctx->self_is_typing && ctx->line[0] != '/') + if (ctx->line[0] != '/') set_typingstatus(self, m, 1); - } else { /* if (!ltr) */ - if (line_info_onKey(self, key)) - return; + return; + } - if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key */ - if (ctx->pos > 0) { - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); - del_char_buf_bck(ctx); + if (line_info_onKey(self, key)) + return; - if (x <= 0) { - ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0; - int new_x = ctx->start == 0 ? ctx->pos : x2 - cur_len; - wmove(self->window, y, new_x); + input_handle(self, key, x, y, x2, y2); + + if (key == '\t') { /* TAB key: auto-completes command */ + if (ctx->len > 1 && ctx->line[0] == '/') { + int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); + + if (diff != -1) { + if (x + diff > x2 - 1) { + wmove(self->window, y, x + diff); + ctx->start += diff; } else { - wmove(self->window, y, x - cur_len); + wmove(self->window, y, x + diff); } + } else beep(); + } else beep(); + + } else if (key == '\n') { + rm_trailing_spaces_buf(ctx); + + uint8_t line[MAX_STR_SIZE]; + + if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) + memset(&line, 0, sizeof(line)); + + if (!string_is_empty(line)) + add_line_to_hist(ctx); + + if (line[0] == '/') { + if (strcmp(line, "/close") == 0) { + kill_chat_window(self, m); + return; + } else if (strncmp(line, "/me ", strlen("/me ")) == 0) { + send_action(self, ctx, m, line + strlen("/me ")); } else { - beep(); + execute(ctx->history, self, m, line, CHAT_COMMAND_MODE); } - } + } else if (!string_is_empty(line)) { + uint8_t selfname[TOX_MAX_NAME_LENGTH]; + uint16_t len = tox_get_self_name(m, selfname); + selfname[len] = '\0'; - else if (key == KEY_DC) { /* DEL key: Remove character at pos */ - if (ctx->pos != ctx->len) - del_char_buf_frnt(ctx); - else - beep(); - } + uint8_t timefrmt[TIME_STR_SIZE]; + get_time_str(timefrmt, sizeof(timefrmt)); - else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */ - if (ctx->pos > 0) { - discard_buf(ctx); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); + line_info_add(self, timefrmt, selfname, NULL, line, OUT_MSG, 0, 0); + + if (!statusbar->is_online || tox_send_message(m, self->num, line, strlen(line)) == 0) { + uint8_t *errmsg = " * Failed to send message."; + line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED); } else { - beep(); + write_to_log(line, selfname, ctx->log, false); } } - else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */ - if (ctx->pos != ctx->len) - kill_buf(ctx); - else - beep(); - } - - else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */ - if (ctx->pos > 0) { - ctx->pos = 0; - ctx->start = 0; - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - } - } - - else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */ - if (ctx->pos != ctx->len) { - ctx->pos = ctx->len; - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - } - - else if (key == KEY_LEFT) { - if (ctx->pos > 0) { - --ctx->pos; - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos])); - - if (x <= 0) { - wmove(self->window, y, x2 - cur_len); - ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0; - ctx->pos = ctx->start + x2 - 1; - } else { - wmove(self->window, y, x - cur_len); - } - } else { - beep(); - } - } - - else if (key == KEY_RIGHT) { - if (ctx->pos < ctx->len) { - ++ctx->pos; - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); - wmove(self->window, y, x + cur_len); - - if (x + cur_len >= x2) - ctx->start += cur_len; - } else { - beep(); - } - } - - else if (key == KEY_UP) { /* fetches previous item in history */ - fetch_hist_item(ctx, MOVE_UP); - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - - else if (key == KEY_DOWN) { /* fetches next item in history */ - fetch_hist_item(ctx, MOVE_DOWN); - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - - else if (key == '\t') { /* TAB key: completes command */ - if (ctx->len > 1 && ctx->line[0] == '/') { - int diff = complete_line(ctx, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); - - if (diff != -1) { - if (x + diff > x2 - 1) { - //int ofst = x + diff - x2; - wmove(self->window, y, x + diff); - ctx->start += x2 / 2; - } else { - wmove(self->window, y, x + diff); - } - } else { - beep(); - } - } else { - beep(); - } - } - - /* RETURN key: Execute command or print line */ - else if (key == '\n') { - rm_trailing_spaces_buf(ctx); - - uint8_t line[MAX_STR_SIZE]; - - if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) - memset(&line, 0, sizeof(line)); - - wclear(ctx->linewin); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - - if (!string_is_empty(line)) - add_line_to_hist(ctx); - - if (line[0] == '/') { - if (strcmp(line, "/close") == 0) { - if (ctx->self_is_typing) - set_typingstatus(self, m, 0); - - kill_chat_window(self); - return; - } else if (strncmp(line, "/me ", strlen("/me ")) == 0) { - send_action(self, ctx, m, line + strlen("/me ")); - } else { - execute(ctx->history, self, m, line, CHAT_COMMAND_MODE); - } - } else if (!string_is_empty(line)) { - uint8_t selfname[TOX_MAX_NAME_LENGTH]; - uint16_t len = tox_get_self_name(m, selfname); - selfname[len] = '\0'; - - uint8_t timefrmt[TIME_STR_SIZE]; - get_time_str(timefrmt, sizeof(timefrmt)); - - line_info_add(self, timefrmt, selfname, NULL, line, OUT_MSG, 0, 0); - - if (!statusbar->is_online || tox_send_message(m, self->num, line, strlen(line)) == 0) { - uint8_t *errmsg = " * Failed to send message."; - line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED); - } else { - write_to_log(line, selfname, ctx->log, false); - } - } - - reset_buf(ctx); - } + wclear(ctx->linewin); + wmove(self->window, y2 - CURS_Y_OFFSET, 0); + reset_buf(ctx); } if (ctx->len <= 0 && ctx->self_is_typing) @@ -863,16 +746,8 @@ static void chat_onDraw(ToxWindow *self, Tox *m) curs_set(1); - if (ctx->len > 0) { - uint8_t line[MAX_STR_SIZE]; - - if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) { - reset_buf(ctx); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - } else { - mvwprintw(ctx->linewin, 1, 0, "%s", &line[ctx->start]); - } - } + if (ctx->len > 0) + mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]); /* Draw status bar */ StatusBar *statusbar = self->stb; diff --git a/src/friendlist.c b/src/friendlist.c index 13cff65..c2ed77d 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -58,7 +58,7 @@ static struct _pendingDel { WINDOW *popup; } pendingdelete; -#define S_WEIGHT 100 +#define S_WEIGHT 100000 static int index_name_cmp(const void *n1, const void *n2) { diff --git a/src/groupchat.c b/src/groupchat.c index 4a70000..90e3ec4 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -21,7 +21,7 @@ */ #ifndef _GNU_SOURCE -#define _GNU_SOURCE /* needed for strcasestr() and wcwidth() */ +#define _GNU_SOURCE /* needed for strcasestr() */ #endif #include @@ -39,6 +39,7 @@ #include "log.h" #include "line_info.h" #include "settings.h" +#include "input.h" extern char *DATA_FILE; @@ -393,199 +394,80 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (x2 <= 0) return; - int cur_len = 0; /* widechar len of current char */ - int x2_is_odd = x2 % 2 != 0; - if (ltr) { /* char is printable */ - if (ctx->len < MAX_STR_SIZE - 1) { - add_char_to_buf(ctx, key); - cur_len = MAX(1, wcwidth(key)); - wmove(self->window, y, x + cur_len); + input_new_char(self, key, x, y, x2, y2); + return; + } - if (x + cur_len >= x2) - ctx->start += cur_len; - } - } else { /* if (!ltr) */ + if (line_info_onKey(self, key)) + return; - if (line_info_onKey(self, key)) - return; + if (input_handle(self, key, x, y, x2, y2)) + return; - if (key == 0x107 || key == 0x8 || key == 0x7f) { /* BACKSPACE key */ - if (ctx->pos > 0) { - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); - del_char_buf_bck(ctx); + if (key == '\t') { /* TAB key: auto-completes peer name or command */ + if (ctx->len > 0) { + int diff; - if (x <= 0) { - ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0; - int new_x = ctx->start == 0 ? ctx->pos : x2 - cur_len; - wmove(self->window, y, new_x); - } else { - wmove(self->window, y, x - cur_len); - } - } else { - beep(); - } - } - - else if (key == KEY_DC) { /* DEL key: Remove character at pos */ - if (ctx->pos != ctx->len) - del_char_buf_frnt(ctx); - else - beep(); - } - - else if (key == T_KEY_DISCARD) { /* CTRL-U: Delete entire line behind pos */ - if (ctx->pos > 0) { - discard_buf(ctx); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - } else { - beep(); - } - } - - else if (key == T_KEY_KILL) { /* CTRL-K: Delete entire line in front of pos */ - if (ctx->pos != ctx->len) - kill_buf(ctx); - else - beep(); - } - - else if (key == KEY_HOME || key == T_KEY_C_A) { /* HOME/C-a key: Move cursor to start of line */ - if (ctx->pos > 0) { - ctx->pos = 0; - ctx->start = 0; - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - } - } - - else if (key == KEY_END || key == T_KEY_C_E) { /* END/C-e key: move cursor to end of line */ - if (ctx->pos != ctx->len) { - ctx->pos = ctx->len; - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - } - - else if (key == KEY_LEFT) { - if (ctx->pos > 0) { - --ctx->pos; - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); - - if (x <= 0) { - wmove(self->window, y, x2 - cur_len); - ctx->start = ctx->start >= x2 ? ctx->start - x2 : 0; - ctx->pos = ctx->start + x2 - 1; - } else { - wmove(self->window, y, x - cur_len); - } - } else { - beep(); - } - } - - else if (key == KEY_RIGHT) { - if (ctx->pos < ctx->len) { - ++ctx->pos; - cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); - wmove(self->window, y, x + cur_len); - - if (x + cur_len >= x2) - ctx->start += cur_len; - } else { - beep(); - } - } - - else if (key == KEY_UP) { /* fetches previous item in history */ - fetch_hist_item(ctx, MOVE_UP); - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - - else if (key == KEY_DOWN) { /* fetches next item in history */ - fetch_hist_item(ctx, MOVE_DOWN); - ctx->start = x2 * (ctx->len / x2); - mv_curs_end(self->window, MAX(0, wcswidth(ctx->line, MAX_STR_SIZE)), y2, x2); - } - - else if (key == '\t') { /* TAB key: completes peer name */ - if (ctx->len > 0) { - int diff; - - if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e')) - diff = complete_line(ctx, groupchats[self->num].peer_names, + if ((ctx->line[0] != '/') || (ctx->line[1] == 'm' && ctx->line[2] == 'e')) + diff = complete_line(ctx, groupchats[self->num].peer_names, groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH); + else + diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); + + if (diff != -1) { + if (x + diff > x2 - 1) { + wmove(self->window, y, x + diff); + ctx->start += diff; + } else { + wmove(self->window, y, x + diff); + } + } else beep(); + } else beep(); + } else if (key == T_KEY_C_RB) { /* Scroll peerlist up and down one position */ + int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST; + + if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L) + ++groupchats[self->num].side_pos; + } else if (key == T_KEY_C_LB) { + if (groupchats[self->num].side_pos > 0) + --groupchats[self->num].side_pos; + } else if (key == '\n') { + rm_trailing_spaces_buf(ctx); + + uint8_t line[MAX_STR_SIZE]; + + if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) + memset(&line, 0, sizeof(line)); + + if (!string_is_empty(line)) + add_line_to_hist(ctx); + + if (line[0] == '/') { + if (strcmp(line, "/close") == 0) { + close_groupchat(self, m, self->num); + return; + } else if (strcmp(line, "/help") == 0) { + if (strcmp(line, "help global") == 0) + execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE); else - diff = complete_line(ctx, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); + print_groupchat_help(self); - if (diff != -1) { - if (x + diff > x2 - 1) { - int ofst = (x + diff - 1) - (x2 - 1); - wmove(self->window, y + 1, ofst); - } else { - wmove(self->window, y, x + diff); - } - } else { - beep(); - } + } else if (strncmp(line, "/me ", strlen("/me ")) == 0) { + send_group_action(self, ctx, m, line + strlen("/me ")); } else { - beep(); + execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE); + } + } else if (!string_is_empty(line)) { + if (tox_group_message_send(m, self->num, line, strlen(line)) == -1) { + uint8_t *errmsg = " * Failed to send message."; + line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED); } } - /* Scroll peerlist up and down one position if list overflows window */ - else if (key == T_KEY_C_RB) { - int L = y2 - CHATBOX_HEIGHT - SDBAR_OFST; - - if (groupchats[self->num].side_pos < groupchats[self->num].num_peers - L) - ++groupchats[self->num].side_pos; - } - - else if (key == T_KEY_C_LB) { - if (groupchats[self->num].side_pos > 0) - --groupchats[self->num].side_pos; - } - - /* RETURN key: Execute command or print line */ - else if (key == '\n') { - rm_trailing_spaces_buf(ctx); - - uint8_t line[MAX_STR_SIZE]; - - if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) - memset(&line, 0, sizeof(line)); - - wclear(ctx->linewin); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - - - if (!string_is_empty(line)) - add_line_to_hist(ctx); - - if (line[0] == '/') { - if (strcmp(line, "/close") == 0) { - close_groupchat(self, m, self->num); - return; - } else if (strcmp(line, "/help") == 0) { - if (strcmp(line, "help global") == 0) - execute(ctx->history, self, m, "/help", GLOBAL_COMMAND_MODE); - else - print_groupchat_help(self); - - } else if (strncmp(line, "/me ", strlen("/me ")) == 0) { - send_group_action(self, ctx, m, line + strlen("/me ")); - } else { - execute(ctx->history, self, m, line, GROUPCHAT_COMMAND_MODE); - } - } else if (!string_is_empty(line)) { - if (tox_group_message_send(m, self->num, line, strlen(line)) == -1) { - uint8_t *errmsg = " * Failed to send message."; - line_info_add(self, NULL, NULL, NULL, errmsg, SYS_MSG, 0, RED); - } - } - - reset_buf(ctx); - } + wclear(ctx->linewin); + wmove(self->window, y2 - CURS_Y_OFFSET, 0); + reset_buf(ctx); } } @@ -603,16 +485,8 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m) scrollok(ctx->history, 0); curs_set(1); - if (ctx->len > 0) { - uint8_t line[MAX_STR_SIZE]; - - if (wcs_to_mbs_buf(line, ctx->line, MAX_STR_SIZE) == -1) { - reset_buf(ctx); - wmove(self->window, y2 - CURS_Y_OFFSET, 0); - } else { - mvwprintw(ctx->linewin, 1, 0, "%s", &line[ctx->start]); - } - } + if (ctx->len > 0) + mvwprintw(ctx->linewin, 1, 0, "%ls", &ctx->line[ctx->start]); wclear(ctx->sidebar); mvwhline(ctx->linewin, 0, 0, ACS_HLINE, x2); diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..3dc9ad4 --- /dev/null +++ b/src/input.c @@ -0,0 +1,278 @@ +/* input.c + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* needed for wcwidth() */ +#endif + +#include + +#include "toxic.h" +#include "windows.h" +#include "misc_tools.h" +#include "toxic_strings.h" +#include "line_info.h" + +/* add a char to input field and buffer */ +void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->len >= MAX_STR_SIZE - 1) { + beep(); + return; + } + + int cur_len = wcwidth(key); + + /* this is the only place we need to do this check */ + if (cur_len == -1) + return; + + add_char_to_buf(ctx, key); + + if (x + cur_len >= mx_x) { + int s_len = wcwidth(ctx->line[ctx->start]); + int cdiff = cur_len - s_len; + ctx->start += 1 + MAX(0, cdiff); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else { + wmove(self->window, y, x + cur_len); + } +} + +/* delete a char via backspace key from input field and buffer */ +static void input_backspace(ToxWindow *self, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos <= 0) { + beep(); + return; + } + + int cur_len = wcwidth(ctx->line[ctx->pos - 1]); + + del_char_buf_bck(ctx); + + int s_len = wcwidth(ctx->line[ctx->start - 1]); + int cdiff = s_len - cur_len; + + if (ctx->start && (x >= mx_x - cur_len)) { + ctx->start = MAX(0, ctx->start - 1 + cdiff); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else if (ctx->start && (ctx->pos == ctx->len)) { + ctx->start = MAX(0, ctx->start - cur_len); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else if (ctx->start) { + ctx->start = MAX(0, ctx->start - cur_len); + } else { + wmove(self->window, y, x - cur_len); + } +} + +/* delete a char via delete key from input field and buffer */ +static void input_delete(ToxWindow *self) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos >= ctx->len) { + beep(); + return; + } + + del_char_buf_frnt(ctx); +} + +/* deletes entire line before cursor from input field and buffer */ +static void input_discard(ToxWindow *self, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos <= 0) { + beep(); + return; + } + + discard_buf(ctx); + wmove(self->window, mx_y - CURS_Y_OFFSET, 0); +} + +/* deletes entire line after cursor from input field and buffer */ +static void input_kill(ChatContext *ctx) +{ + if (ctx->pos != ctx->len) { + kill_buf(ctx); + return; + } + + beep(); +} + +/* moves cursor/line position to end of line in input field and buffer */ +static void input_mv_end(ToxWindow *self, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + ctx->pos = ctx->len; + + int wlen = wcswidth(ctx->line, sizeof(ctx->line)); + ctx->start = MAX(0, 1 + (mx_x * (wlen / mx_x) - mx_x) + (wlen % mx_x)); + + int llen = wcswidth(&ctx->line[ctx->start], mx_x); + int new_x = wlen >= mx_x ? mx_x - 1 : llen; + + wmove(self->window, y, new_x); +} + +/* moves cursor/line position to start of line in input field and buffer */ +static void input_mv_home(ToxWindow *self, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos <= 0) { + beep(); + return; + } + + ctx->pos = 0; + ctx->start = 0; + wmove(self->window, mx_y - CURS_Y_OFFSET, 0); +} + +/* moves cursor/line position left in input field and buffer */ +static void input_mv_left(ToxWindow *self, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos <= 0) { + beep(); + return; + } + + int cur_len = wcwidth(ctx->line[ctx->pos - 1]); + + --ctx->pos; + + int s_len = wcwidth(ctx->line[ctx->start - 1]); + int cdiff = s_len - cur_len; + + if (ctx->start && (x >= mx_x - cur_len)) { + ctx->start = MAX(0, ctx->start - 1 + cdiff); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else if (ctx->start && (ctx->pos == ctx->len)) { + ctx->start = MAX(0, ctx->start - cur_len); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else if (ctx->start) { + ctx->start = MAX(0, ctx->start - cur_len); + } else { + wmove(self->window, y, x - cur_len); + } +} + +/* moves cursor/line position right in input field and buffer */ +static void input_mv_right(ToxWindow *self, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + if (ctx->pos >= ctx->len) { + beep(); + return; + } + + ++ctx->pos; + + int cur_len = MAX(1, wcwidth(ctx->line[ctx->pos - 1])); + + if (x + cur_len >= mx_x) { + int s_len = wcwidth(ctx->line[ctx->start]); + int cdiff = cur_len - s_len; + ctx->start += 1 + MAX(0, cdiff); + wmove(self->window, y, wcswidth(&ctx->line[ctx->start], mx_x)); + } else { + wmove(self->window, y, x + cur_len); + } +} + +/* puts a line history item in input field and buffer */ +static void input_history(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y) +{ + ChatContext *ctx = self->chatwin; + + fetch_hist_item(ctx, key); + ctx->start = mx_x * (ctx->len / mx_x); + input_mv_end(self, x, y, mx_x, mx_y); +} + +/* Handles non-printable input keys that behave the same for all types of chat windows. + return true if key matches a function, false otherwise */ +bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y) +{ + bool match = true; + + switch (key) { + case KEY_BACKSPACE: + input_backspace(self, x, y, mx_x, mx_y); + break; + + case KEY_DC: + input_delete(self); + break; + + case T_KEY_DISCARD: + input_discard(self, mx_y); + break; + + case T_KEY_KILL: + input_kill(self->chatwin); + break; + + case KEY_HOME: + case T_KEY_C_A: + input_mv_home(self, mx_y); + break; + + case KEY_END: + case T_KEY_C_E: + input_mv_end(self, x, y, mx_x, mx_y); + break; + + case KEY_LEFT: + input_mv_left(self, x, y, mx_x, mx_y); + break; + + case KEY_RIGHT: + input_mv_right(self, x, y, mx_x, mx_y); + break; + + case KEY_UP: + case KEY_DOWN: + input_history(self, key, x, y, mx_x, mx_y); + break; + + default: + match = false; + break; + } + + return match; +} diff --git a/src/input.h b/src/input.h new file mode 100644 index 0000000..1d4f40d --- /dev/null +++ b/src/input.h @@ -0,0 +1,33 @@ +/* input.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#ifndef _input_h +#define _input_h + +/* add a char to input field and buffer for given chatcontext */ +void input_new_char(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y); + +/* Handles non-printable input keys that behave the same for all types of chat windows. + return true if key matches a function, false otherwise */ +bool input_handle(ToxWindow *self, wint_t key, int x, int y, int mx_x, int mx_y); + +#endif /* #define _input_h */ \ No newline at end of file diff --git a/src/misc_tools.c b/src/misc_tools.c index b78af80..bc0d19f 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -188,13 +188,6 @@ int valid_nick(uint8_t *nick) return 1; } -/* Moves cursor to the end of the line in given window */ -void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x) -{ - int new_x = len < max_x ? len : len % max_x; - wmove(w, max_y - CURS_Y_OFFSET, new_x); -} - /* gets base file name from path or original file name if no path is supplied */ void get_file_name(uint8_t *namebuf, uint8_t *pathname) { diff --git a/src/misc_tools.h b/src/misc_tools.h index 622c746..797a1f2 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -79,9 +79,6 @@ int qsort_strcasecmp_hlpr(const void *nick1, const void *nick2); - must not contain contiguous spaces */ int valid_nick(uint8_t *nick); -/* Moves the cursor to the end of the line in given window */ -void mv_curs_end(WINDOW *w, size_t len, int max_y, int max_x); - /* gets base file name from path or original file name if no path is supplied */ void get_file_name(uint8_t *namebuf, uint8_t *pathname); diff --git a/src/prompt.c b/src/prompt.c index f172c34..f4d4126 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -195,7 +195,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) else if (key == KEY_UP) { /* fetches previous item in history */ wmove(ctx->history, ctx->orig_y, X_OFST); - fetch_hist_item(ctx, MOVE_UP); + fetch_hist_item(ctx, KEY_UP); /* adjust line y origin appropriately when window scrolls down */ if (ctx->at_bottom && ctx->len >= x2 - X_OFST) { @@ -215,7 +215,7 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) else if (key == KEY_DOWN) { /* fetches next item in history */ wmove(ctx->history, ctx->orig_y, X_OFST); - fetch_hist_item(ctx, MOVE_DOWN); + fetch_hist_item(ctx, KEY_DOWN); } else if (key == '\t') { /* TAB key: completes command */ diff --git a/src/toxic.h b/src/toxic.h index 1d5c52d..c4bed27 100644 --- a/src/toxic.h +++ b/src/toxic.h @@ -35,7 +35,7 @@ #define UNKNOWN_NAME "Anonymous" #define MAX_FRIENDS_NUM 500 -#define MAX_STR_SIZE 1024 +#define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH #define MAX_CMDNAME_SIZE 64 #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ #define KEY_IDENT_DIGITS 2 /* number of hex digits to display for the pub-key based identifier */ @@ -54,11 +54,6 @@ #define T_KEY_C_F 0x06 /* ctrl-f */ #define T_KEY_C_H 0x08 /* ctrl-h */ -enum { - MOVE_UP, - MOVE_DOWN, -} KEY_DIRS; - typedef enum _FATAL_ERRS { FATALERR_MEMORY = -1, /* malloc() or calloc() failed */ FATALERR_FREAD = -2, /* fread() failed on critical read */ diff --git a/src/toxic_strings.c b/src/toxic_strings.c index c405d03..3f186da 100644 --- a/src/toxic_strings.c +++ b/src/toxic_strings.c @@ -149,7 +149,7 @@ void add_line_to_hist(ChatContext *ctx) resets line if at end of history */ void fetch_hist_item(ChatContext *ctx, int key_dir) { - if (key_dir == MOVE_UP) { + if (key_dir == KEY_UP) { if (--ctx->hst_pos < 0) { ctx->hst_pos = 0; beep(); @@ -247,8 +247,8 @@ int complete_line(ChatContext *ctx, const void *list, int n_items, int size) wcscpy(ctx->line, newbuf); - ctx->len += (size_t) diff; - ctx->pos += (size_t) diff; + ctx->len += diff; + ctx->pos += diff; return diff; } diff --git a/src/windows.h b/src/windows.h index ec8dc09..6bf9f06 100644 --- a/src/windows.h +++ b/src/windows.h @@ -166,9 +166,9 @@ struct infobox { /* chat and groupchat window/buffer holder */ struct ChatContext { wchar_t line[MAX_STR_SIZE]; - size_t pos; - size_t len; - size_t start; /* the position to start printing line at */ + int pos; + int len; + int start; /* the position to start printing line at */ wchar_t ln_history[MAX_LINE_HIST][MAX_STR_SIZE]; /* history for input lines/commands */ int hst_pos;