From eb055ef1bfc3160fe3a0ff53bde1b45a2a333b5f Mon Sep 17 00:00:00 2001 From: Chris Michael Date: Fri, 12 Dec 2014 15:09:42 -0500 Subject: [PATCH] start on appending text to the grid (version 2) ;) Signed-off-by: Chris Michael --- src/bin/channel.c | 67 +--- src/bin/grid.c | 902 ++++++++++++++++++++++++++++++++++++++++++++-- src/bin/grid.h | 11 + 3 files changed, 894 insertions(+), 86 deletions(-) diff --git a/src/bin/channel.c b/src/bin/channel.c index 90c0756..d29cd35 100644 --- a/src/bin/channel.c +++ b/src/bin/channel.c @@ -10,8 +10,6 @@ struct _Channel const char *name; const char *server; - Eina_Binbuf *buff; - Evas *evas; Evas_Object *o_base; Evas_Object *o_bg; @@ -30,34 +28,6 @@ struct _Channel Eina_Bool missed : 1; }; -/* local functions */ -static int -_find_crlf(const unsigned char *data, int length, int *lf) -{ - int i = 0; - - *lf = 0; - for (; i < length; i++) - { - /* find crlf (\r\n) */ - if ((data[i] == 0x0D) && - (i < (length - 1)) && (data[i + 1] == 0x0A)) - { - *lf = 2; - return i; - } - - /* find just lf */ - if (data[i] == 0x0A) - { - *lf = 1; - return i; - } - } - - return -1; -} - static void _cb_theme_reload(Channel *chl) { @@ -181,8 +151,6 @@ _channel_create(Evas *evas, const char *name, const char *server) chl->evas = evas; - chl->buff = eina_binbuf_new(); - /* store channel name */ if (name) chl->name = eina_stringshare_add(name); @@ -249,8 +217,6 @@ _channel_destroy(Channel *chl) /* delete channel server name */ if (chl->server) eina_stringshare_del(chl->server); - if (chl->buff) eina_binbuf_free(chl->buff); - /* free allocated channel structure */ free(chl); } @@ -488,40 +454,15 @@ _channel_spacer_create(Channel *chl) void _channel_text_append(Channel *chl, const char *txt) { - int len = 0, crlf = 0, lf = 0; + fprintf(stderr, "Channel %s Append: %s", chl->name, txt); - if (!eina_binbuf_append_length(chl->buff, (void *)txt, strlen(txt))) return; - - len = eina_binbuf_length_get(chl->buff); - while (len > 0) - { - const unsigned char *str; - - str = eina_binbuf_string_get(chl->buff); - - crlf = _find_crlf(str, len, &lf); - if (crlf > 0) - { - char buff[crlf + lf + 1]; - - memcpy(buff, str, crlf + lf); - buff[crlf + lf] = '\0'; - - fprintf(stderr, "Channel %s Append: %s", chl->name, buff); - - /* TODO: write buff to grid */ - - eina_binbuf_remove(chl->buff, 0, crlf + lf); - } - else - break; - - len = eina_binbuf_length_get(chl->buff); - } + /* write buff to grid */ + _grid_text_append(chl->o_grid, txt, strlen(txt)); } void _channel_window_set(Channel *chl, Evas_Object *win) { _grid_window_set(chl->o_grid, win); + _grid_theme_set(chl->o_grid, chl->o_bg); } diff --git a/src/bin/grid.c b/src/bin/grid.c index 0020e03..f99e459 100644 --- a/src/bin/grid.c +++ b/src/bin/grid.c @@ -1,10 +1,14 @@ #include "private.h" #include "grid.h" #include "grid_save.h" +#include "colors.h" +#include "utils.h" #include "config.h" /* local function prototypes */ static void _smart_size(Evas_Object *obj, int w, int h, Eina_Bool force); +static void _smart_queue_update(Evas_Object *obj, Grid *sd); +Grid_Cell *_cellrow_get(Grid *sd, int y, int *wret); /* local variables */ static Evas_Smart *_smart = NULL; @@ -41,6 +45,32 @@ _cb_mouse_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, evas_object_smart_callback_call(data, "options", NULL); } +static void +_cb_mouse_wheel(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) +{ + Evas_Event_Mouse_Wheel *ev; + Grid *sd; + + ev = event; + + /* skip horizontal scrolling */ + if (ev->direction) return; + + if (evas_key_modifier_is_set(ev->modifiers, "Control")) return; + if (evas_key_modifier_is_set(ev->modifiers, "Alt")) return; + if (evas_key_modifier_is_set(ev->modifiers, "Shift")) return; + + if (!(sd = evas_object_smart_data_get(data))) return; + + sd->scroll -= (ev->z * 4); + if (sd->scroll > sd->backscroll_num) + sd->scroll = sd->backscroll_num; + else if (sd->scroll < 0) + sd->scroll = 0; + + _smart_queue_update(data, sd); +} + static void _cb_key_down(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event) { @@ -103,6 +133,8 @@ _smart_add(Evas_Object *obj) /* TODO: finish callbacks */ evas_object_event_callback_add(sd->o_event, EVAS_CALLBACK_MOUSE_DOWN, _cb_mouse_down, obj); + evas_object_event_callback_add(sd->o_event, EVAS_CALLBACK_MOUSE_WHEEL, + _cb_mouse_wheel, obj); evas_object_event_callback_add(sd->o_event, EVAS_CALLBACK_KEY_DOWN, _cb_key_down, obj); } @@ -121,7 +153,7 @@ _smart_del(Evas_Object *obj) if (sd->delayed_size_tmr) ecore_timer_del(sd->delayed_size_tmr); /* delete animator */ - /* if (sd->anim) ecore_animator_del(sd->anim); */ + if (sd->anim) ecore_animator_del(sd->anim); /* delete objects */ if (sd->grid.obj) evas_object_del(sd->grid.obj); @@ -133,6 +165,8 @@ _smart_del(Evas_Object *obj) if (sd->cells2) free(sd->cells2); if (sd->cells) free(sd->cells); + if (sd->buff) free(sd->buff); + _parent_sc.del(obj); } @@ -203,6 +237,145 @@ _smart_init(void) _smart = evas_smart_class_new(&sc); } +static void +_smart_apply(Evas_Object *obj) +{ + Grid *sd; + Evas_Coord ox, oy, ow, oh; + int x, y, w;// h; + int ch1 = 0, ch2 = 0, inv = 0; + + if (!(sd = evas_object_smart_data_get(obj))) return; + + evas_object_geometry_get(obj, &ox, &oy, &ow, &oh); + + inv = sd->state.reverse; + _grid_save_freeze(); + for (y = 0; y < sd->grid.h; y++) + { + Grid_Cell *cells; + Evas_Textgrid_Cell *tc; + + w = 0; + cells = _cellrow_get(sd, y - sd->scroll, &w); + tc = evas_object_textgrid_cellrow_get(sd->grid.obj, y); + if (!tc) continue; + ch1 = -1; + for (x = 0; x < sd->grid.w; x++) + { + if ((!cells) || (x >= w)) + { + if ((tc[x].codepoint != 0) || + (tc[x].bg != COL_INVIS) || (tc[x].bg_extended)) + { + if (ch1 < 0) ch1 = x; + ch2 = x; + } + tc[x].codepoint = 0; + if (inv) tc[x].bg = COL_INVERSEBG; + else tc[x].bg = COL_INVIS; + tc[x].bg_extended = 0; + tc[x].double_width = 0; + tc[x].underline = 0; + tc[x].strikethrough = 0; + } + else + { + /* TODO: handle block id */ + + if (cells[x].att.invisible) + { + if ((tc[x].codepoint != 0) || + (tc[x].bg != COL_INVIS) || (tc[x].bg_extended)) + { + if (ch1 < 0) ch1 = x; + ch2 = x; + } + tc[x].codepoint = 0; + if (inv) tc[x].bg = COL_INVERSEBG; + else tc[x].bg = COL_INVIS; + tc[x].bg_extended = 0; + tc[x].underline = 0; + tc[x].strikethrough = 0; +#if defined(SUPPORT_DBLWIDTH) + tc[x].double_width = cells[x].att.dblwidth; +#endif + if ((tc[x].double_width) && (tc[x].codepoint == 0) && + (ch2 == x - 1)) + ch2 = x; + } + else + { + int fg, bg, fgext, bgext, codepoint; + + // colors + fg = cells[x].att.fg; + bg = cells[x].att.bg; + fgext = cells[x].att.fg256; + bgext = cells[x].att.bg256; + codepoint = cells[x].codepoint; + + if ((fg == COL_DEF) && (cells[x].att.inverse ^ inv)) + fg = COL_INVERSEBG; + if (bg == COL_DEF) + { + if (cells[x].att.inverse ^ inv) + bg = COL_INVERSE; + else if (!bgext) + bg = COL_INVIS; + } + if ((cells[x].att.fgintense) && (!fgext)) fg += 48; + if ((cells[x].att.bgintense) && (!bgext)) bg += 48; + if (cells[x].att.inverse ^ inv) + { + int t; + + t = fgext; fgext = bgext; bgext = t; + t = fg; fg = bg; bg = t; + } + if ((cells[x].att.bold) && (!fgext)) fg += 12; + if ((cells[x].att.faint) && (!fgext)) fg += 24; + if ((tc[x].codepoint != codepoint) || + (tc[x].fg != fg) || (tc[x].bg != bg) || + (tc[x].fg_extended != fgext) || + (tc[x].bg_extended != bgext) || + (tc[x].underline != cells[x].att.underline) || + (tc[x].strikethrough != cells[x].att.strike)) + { + if (ch1 < 0) ch1 = x; + ch2 = x; + } + tc[x].fg_extended = fgext; + tc[x].bg_extended = bgext; + tc[x].underline = cells[x].att.underline; + tc[x].strikethrough = cells[x].att.strike; + tc[x].fg = fg; + tc[x].bg = bg; + tc[x].codepoint = codepoint; +#if defined(SUPPORT_DBLWIDTH) + tc[x].double_width = cells[x].att.dblwidth; +#endif + if ((tc[x].double_width) && (tc[x].codepoint == 0) && + (ch2 == x - 1)) + ch2 = x; + // cells[x].att.italic // never going 2 support + // cells[x].att.blink + // cells[x].att.blink2 + } + } + } + + evas_object_textgrid_cellrow_set(sd->grid.obj, y, tc); + + /* only bothering to keep 1 change span per row - not worth doing + * more really */ + if (ch1 >= 0) + evas_object_textgrid_update_add(sd->grid.obj, ch1, y, + ch2 - ch1 + 1, 1); + } + _grid_save_thaw(); +} + static void _smart_size(Evas_Object *obj, int w, int h, Eina_Bool force) { @@ -234,25 +407,155 @@ _smart_size(Evas_Object *obj, int w, int h, Eina_Bool force) _grid_resize(obj, w, h); _smart_calculate(obj); + _smart_apply(obj); evas_event_thaw(sd->evas); } +static Eina_Bool +_smart_change(void *data) +{ + Evas_Object *obj; + Grid *sd; + + obj = data; + if (!(sd = evas_object_smart_data_get(obj))) return EINA_FALSE; + + sd->anim = NULL; + + _smart_apply(obj); + + return EINA_FALSE; +} + static void -_grid_cell_copy(Grid *sd, Grid_Cell *src, Grid_Cell *dst, int n) +_smart_queue_update(Evas_Object *obj, Grid *sd) +{ + if (sd->anim) return; + sd->anim = ecore_animator_add(_smart_change, obj); +} + +static void +_codepoint_overwrite_heavy(Grid *sd EINA_UNUSED, int oldc, int newc) +{ + int ido = 0, idn = 0; + + if (oldc & 0x80000000) ido = (oldc >> 18) & 0x1fff; + if (newc & 0x80000000) idn = (newc >> 18) & 0x1fff; + if (((oldc & 0x80000000) && (newc & 0x80000000)) && (idn == ido)) + return; + + /* TODO: Commented out until we support blocks */ + /* if (oldc & 0x80000000) */ + /* { */ + + /* } */ + + /* if (newc & 0x80000000) */ + /* { */ + + /* } */ +} + +static inline void +_codepoint_overwrite(Grid *sd, Eina_Unicode oldc, Eina_Unicode newc) +{ + if (!((oldc | newc) & 0x80000000)) return; + _codepoint_overwrite_heavy(sd, oldc, newc); +} + +Grid_Cell * +_cellrow_get(Grid *sd, int y, int *wret) +{ + Grid_Save *gs, **gssrc; + + if (y >= 0) + { + if (y > sd->h) return NULL; + *wret = sd->w; + return &(GRID_CELLS(sd, 0, y)); + } + if ((y < -sd->backmax) || (!sd->back)) return NULL; + gssrc = &(sd->back[(sd->backmax + sd->backpos + y) % sd->backmax]); + gs = _grid_save_extract(*gssrc); + if (!gs) return NULL; + *gssrc = gs; + *wret = gs->w; + return gs->cell; +} + +static void +_cell_copy(Grid *sd, Grid_Cell *src, Grid_Cell *dst, int n) { int i = 0; for (; i < n; i++) { - /* TODO */ - /* _handle_block_codepoint_overwrite(sd, dst[i].codepoint, src[i].codepoint); */ + _codepoint_overwrite(sd, dst[i].codepoint, src[i].codepoint); dst[i] = src[i]; } } static void -_grid_limit_coord(Grid *sd, Grid_State *state) +_cell_codepoint_att_fill(Grid *sd, Eina_Unicode codepoint, Grid_Att att, Grid_Cell *dst, int n) +{ + Grid_Cell local = { .codepoint = codepoint, .att = att }; + int i; + + for (i = 0; i < n; i++) + { + _codepoint_overwrite(sd, dst[i].codepoint, codepoint); + dst[i] = local; + } +} + +static void +_cell_fill(Grid *sd, Grid_Cell *src, Grid_Cell *dst, int n) +{ + int i; + + if (src) + { + for (i = 0; i < n; i++) + { + _codepoint_overwrite(sd, dst[i].codepoint, src[0].codepoint); + dst[i] = src[0]; + } + } + else + { + for (i = 0; i < n; i++) + { + _codepoint_overwrite(sd, dst[i].codepoint, 0); + memset(&(dst[i]), 0, sizeof(*dst)); + } + } +} + +static void +_cells_swap(Grid *sd) +{ + Grid_Cell *tmp; + int tmp_circular_offset; + + tmp = sd->cells; + sd->cells =sd->cells2; + sd->cells2 = tmp; + + if (sd->altbuf) + sd->state = sd->swap; + else + sd->swap = sd->state; + + tmp_circular_offset = sd->circular_offset; + sd->circular_offset = sd->circular_offset2; + sd->circular_offset2 = tmp_circular_offset; + + sd->altbuf = !sd->altbuf; +} + +static void +_limit_coord(Grid *sd, Grid_State *state) { state->wrapnext = 0; if (state->cx >= sd->w) state->cx = sd->w - 1; @@ -262,7 +565,7 @@ _grid_limit_coord(Grid *sd, Grid_State *state) } ssize_t -_grid_line_length(const Grid_Cell *cells, ssize_t nb_cells) +_line_length(const Grid_Cell *cells, ssize_t nb_cells) { ssize_t len = nb_cells; @@ -279,7 +582,7 @@ _grid_line_length(const Grid_Cell *cells, ssize_t nb_cells) } static int -_grid_line_find_top(Grid *sd, int y_end, int *top) +_line_find_top(Grid *sd, int y_end, int *top) { int y_start = y_end; @@ -316,7 +619,7 @@ _grid_line_find_top(Grid *sd, int y_end, int *top) } static int -_grid_line_rewrap(Grid *sd, int y_start, int y_end, Grid_Cell *cells2, Grid_Save **back2, int w2, int y2_end, int *new_y2_start) +_line_rewrap(Grid *sd, int y_start, int y_end, Grid_Cell *cells2, Grid_Save **back2, int w2, int y2_end, int *new_y2_start, int *new_cyp) { int x, x2, y, y2, y2_start; int len, len_last, len_remaining, copy_width, ts2_width; @@ -324,7 +627,7 @@ _grid_line_rewrap(Grid *sd, int y_start, int y_end, Grid_Cell *cells2, Grid_Save Grid_Cell *line, *line2 = NULL; if (y_end >= 0) - len_last = _grid_line_length(&GRID_CELLS(sd, 0, y_end), sd->w); + len_last = _line_length(&GRID_CELLS(sd, 0, y_end), sd->w); else { gs = _grid_save_extract(sd->back[(y_end + sd->backpos + @@ -391,9 +694,13 @@ _grid_line_rewrap(Grid *sd, int y_start, int y_end, Grid_Cell *cells2, Grid_Save back2[y2 + sd->backmax] = gs2; } } + if (y == sd->state.cy) + { + *new_cyp = y2_start; + } if (line2) { - _grid_cell_copy(sd, line + x, line2 + x2, copy_width); + _cell_copy(sd, line + x, line2 + x2, copy_width); x += copy_width; x2 += copy_width; len_remaining -= copy_width; @@ -412,6 +719,463 @@ _grid_line_rewrap(Grid *sd, int y_start, int y_end, Grid_Cell *cells2, Grid_Save return 0; } +static void +_scroll(Grid *sd, int direction, int start_y EINA_UNUSED, int end_y EINA_UNUSED) +{ + if (sd->scroll > 0) + { + sd->scroll -= direction; + if (sd->scroll > sd->backscroll_num) + sd->scroll = sd->backscroll_num; + } + + /* if (sd->selection.active) */ + /* { */ + /* if ((start_y <= sd->selection.start.y) && */ + /* (end_y >= sd->selection.end.y)) */ + /* { */ + + /* } */ + /* } */ +} + +static void +_text_clear(Grid *sd, Grid_Cell *cells, int count, int val, Eina_Bool inherit_att) +{ + Grid_Cell src; + + memset(&src, 0, sizeof(src)); + src.codepoint = val; + if (inherit_att) src.att = sd->state.att; + _cell_fill(sd, &src, cells, count); +} + +static void +_text_save_top(Grid *sd, Grid_Cell *cells, ssize_t w_max) +{ + Grid_Save *gs; + ssize_t w; + + if (sd->backmax <= 0) return; + + _grid_save_freeze(); + + w = _line_length(cells, w_max); + gs = _grid_save_new(w); + if (!gs) return; + + _cell_copy(sd, cells, gs->cell, w); + + if (!sd->back) + sd->back = calloc(1, sizeof(Grid_Cell *) * sd->backmax); + + if (sd->back[sd->backpos]) + { + _grid_save_free(sd->back[sd->backpos]); + sd->back[sd->backpos] = NULL; + } + + sd->back[sd->backpos] = gs; + sd->backpos++; + if (sd->backpos >= sd->backmax) sd->backpos = 0; + sd->backscroll_num++; + if (sd->backscroll_num >= sd->backmax) + sd->backscroll_num = sd->backmax; + + _grid_save_thaw(); +} + +static void +_text_scroll(Grid *sd, Eina_Bool clear) +{ + Grid_Cell *cells, *cells2 = NULL; + int y, start_y = 0, end_y = sd->h - 1; + + if (sd->state.scroll_y2 != 0) + { + start_y = sd->state.scroll_y1; + end_y = sd->state.scroll_y2 - 1; + } + else + { + if (!sd->altbuf) + _text_save_top(sd, &(GRID_CELLS(sd, 0, 0)), sd->w); + } + + _scroll(sd, 1, start_y, end_y); + + if ((start_y == 0) && (end_y = (sd->h - 1))) + { + cells = &(sd->cells[sd->circular_offset * sd->w]); + if (clear) + _text_clear(sd, cells, sd->w, 0, EINA_TRUE); + sd->circular_offset++; + if (sd->circular_offset >= sd->h) + sd->circular_offset = 0; + } + else + { + cells = &(GRID_CELLS(sd, 0, end_y)); + for (y = start_y; y < end_y; y++) + { + cells = &(GRID_CELLS(sd, 0, (y + 1))); + cells2 = &(GRID_CELLS(sd, 0, y)); + _cell_copy(sd, cells, cells2, sd->w); + } + if (clear) + _text_clear(sd, cells, sd->w, 0, EINA_TRUE); + } +} + +static void +_text_scroll_test(Grid *sd, Eina_Bool clear) +{ + int e; + + e = sd->h; + + if (sd->state.scroll_y2 != 0) e = sd->state.scroll_y2; + if (sd->state.cy >= e) + { + _text_scroll(sd, clear); + sd->state.cy = (e - 1); + } +} + +static void +_cursor_handle(Grid *sd, const Eina_Unicode *cc) +{ + switch (*cc) + { + case 0x0a: // LF '\n' (new line); + if (sd->state.had_cr) + { + GRID_CELLS(sd, sd->state.had_cr_x, + sd->state.had_cr_y).att.newline = 1; + } + sd->state.had_cr = 0; + sd->state.wrapnext = 0; + if (sd->state.crlf) sd->state.cx = 0; + sd->state.cy++; + _text_scroll_test(sd, EINA_FALSE); // NB: Was EINA_TRUE + return; + case 0x0d: // CR '\r' (carriage return) + if (sd->state.cx != 0) + { + sd->state.had_cr_x = sd->state.cx; + sd->state.had_cr_y = sd->state.cy; + sd->state.wrapnext = 0; + } + sd->state.cx = 0; + sd->state.had_cr = 1; + return; + default: + break; + } +} + +static void +_text_append(Grid *sd, const Eina_Unicode *codepoints, int len) +{ + Grid_Cell *cells; + int i, j; + + cells = &(GRID_CELLS(sd, 0, sd->state.cy)); + for (i = 0; i < len; i++) + { + Eina_Unicode g; + + if (sd->state.wrapnext) + { + cells[sd->w - 1].att.autowrapped = 1; + sd->state.wrapnext = 0; + sd->state.cx = 0; + sd->state.cy++; + _text_scroll_test(sd, EINA_FALSE); + cells = &(GRID_CELLS(sd, 0, sd->state.cy)); + } + + if (sd->state.insert) + { + for (j = (sd->w - 1); j > sd->state.cx; j--) + _cell_copy(sd, &(cells[j - 1]), &(cells[j]), 1); + } + + g = _util_charset_translate(codepoints[i], &sd->state); + + _cell_codepoint_att_fill(sd, g, sd->state.att, + &(cells[sd->state.cx]), 1); + +#if defined(SUPPORT_DBLWIDTH) + cells[sd->state.cx].att.dblwidth = _util_dblwidth_get(sd, g); + if (EINA_UNLIKELY((cells[sd->state.cx].att.dblwidth) && + (sd->state.cx < (sd->w - 1)))) + { + GRID_FMTCLR(cells[sd->state.cx].att); + _cell_codepoint_att_fill(sd, 0, cells[sd->state.cx].att, + &(cells[sd->state.cx + 1]), 1); + } +#endif + if (sd->state.wrap) + { + unsigned char offset = 1; + + sd->state.wrapnext = 0; +#if defined(SUPPORT_DBLWIDTH) + if (EINA_UNLIKELY(cells[sd->state.cx].att.dblwidth)) + offset = 2; +#endif + if (EINA_UNLIKELY(sd->state.cx >= (sd->w - offset))) + sd->state.wrapnext = 1; + else + sd->state.cx += offset; + } + else + { + unsigned char offset = 1; + + sd->state.wrapnext = 0; +#if defined(SUPPORT_DBLWIDTH) + if (EINA_UNLIKELY(cells[sd->state.cx].att.dblwidth)) + offset = 2; +#endif + sd->state.cx += offset; + if (sd->state.cx > (sd->w - offset)) + { + sd->state.cx = sd->w - offset; + return; + } + } + } +} + +static int +_seq_handle(Grid *sd, Eina_Unicode *c, Eina_Unicode *ce) +{ + Eina_Unicode *cc; + int len = 0; + + if (c[0] < 0x20) + { + switch (c[0]) + { + case 0x0a: // LF '\n' (new line); + case 0x0d: // CR '\r' (carriage return) + _cursor_handle(sd, c); + return 1; + default: + sd->state.had_cr = 0; + return 1; + } + } + else + sd->state.had_cr = 0; + + cc = (int *)c; + while ((cc < ce) && (*cc >= 0x20) && (*cc != 0x7f)) + { + cc++; + len++; + } + + _text_append(sd, c, len); + + sd->state.had_cr = 0; + return len; +} + +static void +_buffer_handle(Grid *sd, const Eina_Unicode *codepoints, int len) +{ + Eina_Unicode *c, *ce, *b; + int n, bytes; + + c = (Eina_Unicode *)codepoints; + ce = &(c[len]); + + if (sd->buff) + { + bytes = (sd->bufflen + len + 1) * sizeof(int); + b = realloc(sd->buff, bytes); + if (!b) + { + ERR("Memerr: %s", strerror(errno)); + return; + } + bytes = len * sizeof(Eina_Unicode); + memcpy(&(b[sd->bufflen]), codepoints, bytes); + sd->buff = b; + sd->bufflen += len; + sd->buff[sd->bufflen] = 0; + + c = sd->buff; + ce = c + sd->bufflen; + while (c < ce) + { + n = _seq_handle(sd, c, ce); + if (n == 0) + { + Eina_Unicode *tmp; + + tmp = sd->buff; + sd->buff = NULL; + sd->bufflen = 0; + bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode); + sd->buff = malloc(bytes); + if (!sd->buff) + { + ERR("Memerr: %s", strerror(errno)); + return; + } + bytes = (char *)ce - (char *)c; + memcpy(sd->buff, c, bytes); + sd->bufflen = bytes / sizeof(Eina_Unicode); + sd->buff[sd->bufflen] = 0; + free(tmp); + break; + } + c += n; + } + + if (c == ce) + { + if (sd->buff) + { + free(sd->buff); + sd->buff = NULL; + } + sd->bufflen = 0; + } + } + else + { + while (c < ce) + { + n = _seq_handle(sd, c, ce); + if (n == 0) + { + bytes = ((char *)ce - (char *)c) + sizeof(Eina_Unicode); + sd->buff = malloc(bytes); + if (!sd->buff) + { + ERR("Memerr: %s", strerror(errno)); + } + else + { + bytes = (char *)ce - (char *)c; + memcpy(sd->buff, c, bytes); + sd->bufflen = bytes / sizeof(Eina_Unicode); + sd->buff[sd->bufflen] = 0; + } + break; + } + c += n; + } + } +} + +static void +_att_reset(Grid_Att *att) +{ + att->fg = COL_DEF; + att->bg = COL_DEF; + att->bold = 0; + att->faint = 0; +#if defined(SUPPORT_ITALIC) + att->italic = 0; +#elif defined(SUPPORT_DBLWIDTH) + att->dblwidth = 0; +#endif + att->underline = 0; + att->blink = 0; + att->blink2 = 0; + att->inverse = 0; + att->invisible = 0; + att->strike = 0; + att->fg256 = 0; + att->bg256 = 0; + att->fgintense = 0; + att->bgintense = 0; + att->autowrapped = 0; + att->newline = 0; + att->tab = 0; + att->fraktur = 0; +} + +static void +_state_reset(Grid *sd) +{ + sd->state.cx = 0; + sd->state.cy = 0; + sd->state.scroll_y1 = 0; + sd->state.scroll_y2 = 0; + sd->state.had_cr_x = 0; + sd->state.had_cr_y = 0; + _att_reset(&(sd->state.att)); + sd->state.charset = 0; + sd->state.charsetch = 'B'; + sd->state.chset[0] = 'B'; + sd->state.chset[1] = 'B'; + sd->state.chset[2] = 'B'; + sd->state.chset[3] = 'B'; + sd->state.multibyte = 0; + sd->state.alt_kp = 0; + sd->state.insert = 0; + sd->state.appcursor = 0; + sd->state.wrap = 1; + sd->state.wrapnext = 0; + sd->state.hidecursor = 0; + sd->state.crlf = 0; + sd->state.had_cr = 0; + /* sd->mouse_mode = MOUSE_OFF; */ + /* sd->mouse_ext = MOUSE_EXT_NONE; */ + /* sd->bracketed_paste = 0; */ + + _grid_save_freeze(); + if (sd->back) + { + int i; + + for (i = 0; i < sd->backmax; i++) + if (sd->back[i]) _grid_save_free(sd->back[i]); + free(sd->back); + sd->back = NULL; + } + sd->backscroll_num = 0; + sd->backpos = 0; + if (sd->backmax) + sd->back = calloc(1, sizeof(Grid_Save *) * sd->backmax); + _grid_save_thaw(); +} + +static void +_backscroll_set(Grid *sd, int size) +{ + int i; + + if (sd->backmax == size) return; + + _grid_save_freeze(); + + if (sd->back) + { + for (i = 0; i < sd->backmax; i++) + if (sd->back[i]) _grid_save_free(sd->back[i]); + free(sd->back); + } + + if (size > 0) + sd->back = calloc(1, sizeof(Grid_Save *) * size); + else + sd->back = NULL; + + sd->backscroll_num = 0; + sd->backpos = 0; + sd->backmax = size; + + _grid_save_thaw(); +} + /* external functions */ Evas_Object * _grid_add(Evas *evas) @@ -429,15 +1193,17 @@ _grid_add(Evas *evas) sd->w = 80; sd->h = 24; + _state_reset(sd); + sd->save = sd->state; + sd->swap = sd->state; + sd->cells = calloc(1, sizeof(Grid_Cell) * sd->w * sd->h); if (!sd->cells) goto err; sd->cells2 = calloc(1, sizeof(Grid_Cell) * sd->w * sd->h); if (!sd->cells2) goto err; - _grid_update(obj); - - _smart_size(obj, sd->w, sd->h, EINA_FALSE); + _smart_size(obj, sd->w, sd->h, EINA_TRUE); _grid_save_register(obj); @@ -476,8 +1242,17 @@ _grid_update(Evas_Object *obj) sd->font.size = _ex_cfg->font.size; + _backscroll_set(sd, _ex_cfg->gui.scrollback); + sd->scroll = 0; + + _colors_init(sd->grid.obj, sd->o_theme); + evas_object_scale_set(sd->grid.obj, elm_config_scale_get()); evas_object_textgrid_font_set(sd->grid.obj, sd->font.name, sd->font.size); + evas_object_textgrid_size_get(sd->grid.obj, &w, &h); + if (w < 1) w = 1; + if (h < 1) h = 1; + evas_object_textgrid_size_set(sd->grid.obj, w, h); evas_object_textgrid_cell_size_get(sd->grid.obj, &w, &h); if (w < 1) w = 1; @@ -499,6 +1274,16 @@ _grid_window_set(Evas_Object *obj, Evas_Object *win) sd->win = win; } +void +_grid_theme_set(Evas_Object *obj, Evas_Object *theme) +{ + Grid *sd; + + /* try to get the objects smart data */ + if (!(sd = evas_object_smart_data_get(obj))) return; + sd->o_theme = theme; +} + void _grid_resize(Evas_Object *obj, int nw, int nh) { @@ -506,6 +1291,7 @@ _grid_resize(Evas_Object *obj, int nw, int nh) Grid_Cell *new_cells = NULL; Grid_Save **new_back = NULL; int y_start, y_end, new_y_start = 0, new_y_end, i; + int altbuf = 0, new_cy; /* try to get the objects smart data */ if (!(sd = evas_object_smart_data_get(obj))) return; @@ -513,8 +1299,16 @@ _grid_resize(Evas_Object *obj, int nw, int nh) if ((sd->w == nw) && (sd->h == nh)) return; if ((nw == nh) && (nw == 1)) return; + new_cy = sd->state.cy; + _grid_save_freeze(); + if (sd->altbuf) + { + _cells_swap(sd); + altbuf = 1; + } + new_cells = calloc(1, sizeof(Grid_Cell) * nw * nh); if (!new_cells) goto err; @@ -528,10 +1322,9 @@ _grid_resize(Evas_Object *obj, int nw, int nh) new_y_end = nh - 1; while ((y_end >= -sd->backscroll_num) && (new_y_end >= -sd->backmax)) { - if (_grid_line_find_top(sd, y_end, &y_start) < 0) goto err; - if (_grid_line_rewrap(sd, y_start, y_end, new_cells, - new_back, nw, new_y_end, - &new_y_start) < 0) + if (_line_find_top(sd, y_end, &y_start) < 0) goto err; + if (_line_rewrap(sd, y_start, y_end, new_cells, + new_back, nw, new_y_end, &new_y_start, &new_cy) < 0) goto err; y_end = y_start - 1; new_y_end = new_y_start - 1; @@ -546,18 +1339,17 @@ _grid_resize(Evas_Object *obj, int nw, int nh) sd->w = nw; sd->h = nh; - sd->state.cy = MIN((nh - 1) - new_y_start, nh - 1); - sd->state.cx = _grid_line_length(new_cells + ((nh - 1) * nw), nw); sd->circular_offset = MAX(new_y_start, 0); sd->backpos = 0; sd->backscroll_num = MAX(-new_y_start, 0); sd->state.had_cr = 0; + sd->state.cy = (new_cy + nh - sd->circular_offset) % nh; - /* if (altbuf) termpty_screen_swap(ty); */ + if (altbuf) _cells_swap(sd); - _grid_limit_coord(sd, &(sd->state)); - _grid_limit_coord(sd, &(sd->swap)); - _grid_limit_coord(sd, &(sd->save)); + _limit_coord(sd, &(sd->state)); + _limit_coord(sd, &(sd->swap)); + _limit_coord(sd, &(sd->save)); _grid_save_thaw(); @@ -568,3 +1360,67 @@ err: free(new_cells); free(new_back); } + +void +_grid_text_append(Evas_Object *obj, const char *txt, int len) +{ + Grid *sd; + char buff[len]; + Eina_Unicode codepoint[len]; + int i = 0, j = 0, k = 0; + +// fprintf(stdout, "Append Len: %d\n", len); + + /* try to get the objects smart data */ + if (!(sd = evas_object_smart_data_get(obj))) return; + + /* copy txt into a buffer we can manipulate */ + memcpy(buff, txt, len); + buff[len] = 0;//'\0'; + +// fprintf(stdout, "BUFFER: [START]%s[END]", buff); +// fprintf(stdout, "\tLen: %zu\n", strlen(buff)); + + for (i = 0; i < (int)sizeof(sd->oldbuff); i++) + sd->oldbuff[i] = 0; + + for (i = 0; i < len;) + { + int g = 0, prev_i = i; + + if (buff[i]) + { +#if (EINA_VERSION_MAJOR > 1) || (EINA_VERSION_MINOR >= 8) + g = eina_unicode_utf8_next_get(buff, &i); + if ((0xdc80 <= g) && (g <= 0xdcff) && + (len - prev_i) <= (int)sizeof(sd->oldbuff)) +#else + i = evas_string_char_next_get(buff, i, &g); + if (i < 0 && + (len - prev_i) <= (int)sizeof(sd->oldbuff)) +#endif + { + for (k = 0; (k < (int)sizeof(sd->oldbuff)) && + (k < (len - prev_i)); k++) + { + sd->oldbuff[k] = buff[prev_i + k]; + } + DBG("failure at %d/%d/%d", prev_i, i, len); + break; + } + } + else + { + g = 0; + i++; + } + codepoint[j] = g; + j++; + } + + codepoint[j] = 0; + + _buffer_handle(sd, codepoint, j); + + _smart_queue_update(obj, sd); +} diff --git a/src/bin/grid.h b/src/bin/grid.h index 281758a..213d6e7 100644 --- a/src/bin/grid.h +++ b/src/bin/grid.h @@ -109,9 +109,15 @@ struct _Grid Evas *evas; Evas_Object *win; Evas_Object *o_event; + Evas_Object *o_theme; int w, h; + int *buff; + int bufflen; + unsigned char oldbuff[4]; + + int scroll; int circular_offset, circular_offset2; int backmax, backpos, backscroll_num; @@ -136,13 +142,18 @@ struct _Grid Eina_Bool active : 1; } selection; + unsigned int altbuf : 1; + + Ecore_Animator *anim; Ecore_Timer *delayed_size_tmr; }; Evas_Object *_grid_add(Evas *evas); void _grid_update(Evas_Object *obj); void _grid_window_set(Evas_Object *obj, Evas_Object *win); +void _grid_theme_set(Evas_Object *obj, Evas_Object *theme); void _grid_resize(Evas_Object *obj, int nw, int nh); +void _grid_text_append(Evas_Object *obj, const char *txt, int len); #define GRID_CELLS(SD, X, Y) \ SD->cells[X + (((Y + SD->circular_offset) % SD->h) * SD->w)]