]> git.neil.brown.name Git - edlib.git/blobdiff - display-ncurses.c
TODO: clean out done items.
[edlib.git] / display-ncurses.c
index e6aae170e8c6ce441c4bcc3d5290b8814873235c..86995cd44e86ca57bb051f9bc26729dd389e127e 100644 (file)
@@ -441,7 +441,7 @@ DEF_CMD(nc_close_display)
 {
        /* If this is only display, then refuse to close this one */
        struct call_return cr;
-       char *nc = attr_find(ci->home->attrs, "no-close");
+       char *nc = pane_attr_get(ci->home, "no-close");
 
        if (nc) {
                call("Message", ci->focus, 0, NULL, nc);
@@ -463,16 +463,6 @@ DEF_CMD(nc_close_display)
        return 1;
 }
 
-DEF_CMD(nc_set_attr)
-{
-       const char *attr = ci->str2;
-
-       if (!attr)
-               attr = ksuffix(ci, "Display:set:");
-       attr_set_str(&ci->home->attrs, attr, ci->str);
-       return 1;
-}
-
 static int nc_putc(int ch)
 {
        if (current_dd)
@@ -798,7 +788,7 @@ static int to_pair(struct display_data *dd safe, int fg, int bg)
 }
 
 static int cvt_attrs(struct pane *p safe, struct pane *home safe,
-                    const char *attrs, int *pairp safe, bool use_parent)
+                    const char *attrs, int *pairp safe)
 {
        struct display_data *dd = home->data;
        int attr = 0;
@@ -809,10 +799,9 @@ static int cvt_attrs(struct pane *p safe, struct pane *home safe,
        int bg = COLOR_WHITE+8;
 
        set_screen(home);
-       do {
+       while (p->parent != p &&(pan = pane_panel(p, NULL)) == NULL)
                p = p->parent;
-       } while (p->parent != p &&(pan = pane_panel(p, NULL)) == NULL);
-       if (pan && use_parent) {
+       if (pan) {
                /* Get 'default colours for this pane - set at clear */
                int at = getbkgd(panel_window(pan));
                int pair = PAIR_NUMBER(at);
@@ -869,7 +858,7 @@ DEF_CMD(nc_notify_display)
        return 1;
 }
 
-DEF_CMD(nc_close)
+DEF_CMD_CLOSED(nc_close)
 {
        struct pane *p = ci->home;
        struct display_data *dd = p->data;
@@ -920,7 +909,8 @@ DEF_CMD(nc_clear)
        struct display_data *dd = p->data;
        cchar_t cc = {};
        int pair = 0;
-       int attr = cvt_attrs(ci->focus, p, ci->str, &pair, ci->str == NULL);
+       /* default come from parent when clearing pane */
+       int attr = cvt_attrs(ci->focus->parent, p, ci->str, &pair);
        PANEL *panel;
        WINDOW *win;
        int w, h;
@@ -976,7 +966,7 @@ DEF_CMD(nc_draw_text)
 {
        struct pane *p = ci->home;
        int pair = 0;
-       int attr = cvt_attrs(ci->focus, p, ci->str2, &pair, True);
+       int attr = cvt_attrs(ci->focus, p, ci->str2, &pair);
        int cursor_offset = ci->num;
        short x = ci->x, y = ci->y;
        const char *str = ci->str;
@@ -1005,32 +995,124 @@ DEF_CMD(nc_draw_text)
        return 1;
 }
 
+struct di_info {
+       struct command c;
+       MagickWand *wd safe;
+       int x,y,w,h;
+       int xo, yo;
+       struct pane *p safe;
+};
+
+DEF_CB(nc_draw_image_cb)
+{
+       struct di_info *dii = container_of(ci->comm, struct di_info, c);
+       struct display_data *dd = dii->p->data;
+       int i, j;
+       unsigned char *buf;
+
+       switch (ci->key[0]) {
+       case 'w': /* width */
+               return MagickGetImageWidth(dii->wd);
+       case 'h': /* height */
+               return MagickGetImageHeight(dii->wd);
+       case 's': /* scale */
+               MagickResizeImage(dii->wd, ci->num, ci->num2, BoxFilter, 1.0);
+               return 1;
+       case 'c': /* crop or cursor */
+               if (ci->key[1] != 'u') {
+                       /* crop */
+                       dii->x = ci->x;
+                       dii->y = ci->y;
+                       dii->w = ci->num;
+                       dii->h = ci->num2;
+                       return 1;
+               } else {
+                       /* cursor */
+                       /* FIXME this doesn't work because
+                        * render-line knows too much and gets it wrong.
+                        */
+                       ncurses_text(ci->focus, dii->p, 'X', 0,
+                                    to_pair(dd, 0, 0),
+                                    ci->x + dii->xo,
+                                    (ci->y + dii->xo)/2, 1);
+                       return 1;
+               }
+       case 'd': /* draw */
+               if (dii->w <= 0 || dii->h <= 0)
+                       return Efail;
+               buf = malloc(dii->h * dii->w * 4);
+
+               MagickExportImagePixels(dii->wd, dii->x, dii->y,
+                                       dii->w, dii->h,
+                                       "RGBA", CharPixel, buf);
+
+               for (i = 0; i < dii->h; i+= 2) {
+                       static const wint_t hilo = 0x2580; /* L'▀' */
+                       static unsigned char blk[4] = "\0\0\0";
+                       for (j = 0; j < dii->w ; j+= 1) {
+                               unsigned char *p1 = buf + i*dii->w*4 + j*4;
+                               unsigned char *p2 = i + 1 < dii->h ?
+                                       buf + (i+1)*dii->w*4 + j*4 : blk;
+                               int rgb1[3] = { p1[0]*1000/255, p1[1]*1000/255,
+                                              p1[2]*1000/255 };
+                               int rgb2[3] = { p2[0]*1000/255, p2[1]*1000/255,
+                                              p2[2]*1000/255 };
+                               int fg = find_col(dd, rgb1);
+                               int bg = find_col(dd, rgb2);
+
+                               if (p1[3] < 128 || p2[3] < 128) {
+                                       /* transparent */
+                                       cchar_t cc;
+                                       short f,b;
+                                       struct pane *pn2 = ci->focus;
+                                       PANEL *pan = pane_panel(pn2, NULL);
+
+                                       while (!pan && pn2->parent != pn2) {
+                                               pn2 = pn2->parent;
+                                               pan = pane_panel(pn2, NULL);
+                                       }
+                                       if (pan) {
+                                               wgetbkgrnd(panel_window(pan), &cc);
+                                               if (cc.ext_color == 0)
+                                                       /* default.  This is light
+                                                        * gray rather then white,
+                                                        * but I think it is a good
+                                                        * result.
+                                                        */
+                                                       b = COLOR_WHITE;
+                                               else
+                                                       pair_content(cc.ext_color, &f, &b);
+                                               if (p1[3] < 128)
+                                                       fg = b;
+                                               if (p2[3] < 128)
+                                                       bg = b;
+                                       }
+                               }
+                               ncurses_text(ci->focus, dii->p, hilo, 0,
+                                            to_pair(dd, fg, bg),
+                                            ci->num + dii->xo + j,
+                                            (ci->num2 + dii->yo + i)/2,
+                                            0);
+                       }
+               }
+               free(buf);
+               return 1;
+       default:
+               return Efail;
+       }
+}
+
 DEF_CMD(nc_draw_image)
 {
        /* 'str' identifies the image. Options are:
         *     file:filename  - load file from fs
         *     comm:command   - run command collecting bytes
-        * 'num' is '16' if image should be stretched to fill pane
-        * Otherwise it is the 'or' of
-        *   0,1,2 for left/middle/right in x direction
-        *   0,4,8 for top/middle/bottom in y direction
-        * only one of these can be used as image will fill pane
-        * in other direction.
-        * If 'x' and 'y' are both positive, draw cursor box at
-        * p->cx, p->cy of a size so that 'x' will fit across and
-        * 'y' will fit down.
+        * 'str2' and numbers are handled by Draw:scale-image.
         */
        struct pane *p = ci->home;
-       struct display_data *dd = p->data;
-       int x = 0, y = 0;
-       bool stretch = ci->num & 16;
-       int pos = ci->num;
-       int w = ci->focus->w, h = ci->focus->h * 2;
-       int cx = -1, cy = -1;
        MagickBooleanType status;
-       MagickWand *wd;
-       unsigned char *buf;
-       int i, j;
+       MagickWand *wd = NULL;
+       struct di_info dii;
 
        if (!ci->str)
                return Enoarg;
@@ -1044,7 +1126,7 @@ DEF_CMD(nc_draw_image)
        } else if (strstarts(ci->str, "comm:")) {
                struct call_return cr;
                wd = NewMagickWand();
-               cr = call_ret(bytes, ci->str+5, ci->focus, 0, NULL, ci->str2);
+               cr = call_ret(bytes, ci->str+5, ci->focus);
                if (!cr.s) {
                        DestroyMagickWand(wd);
                        return Efail;
@@ -1055,103 +1137,19 @@ DEF_CMD(nc_draw_image)
                        DestroyMagickWand(wd);
                        return Efail;
                }
-       } else
+       }
+
+       if (!wd)
                return Einval;
 
        MagickAutoOrientImage(wd);
-       if (!stretch) {
-               int ih = MagickGetImageHeight(wd);
-               int iw = MagickGetImageWidth(wd);
-
-               if (iw <= 0 || iw <= 0) {
-                       DestroyMagickWand(wd);
-                       return Efail;
-               }
-               if (iw * h > ih * w) {
-                       /* Image is wider than space, use less height */
-                       ih = ih * w / iw;
-                       switch(pos & (8+4)) {
-                       case 4: /* center */
-                               y = (h - ih) / 2; break;
-                       case 8: /* bottom */
-                               y = h - ih; break;
-                       }
-                       /* Keep 'h' even! */
-                       h = ((ih+1)/2) * 2;
-               } else {
-                       /* image is too tall, use less width */
-                       iw = iw * h / ih;
-                       switch (pos & (1+2)) {
-                       case 1: /* center */
-                               x = (w - iw) / 2; break;
-                       case 2: /* right */
-                               x = w - iw ; break;
-                       }
-                       w = iw;
-               }
-       }
-       MagickAdaptiveResizeImage(wd, w, h);
-       buf = malloc(h * w * 4);
-       MagickExportImagePixels(wd, 0, 0, w, h, "RGBA", CharPixel, buf);
-
-       if (ci->x > 0 && ci->y > 0 && ci->focus->cx >= 0) {
-               /* We want a cursor */
-               cx = x + ci->focus->cx;
-               cy = y + ci->focus->cy;
-       }
-       for (i = 0; i < h; i+= 2) {
-               static const wint_t hilo = 0x2580; /* L'▀' */
-               for (j = 0; j < w ; j+= 1) {
-                       unsigned char *p1 = buf + i*w*4 + j*4;
-                       unsigned char *p2 = buf + (i+1)*w*4 + j*4;
-                       int rgb1[3] = { p1[0]*1000/255, p1[1]*1000/255, p1[2]*1000/255 };
-                       int rgb2[3] = { p2[0]*1000/255, p2[1]*1000/255, p2[2]*1000/255 };
-                       int fg = find_col(dd, rgb1);
-                       int bg = find_col(dd, rgb2);
-
-                       if (p1[3] < 128 || p2[3] < 128) {
-                               /* transparent */
-                               cchar_t cc;
-                               short f,b;
-                               struct pane *pn2 = ci->focus;
-                               PANEL *pan = pane_panel(pn2, NULL);
-
-                               while (!pan && pn2->parent != pn2) {
-                                       pn2 = pn2->parent;
-                                       pan = pane_panel(pn2, NULL);
-                               }
-                               if (pan) {
-                                       wgetbkgrnd(panel_window(pan), &cc);
-                                       if (cc.ext_color == 0)
-                                               /* default.  This is light
-                                                * gray rather then white,
-                                                * but I think it is a good
-                                                * result.
-                                                */
-                                               b = COLOR_WHITE;
-                                       else
-                                               pair_content(cc.ext_color, &f, &b);
-                                       if (p1[3] < 128)
-                                               fg = b;
-                                       if (p2[3] < 128)
-                                               bg = b;
-                               }
-                       }
-                       /* FIXME this doesn't work because
-                        * render-line knows too much and gets it wrong.
-                        */
-                       if (cx == x+j && cy == y + (i/2))
-                               ncurses_text(ci->focus, p, 'X', 0,
-                                            to_pair(dd, 0, 0),
-                                            x+j, y+(i/2), 1);
-                       else
-                               ncurses_text(ci->focus, p, hilo, 0,
-                                            to_pair(dd, fg, bg),
-                                            x+j, y+(i/2), 0);
-
-               }
-       }
-       free(buf);
+       dii.c = nc_draw_image_cb;
+       dii.wd = wd;
+       dii.p = p;
+       dii.w = dii.h = dii.x = dii.y = dii.xo = dii.yo = 0;
+       call("Draw:scale-image", ci->focus,
+            ci->num, NULL, NULL, ci->num2, NULL, ci->str2,
+            ci->x, ci->y, &dii.c);
 
        DestroyMagickWand(wd);
 
@@ -1178,7 +1176,7 @@ DEF_CMD(nc_image_size)
        } else if (strstarts(ci->str, "comm:")) {
                struct call_return cr;
                wd = NewMagickWand();
-               cr = call_ret(bytes, ci->str+5, ci->focus, 0, NULL, ci->str2);
+               cr = call_ret(bytes, ci->str+5, ci->focus);
                if (!cr.s) {
                        DestroyMagickWand(wd);
                        return Efail;
@@ -1283,7 +1281,7 @@ DEF_CMD(nc_refresh_post)
                        dest.y, dest.x, destend.y-1, destend.x-1, 0);
        }
        /* place the cursor */
-       p1 = pane_leaf(p);
+       p1 = pane_focus(p);
        pan = NULL;
        while (p1 != p && (pan = pane_panel(p1, NULL)) == NULL)
                p1 = p1->parent;
@@ -1357,6 +1355,8 @@ static struct pane *ncurses_init(struct pane *ed safe,
        dd->scr_file = f;
        dd->is_xterm = (term && strstarts(term, "xterm"));
 
+       attr_set_str(&p->attrs, "Display:pixels", "1x2");
+
        set_screen(p);
 
        ncurses_start(p);
@@ -1406,6 +1406,7 @@ DEF_CMD(force_redraw)
        ncurses_start(p);
 
        clearok(curscr, 1);
+       pane_damaged(p, DAMAGED_POSTORDER);
        return 1;
 }
 
@@ -1802,12 +1803,11 @@ DEF_CMD(display_ncurses)
        if (!term)
                term = "xterm-256color";
 
-       p = ncurses_init(ed, tty, term);
-       if (p)
-               p = call_ret(pane, "editor:activate-display", p);
-       if (p && ci->focus != ed)
-               /* Assume ci->focus is a document */
-               p = home_call_ret(pane, ci->focus, "doc:attach-view", p, 1);
+       p = call_ret(pane, "attach-window-core", ed);
+       if (!p)
+               return Efail;
+
+       p = ncurses_init(p, tty, term);
        if (p)
                return comm_call(ci->comm2, "callback:display", p);
 
@@ -1820,10 +1820,9 @@ void edlib_init(struct pane *ed safe)
                  "attach-display-ncurses");
 
        nc_map = key_alloc();
-       key_add(nc_map, "Display:refresh", &force_redraw);
-       key_add(nc_map, "Display:close", &nc_close_display);
-       key_add_prefix(nc_map, "Display:set:", &nc_set_attr);
-       key_add(nc_map, "Display:external-viewer", &nc_external_viewer);
+       key_add(nc_map, "Window:refresh", &force_redraw);
+       key_add(nc_map, "Window:close", &nc_close_display);
+       key_add(nc_map, "Window:external-viewer", &nc_external_viewer);
        key_add(nc_map, "Close", &nc_close);
        key_add(nc_map, "Draw:clear", &nc_clear);
        key_add(nc_map, "Draw:text-size", &nc_text_size);