Merge branch 't/gui_improvements'
[paraslash.git] / gui.c
diff --git a/gui.c b/gui.c
index 7bb74e6f484a2ab0731f77a121b95d06af1b2c93..096beb93bfd82f91a68c454779edaa6c59e8a565 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -10,6 +10,7 @@
 #include <signal.h>
 #include <sys/types.h>
 #include <curses.h>
+#include <locale.h>
 #include <sys/time.h>
 
 #include "gui.cmdline.h"
@@ -312,11 +313,18 @@ static void add_spaces(WINDOW* win, unsigned int num)
 static int align_str(WINDOW* win, char *str, unsigned int len,
                unsigned int align)
 {
-       int i, num; /* of spaces */
+       int ret, i, num; /* of spaces */
+       size_t width;
 
        if (!win || !str)
-               return -1;
-       num = len - strlen(str);
+               return 0;
+       ret = strwidth(str, &width);
+       if (ret < 0) {
+               PARA_ERROR_LOG("%s\n", para_strerror(-ret));
+               width = 0;
+               str[0] = '\0';
+       }
+       num = len - width;
        if (num < 0) {
                str[len] = '\0';
                num = 0;
@@ -398,11 +406,14 @@ static int first_visible_rbe(unsigned *lines)
        return RINGBUFFER_SIZE - 1;
 }
 
+/*
+returns number of first visible rbe, *lines is the number of lines drawn.
+ */
 static int draw_top_rbe(unsigned *lines)
 {
-       unsigned len;
-       int offset, fvr = first_visible_rbe(lines);
+       int ret, fvr = first_visible_rbe(lines);
        struct rb_entry *rbe;
+       size_t bytes_to_skip, cells_to_skip, width;
 
        if (fvr < 0)
                return -1;
@@ -410,16 +421,22 @@ static int draw_top_rbe(unsigned *lines)
        rbe = ringbuffer_get(bot_win_rb, fvr);
        if (!rbe)
                return -1;
-       len = strlen(rbe->msg);
        if (*lines > bot.lines) {
-               /* first rbe is only partially visible */
-               offset = (*lines - bot.lines) * bot.cols;
-               assert(offset <= len);
-       } else
-               offset = 0;
+               /* rbe is partially visible multi-line */
+               cells_to_skip = (*lines - bot.lines) * bot.cols;
+               ret = skip_cells(rbe->msg, cells_to_skip, &bytes_to_skip);
+               if (ret < 0)
+                       return ret;
+               ret = strwidth(rbe->msg + bytes_to_skip, &width);
+               if (ret < 0)
+                       return ret;
+       } else {
+               bytes_to_skip = 0;
+               width = rbe->len;
+       }
        wattron(bot.win, COLOR_PAIR(rbe->color));
-       waddstr(bot.win, rbe->msg + offset);
-       *lines = NUM_LINES(len - offset);
+       waddstr(bot.win, rbe->msg + bytes_to_skip);
+       *lines = NUM_LINES(width);
        return fvr;
 }
 
@@ -451,10 +468,15 @@ out:
 
 static void rb_add_entry(int color, char *msg)
 {
-       struct rb_entry *old, *new = para_malloc(sizeof(struct rb_entry));
+       struct rb_entry *old, *new;
        int x, y;
+       size_t len;
+
+       if (strwidth(msg, &len) < 0)
+               return;
+       new = para_malloc(sizeof(struct rb_entry));
        new->color = color;
-       new->len = strlen(msg);
+       new->len = len;
        new->msg = msg;
        old = ringbuffer_add(bot_win_rb, new);
 //     fprintf(stderr, "added: %s\n", new->msg);
@@ -982,6 +1004,7 @@ static int do_select(int mode)
        char command_buf[2][COMMAND_BUF_SIZE] = {"", ""};
        int cbo[2] = {0, 0}; /* command buf offsets */
        struct timeval tv;
+       unsigned flags[2] = {0, 0}; /* for for_each_line() */
 
 repeat:
        tv.tv_sec = conf.timeout_arg  / 1000;
@@ -1019,21 +1042,25 @@ repeat:
                                COMMAND_BUF_SIZE - 1 - cbo[i], &rfds, &sz);
                        cbo[i] += sz;
                        sz = cbo[i];
-                       cbo[i] = for_each_line(0, command_buf[i], cbo[i],
+                       cbo[i] = for_each_line(flags[i], command_buf[i], cbo[i],
                                add_output_line, &i);
-                       if (sz != cbo[i])
+                       if (sz != cbo[i]) { /* at least one line found */
                                wrefresh(bot.win);
+                               flags[i] = 0;
+                       }
                        if (ret < 0) {
                                PARA_NOTICE_LOG("closing command fd %d: %s",
                                        i, para_strerror(-ret));
                                close(command_fds[i]);
                                command_fds[i] = -1;
+                               flags[i] = 0;
                                if (command_fds[!i] < 0) /* both fds closed */
                                        return 0;
                        }
                        if (cbo[i] == COMMAND_BUF_SIZE - 1) {
                                PARA_NOTICE_LOG("discarding overlong line");
                                cbo[i] = 0;
+                               flags[i] = FELF_DISCARD_FIRST;
                        }
                }
        }
@@ -1171,7 +1198,7 @@ static void com_scroll_top(void)
                struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
                if (!rbe)
                        break;
-               lines += NUM_LINES(strlen(rbe->msg));
+               lines += NUM_LINES(rbe->len);
        }
        i++;
        if (lines > 0 && scroll_position != i) {
@@ -1202,7 +1229,7 @@ static void com_page_down(void)
                struct rb_entry *rbe = ringbuffer_get(bot_win_rb, i);
                if (!rbe)
                        break;
-               lines += NUM_LINES(strlen(rbe->msg));
+               lines += NUM_LINES(rbe->len);
        }
        if (lines) {
                scroll_position = i;
@@ -1523,6 +1550,7 @@ int main(int argc, char *argv[])
        top.lines = theme.top_lines_default;
        setup_signal_handling();
        bot_win_rb = ringbuffer_new(RINGBUFFER_SIZE);
+       setlocale(LC_CTYPE, "");
        initscr(); /* needed only once, always successful */
        init_curses();
        print_welcome();