]> git.neil.brown.name Git - edlib.git/blobdiff - lib-renderline.c
TODO: clean out done items.
[edlib.git] / lib-renderline.c
index 5cbaa2a26b11227ac2d4ca3a83101af46652ad9e..e5d8169aaa951529a5b7c839ac2d17df2eeff07e 100644 (file)
@@ -63,7 +63,6 @@
  *                       recognised has "wrap-" stripped and is used for the
  *                       head and tail. Default is fg:blue,underline
  *  hide               - Text is hidden if cursor is not within range.
- *                       NOT YET IMPLEMENTED
  *
  * "nn" is measured in "points" which is 1/10 the nominal width of chars
  * in the default font size, which is called "10".  A positive value is
@@ -96,7 +95,7 @@ struct render_item {
                                 * it.
                                 */
        uint8_t         hide;   /* This and consecutive render_items
-                                * with the same hide nmber form a
+                                * with the same hide number form a
                                 * hidden extent which is visible when
                                 * the cursor is in it.
                                 */
@@ -129,6 +128,7 @@ struct rline_data {
        char            *wrap_head, *wrap_tail, *wrap_attr;
        int             head_length, tail_length;
        char            *line safe;
+       char            *background;
        bool            word_wrap;
        bool            image;
        int             curspos;
@@ -255,8 +255,8 @@ static void parse_line(struct rline_data *rd safe)
                         * which should leave either a trailing comma, or an
                         * empty string.
                         */
-                       buf_append(&attr, ',');
                        old_len = attr.len;
+                       buf_append(&attr, ',');
                        foreach_attr(a, v, st, line) {
                                if (amatch(a, "centre") || amatch(a, "center") ||
                                    amatch(a, "ctab")) {
@@ -315,9 +315,9 @@ static void parse_line(struct rline_data *rd safe)
                        /* strip one more ',' */
                        if (attr.len > 0)
                                attr.len -= 1;
-                       if (attr.len <= wrap_depth)
+                       if (wrap && attr.len <= wrap_depth)
                                wrap = 0;
-                       if (attr.len <= hide_depth)
+                       if (hide && attr.len <= hide_depth)
                                hide = 0;
                        break;
                case ack:
@@ -364,7 +364,7 @@ static inline struct call_return do_measure(struct pane *p safe,
                                            int splitpos, int len,
                                            int maxwidth)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        struct call_return cr;
        char tb[] = "        ";
        char *str = rd->line + ri->start + splitpos;
@@ -403,7 +403,7 @@ static inline struct call_return measure_str(struct pane *p safe,
                                             char *str safe,
                                             const char *attr)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
 
        return call_ret(all, "Draw:text-size", p,
                        -1, NULL, str,
@@ -416,7 +416,7 @@ static inline void do_draw(struct pane *p safe,
                           int offset,
                           int x, int y)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        char tmp;
        char *str;
        int len;
@@ -472,7 +472,7 @@ static inline void draw_wrap(struct pane *p safe,
                             char *str safe,
                             int x, int y)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
 
        home_call(focus, "Draw:text", p,
                  -1, NULL, str,
@@ -515,9 +515,9 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
         * 3 if both.
         * 0 if neither
         */
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        struct render_item *ri, *wraprl;
-       int shift_left = pane_attr_get_int(focus, "shift_left", 0);
+       int shift_left = pane_attr_get_int(focus, "render-wrap", -1);
        bool wrap = shift_left < 0;
        int wrap_margin;
        int right_margin;
@@ -529,6 +529,7 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
        int x, y;
        int ret = 0;
        bool seen_rtab = False;
+       unsigned int offset_hide = 0;
 
        if (!rd->content)
                return ret;
@@ -537,6 +538,8 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
            offset == rd->measure_offset) {
                /* No change */
                for (ri = rd->content ; ri ; ri = ri->next) {
+                       if (ri->hidden)
+                               continue;
                        if (ri->eol && rd->line[ri->start] == '\n')
                                ret |= 1;
                        if (ri->eol && rd->line[ri->start] == '\f')
@@ -569,7 +572,20 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
        /* 0 means right edge for right_margin, and left edge for all others */
        right_margin = p->w - calc_pos(-rd->right_margin, p->w, rd->curs_width);
 
+       if (offset >= 0)
+               for (ri = rd->content ; ri ; ri = ri->next)
+                       if (offset < ri->start + ri->len) {
+                               offset_hide = ri->hide;
+                               break;
+                       }
+
+       rd->width = 0;
        for (ri = rd->content; ri; ri = ri->next) {
+               ri->hidden = (ri->hide && ri->hide != offset_hide);
+               if (ri->hidden) {
+                       ri->width = 0;
+                       continue;
+               }
                if (ri->len == 0 ||
                    (unsigned char)rd->line[ri->start] >= ' ') {
                        cr = do_measure(p, ri, 0, -1, -1);
@@ -598,7 +614,7 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
                if (cr.i2 > rd->ascent)
                        rd->ascent = cr.i2;
                ri->width = ri->eol ? 0 : cr.x;
-               ri->hidden = False;
+               rd->width += ri->width;
 
                if (ri->start <= offset && offset <= ri->start + ri->len) {
                        cr = measure_str(p, "M", ri->attr);
@@ -614,19 +630,20 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
         */
        x = left_margin - (shift_left > 0 ? shift_left : 0);
        y = rd->space_above * curs_height / 10;
-       rd->width = 0;
        for (ri = rd->content; ri; ri = ri->next) {
                int w, margin;
                struct render_item *ri2;
                ri->y = y;
+               if (ri->hidden) {
+                       ri->x = x;
+                       continue;
+               }
                if (ri->tab != TAB_UNSET)
                        x =  left_margin + calc_pos(ri->tab,
                                                    right_margin - left_margin,
                                                    rd->curs_width);
                if (ri->eol) {
                        /* EOL */
-                       if (x > rd->width)
-                               rd->width = x;
                        ri->x = x;
                        x = 0; /* Don't include shift. probably not margin */
                        if (rd->line[ri->start])
@@ -680,6 +697,8 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
        wrap_margin = left_margin + rd->head_length;
        for (ri = rd->content ; wrap && ri ; ri = ri->next) {
                int splitpos;
+               if (ri->hidden)
+                       continue;
                if (ri->wrap && (wraprl == NULL || ri->wrap != wraprl->wrap))
                        wraprl = ri;
                if (ri->wrap_margin)
@@ -806,12 +825,12 @@ static int measure_line(struct pane *p safe, struct pane *focus safe, int offset
 
 static void draw_line(struct pane *p safe, struct pane *focus safe, int offset)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        struct render_item *ri;
        char *wrap_tail = rd->wrap_tail ?: "\\";
        char *wrap_head = rd->wrap_head ?: "";
 
-       home_call(focus, "Draw:clear", p);
+       home_call(focus, "Draw:clear", p, 0, NULL, rd->background);
 
        if (!rd->content)
                return;
@@ -866,13 +885,15 @@ static int find_xy(struct pane *p safe, struct pane *focus safe,
         * We do not consider the eol render_item
         */
        struct call_return cr;
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        struct render_item *r, *ri = NULL;
        int splitpos = 0;
        int start = 0;
 
        for (r = rd->content; r ; r = r->next) {
                int split;
+               if (r->hidden)
+                       continue;
                if (r->y <= y && r->x <= x) {
                        ri = r;
                        start = r->start;
@@ -895,8 +916,22 @@ static int find_xy(struct pane *p safe, struct pane *focus safe,
        cr = do_measure(p, ri, splitpos, -1, x - ri->x);
        if ((splitpos ? ri->wrap_x : ri->x ) + cr.x > x &&
            ri->y + rd->line_height * (1 + splitpos) > y &&
-           xyattr)
-               *xyattr = ri->attr;
+           xyattr) {
+               /* This is a bit of a hack.
+                * We stick the x,y co-ords of the start
+                * of the current attr in front of the
+                * attrs so render-lines can provide a
+                * good location for a menu
+                */
+               char buf[100];
+               struct render_item *ri2;
+               int ax = ri->x;
+               for (ri2 = rd->content; ri2 != ri; ri2 = ri2->next)
+                       if (strcmp(ri2->attr, ri->attr) == 0)
+                               ax = ri2->x;
+               snprintf(buf, sizeof(buf), "%dx%d,", ax, y);
+               *xyattr = strconcat(p, buf, ri->attr);
+       }
        if (cr.s)
                return cr.s - rd->line;
        return start + cr.i;
@@ -908,10 +943,12 @@ static struct xy find_curs(struct pane *p safe, int offset, const char **cursatt
        struct xy xy = {0,0};
        int split;
        int st;
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        struct render_item *r, *ri = NULL;
 
        for (r = rd->content; r; r = r->next) {
+               if (r->hidden)
+                       continue;
                if (offset < r->start)
                        break;
                ri = r;
@@ -996,7 +1033,7 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
                        int dodraw,
                        int offset, int want_xypos, short x, short y)
 {
-       struct rline_data *rd = &p->data;
+       struct rline_data *rd = p->data;
        char *fname = NULL;
        const char *orig_line = line;
        short width, height;
@@ -1006,6 +1043,7 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
        struct xy xyscale = pane_scale(focus);
        int scale = xyscale.x;
        struct xy size= {-1, -1};
+       char mode[30] = "";
        const char *a, *v;
        const char *end;
 
@@ -1059,6 +1097,9 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
                         */
                        map_offset = v - orig_line;
                        parse_map(v, &rows, &cols);
+                       if (rows > 0 && cols > 0)
+                               snprintf(mode, sizeof(mode),
+                                        ":%dx%d", cols, rows);
                }
        }
        pane_resize(p, (p->parent->w - width)/2, p->y, width, height);
@@ -1092,8 +1133,8 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
        }
 
        if (fname && dodraw)
-               home_call(focus, "Draw:image", p, 5, NULL, fname,
-                         0, NULL, NULL, cols, rows);
+               home_call(focus, "Draw:image", p, 0, NULL, fname,
+                         0, NULL, mode);
 
        free(fname);
 
@@ -1110,7 +1151,7 @@ static int render_image(struct pane *p safe, struct pane *focus safe,
 
 DEF_CMD(renderline_draw)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        struct xy xy;
        int offset = -1;
 
@@ -1133,7 +1174,7 @@ DEF_CMD(renderline_draw)
 
 DEF_CMD(renderline_refresh)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        int offset = -1;
 
        if (rd->curspos >= 0)
@@ -1150,7 +1191,7 @@ DEF_CMD(renderline_refresh)
 
 DEF_CMD(renderline_measure)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        int ret;
 
        if (rd->image)
@@ -1179,7 +1220,7 @@ DEF_CMD(renderline_measure)
 
 DEF_CMD(renderline_findxy)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        const char *xyattr = NULL;
        int pos;
 
@@ -1203,7 +1244,7 @@ DEF_CMD(renderline_findxy)
 
 DEF_CMD(renderline_get)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        char buf[20];
        const char *val = buf;
 
@@ -1268,16 +1309,18 @@ static char *cvt(char *str safe)
 
 DEF_CMD(renderline_set)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        const char *old = rd->line;
        char *prefix = pane_attr_get(ci->focus, "prefix");
        bool word_wrap = pane_attr_get_int(ci->focus, "word-wrap", 0) != 0;
+       bool bg_changed = False;
 
        if (!ci->str)
                return -Enoarg;
        if (prefix)
-               prefix = cvt(strconcat(ci->home, "<bold>", prefix, "</>"));
-
+               prefix = strconcat(ci->home, ACK SOH "bold" STX,
+                                  prefix, // No mark in prefix!
+                                  ETX);
        if (prefix)
                rd->line = strconcat(NULL, prefix, ci->str);
        else
@@ -1285,8 +1328,22 @@ DEF_CMD(renderline_set)
        rd->prefix_bytes = strlen(prefix?:"");
        cvt(rd->line + rd->prefix_bytes);
 
+       if (ci->str2 && !rd->background) {
+               rd->background = strdup(ci->str2);
+               bg_changed = True;
+       } else if (!ci->str2 && rd->background) {
+               free(rd->background);
+               rd->background = NULL;
+               bg_changed = True;
+       } else if (ci->str2 && rd->background &&
+                  strcmp(ci->str2, rd->background) != 0) {
+               free(rd->background);
+               rd->background = strdup(ci->str2);
+               bg_changed = True;
+       }
+
        rd->curspos = ci->num;
-       if (strcmp(rd->line, old) != 0 ||
+       if (strcmp(rd->line, old) != 0 || bg_changed ||
            (old && word_wrap != rd->word_wrap)) {
                pane_damaged(ci->home, DAMAGED_REFRESH);
                pane_damaged(ci->home->parent, DAMAGED_REFRESH);
@@ -1298,9 +1355,9 @@ DEF_CMD(renderline_set)
        return 1;
 }
 
-DEF_CMD(renderline_close)
+DEF_CMD_CLOSED(renderline_close)
 {
-       struct rline_data *rd = &ci->home->data;
+       struct rline_data *rd = ci->home->data;
        struct render_item *ri = rd->content;
 
        free((void*)rd->line);
@@ -1314,6 +1371,7 @@ DEF_CMD(renderline_close)
        aupdate(&rd->wrap_head, NULL);
        aupdate(&rd->wrap_tail, NULL);
        aupdate(&rd->wrap_attr, NULL);
+       aupdate(&rd->background, NULL);
        return 1;
 }
 
@@ -1334,13 +1392,12 @@ DEF_CMD(renderline_attach)
                key_add(rl_map, "get-attr", &renderline_get);
                key_add(rl_map, "render-line:set", &renderline_set);
                key_add(rl_map, "Close", &renderline_close);
-               key_add(rl_map, "Free", &edlib_do_free);
        }
 
        p = pane_register(ci->focus, ci->num, &renderline_handle.c);
        if (!p)
                return Efail;
-       rd = &p->data;
+       rd = p->data;
        rd->line = strdup(ETX); // Imposible string
 
        return comm_call(ci->comm2, "cb", p);