From: NeilBrown Date: Fri, 29 Sep 2023 02:59:35 +0000 (+1000) Subject: Move some common code from Draw:image implementations into lib-window X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=a0ee48d984c725a4ab22814488dede6afdf9a10a;p=edlib.git Move some common code from Draw:image implementations into lib-window lib-window now provides Draw:scale-image which is used by Draw:image to interpret the request and provide simple requests for the Drawing engine. pygtk doesn't use this yet. Draw:scale-image should probably parse the file name etc too. This fixes a bug in image display in ncurses where the image isn't centred vertically when it isn't high enough to fill space. Signed-off-by: NeilBrown --- diff --git a/DOC/TODO.md b/DOC/TODO.md index e7e1a65d..d6cd3080 100644 --- a/DOC/TODO.md +++ b/DOC/TODO.md @@ -34,6 +34,7 @@ the file. - [ ] selection-menu item for spell-check ?? - [ ] notmuch - capture errors about multiple Subject lines and display them better. +- [ ] switch display-pygtk to use Draw:scale-image ### Small @@ -56,7 +57,7 @@ the file. ### Large -- [ ] image-display pane +- [X] image-display pane - [ ] git-mode - [ ] render-markdown.py - [X] lib-menu @@ -194,12 +195,19 @@ Core features Module features --------------- +### render-imageview + +- [ ] use a document, not a magic command. This requires multipart + to be able to hand over a document +- [ ] activate from file browser somehow +- [ ] cache the decompressed image somewhere. + ### lib-menubar -- enable activation via F10. Cancel makes it disappear if configed - not too. How to keep?? -- allow left/right arrows to move between menus -- emacs to disable 'save' when cannot be saved. +- [ ] enable activation via F10. Cancel makes it disappear if + configured not too. How to keep?? +- [ ] allow left/right arrows to move between menus +- [ ] emacs to disable 'save' when cannot be saved. ### lib-qrcode @@ -1017,7 +1025,7 @@ Possibly some of these will end up being features in other modules. This might support a menu-bar, or drop-downs for spelling or dynamic completion. - [ ] hex edit block device - mmap document type -- [ ] image-display pane - e.g. can be given a png/jpeg etc file and display +- [X] image-display pane - e.g. can be given a png/jpeg etc file and display it scaled, plus allow scaling and movement - [ ] pdf-display pane - like image-display but with multiple pages. Would use libpoppler. diff --git a/core-window.c b/core-window.c index e763702b..54c7ec25 100644 --- a/core-window.c +++ b/core-window.c @@ -138,6 +138,139 @@ DEF_CMD(selection_discard) return 1; } +DEF_CMD(scale_image) +{ + /* This is a helper for Draw:image which interprets str2 + * with other values and calls comm2 with: + * "width" returns image width + * "height" returns image height + * "scale" num=new width, num2=new height + * "crop" x,y is top-left num,num2 - width,height + * These numbers apply after scaling. + * "draw" num,num2 = offset + * "cursor" x,y=pos, num,num2=size + * + * Inputs are: + * 'str2' container 'mode' information. + * By default the image is placed centrally in the pane + * and scaled to use either fully height or fully width. + * Various letters modify this: + * 'S' - stretch to use full height *and* full width + * 'L' - place on left if full width isn't used + * 'R' - place on right if full width isn't used + * 'T' - place at top if full height isn't used + * 'B' - place at bottom if full height isn't used. + * + * Also a suffix ":NNxNN" will be parse and the two numbers used + * to give number of rows and cols to overlay on the image for + * the purpose of cursor positioning. If these are present and + * p->cx,cy are not negative, draw a cursor at p->cx,cy highlighting + * the relevant cell. + * + * num,num2, if both positive, override the automatic scaling. + * The image is scaled to this many pixels. + * x,y is top-left pixel in the scaled image to start display at. + * Negative values allow a margin between pane edge and this image. + */ + struct pane *p = ci->focus; + const char *mode = ci->str2 ?: ""; + bool stretch = strchr(mode, 'S'); + int w, h; + int x = 0, y = 0; + int pw, ph; + int xo = 0, yo = 0; + int cix, ciy; + const char *pxl; + short px, py; + + if (!ci->comm2) + return Enoarg; + + pxl = pane_attr_get(p, "Display:pixels"); + if (sscanf(pxl ?: "1x1", "%hdx%hx", &px, &py) != 2) + px = py = 1; + + w = p->w * px; + h = p->h * py; + if (ci->num > 0 && ci->num2 > 0) { + w = ci->num; + h = ci->num2; + } else if (ci->num > 0) { + int iw = comm_call(ci->comm2, "width", p); + int ih = comm_call(ci->comm2, "height", p); + + if (iw <= 0 || ih <= 0) + return Efail; + + w = iw * ci->num / 1024; + h = ih * ci->num / 1024; + } else if (!stretch) { + int iw = comm_call(ci->comm2, "width", p); + int ih = comm_call(ci->comm2, "height", p); + + if (iw <= 0 || ih <= 0) + return Efail; + + if (iw * h > ih * w) { + /* Image is wider than space, use less height */ + ih = ih * w / iw; + if (strchr(mode, 'B')) + /* bottom */ + y = h - ih; + else if (!strchr(mode, 'T')) + /* center */ + y = (h - ih) / 2; + /* Round up to pixels-per-cell */ + h = ((ih + py - 1) / py) * py; + } else { + /* image is too tall, use less width */ + iw = iw * h / ih; + if (strchr(mode, 'R')) + /* right */ + x = w - iw; + else if (!strchr(mode, 'L')) + x = (w - iw) / 2; + w = ((iw + px - 1) / px) * px; + } + } + + comm_call(ci->comm2, "scale", p, w, NULL, NULL, h); + pw = p->w * px; + ph = p->h * py; + cix = ci->x; + ciy = ci->y; + if (cix < 0) { + xo -= cix; + pw += cix; + cix = 0; + } + if (ciy < 0) { + yo -= ciy; + ph += ciy; + ciy = 0; + } + if (w - cix <= pw) + w -= cix; + else + w = pw; + if (h - ciy <= ph) + h -= ciy; + else + h = ph; + comm_call(ci->comm2, "crop", p, w, NULL, NULL, h, NULL, NULL, cix, ciy); + comm_call(ci->comm2, "draw", p, x + xo, NULL, NULL, y + yo); + + if (p->cx >= 0) { + int rows, cols; + char *cl = strchr(mode, ':'); + if (cl && sscanf(cl, ":%dx%d", &cols, &rows) == 2) + comm_call(ci->comm2, "cursor", p, + w/cols, NULL, NULL, h/rows, NULL, NULL, + p->cx + xo, p->cy + yo); + } + return 1; +} + DEF_CMD(close_notify) { struct window_data *wd = ci->home->data; @@ -186,6 +319,8 @@ void window_setup(struct pane *ed safe) key_add(window_map, "selection:discard", &selection_discard); key_add(window_map, "Notify:Close", &close_notify); + key_add(window_map, "Draw:scale-image", &scale_image); + call_comm("global-set-command", ed, &window_attach, 0, NULL, "attach-window-core"); } diff --git a/display-ncurses.c b/display-ncurses.c index 69cd0fe7..ee8ce70d 100644 --- a/display-ncurses.c +++ b/display-ncurses.c @@ -995,46 +995,120 @@ 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 */ + MagickAdaptiveResizeImage(dii->wd, ci->num, ci->num2); + 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'▀' */ + for (j = 0; j < dii->w ; j+= 1) { + unsigned char *p1 = buf + i*dii->w*4 + j*4; + unsigned char *p2 = buf + (i+1)*dii->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; + } + } + 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 - * 'str2' container 'mode' information. - * By default the image is placed centrally in the pane - * and scaled to use either fully height or fully width. - * Various letters modify this: - * 'S' - stretch to use full height *and* full width - * 'L' - place on left if full width isn't used - * 'R' - place on right if full width isn't used - * 'T' - place at top if full height isn't used - * 'B' - place at bottom if full height isn't used. - * - * Also a suffix ":NNxNN" will be parse and the two numbers used - * to give number of rows and cols to overlay on the image for - * the purpose of cursor positioning. If these are present and - * p->cx,cy are not negative, draw a cursor at p->cx,cy highlighting - * the relevant cell. - * - * num,num2, if both positive, override the automatic scaling. - * The image is scaled to this many pixels. - * x,y is top-left pixel in the scaled image to start display at. - * Negative values allow a margin between pane edge and this image. + * '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; - const char *mode = ci->str2 ?: ""; - bool stretch = strchr(mode, 'S'); - int w = ci->focus->w, h = ci->focus->h * 2; - int pw = w, ph = h; - int xo = 0, yo = 0; - int cix, ciy; - 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; @@ -1059,135 +1133,19 @@ DEF_CMD(nc_draw_image) DestroyMagickWand(wd); return Efail; } - } else + } + + if (!wd) return Einval; MagickAutoOrientImage(wd); - if (ci->num > 0 && ci->num2 > 0) { - w = ci->num; - h = ci->num2; - } else if (ci->num > 0) { - int ih = MagickGetImageHeight(wd); - int iw = MagickGetImageWidth(wd); - - if (iw <= 0 || iw <= 0) { - DestroyMagickWand(wd); - return Efail; - } - w = iw * ci->num / 1024; - h = ih * ci->num / 1024; - } else 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; - if (strchr(mode, 'B')) - /* bottom */ - y = h - ih; - else if (!strchr(mode, 'T')) - /* center */ - y = (h - ih) / 2; - /* Keep 'h' even! */ - h = ((ih+1)/2) * 2; - } else { - /* image is too tall, use less width */ - iw = iw * h / ih; - if (strchr(mode, 'R')) - /* right */ - x = w - iw; - else if (!strchr(mode, 'L')) - x = (w - iw) / 2; - w = iw; - } - } - MagickAdaptiveResizeImage(wd, w, h); - cix = ci->x; - ciy = ci->y; - if (cix < 0) { - xo -= cix; - pw += cix; - cix = 0; - } - if (ciy < 0) { - yo -= ciy; - ph += ciy; - ciy = 0; - } - if (w - cix <= pw) - w -= cix; - else - w = pw; - if (h - ciy <= ph) - h -= ciy; - else - h = ph; - buf = malloc(h * w * 4); - MagickExportImagePixels(wd, cix, ciy, w, h, "RGBA", CharPixel, buf); - - if (ci->focus->cx >= 0 && strchr(mode, ':')) { - /* 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); diff --git a/display-x11-xcb.c b/display-x11-xcb.c index e9cb9560..a006c945 100644 --- a/display-x11-xcb.c +++ b/display-x11-xcb.c @@ -805,59 +805,102 @@ DEF_CMD(xcb_draw_text) return 1; } +struct di_info { + struct command c; + MagickWand *wd safe; + int x,y,w,h; + int xo, yo; + struct panes *ps safe; +}; + +DEF_CB(xcb_draw_image_cb) +{ + struct di_info *dii = container_of(ci->comm, struct di_info, c); + int stride; + int fmt[2]; + unsigned char *buf; + cairo_surface_t *surface; + + switch (ci->key[0]) { + case 'w': /* width */ + return MagickGetImageWidth(dii->wd); + case 'h': /* height */ + return MagickGetImageHeight(dii->wd); + case 's': /* scale */ + MagickAdaptiveResizeImage(dii->wd, ci->num, ci->num2); + 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 */ + cairo_rectangle(dii->ps->ctx, + ci->x + dii->xo, ci->y + dii->yo, + ci->num, ci->num2); + cairo_set_line_width(dii->ps->ctx, 1.0); + cairo_set_source_rgb(dii->ps->ctx, 1.0, 0.0, 0.0); + cairo_stroke(dii->ps->ctx); + return 1; + } + case 'd': /* draw */ + if (dii->w <= 0 || dii->h <= 0) + return Efail; + stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, + dii->w); + buf = malloc(dii->h * stride); + // Cairo expects 32bit values with A in the high byte, then RGB. + // Magick provides 8bit values in the order requests. + // So depending on byte order, a different string is needed + + fmt[0] = ('A'<<24) | ('R' << 16) | ('G' << 8) | ('B' << 0); + fmt[1] = 0; + MagickExportImagePixels(dii->wd, dii->x, dii->y, + dii->w, dii->h, + (char*)fmt, CharPixel, buf); + surface = cairo_image_surface_create_for_data( + buf, CAIRO_FORMAT_ARGB32, dii->w, dii->h, stride); + cairo_set_source_surface(dii->ps->ctx, surface, + ci->num + dii->xo, ci->num2 + dii->yo); + cairo_paint(dii->ps->ctx); + cairo_surface_destroy(surface); + free(buf); + return 1; + default: + return Efail; + } +} + DEF_CMD(xcb_draw_image) { /* 'str' identifies the image. Options are: * file:filename - load file from fs * comm:command - run command collecting bytes - * 'str2' container 'mode' information. - * By default the image is placed centrally in the pane - * and scaled to use either fully height or fully width. - * Various letters modify this: - * 'S' - stretch to use full height *and* full width - * 'L' - place on left if full width isn't used - * 'R' - place on right if full width isn't used - * 'T' - place at top if full height isn't used - * 'B' - place at bottom if full height isn't used. - * - * Also a suffix ":NNxNN" will be parse and the two numbers used - * to give number of rows and cols to overlay on the image for - * the purpose of cursor positioning. If these are present and - * p->cx,cy are not negative, draw a cursor at p->cx,cy highlighting - * the relevant cell. - * - * num,num2, if both positive, override the automatic scaling. - * The image is scaled to this many pixels. - * x,y is top-left pixel in the scaled image to start display at. - * Negative values allow a margin between pane edge and this image. + * 'str2' and numbers are handled by Draw:scale-image. */ struct xcb_data *xd = ci->home->data; - const char *mode = ci->str2 ?: ""; - bool stretch = strchr(mode, 'S'); - int w, h; - int x = 0, y = 0; - int pw, ph; - int xo, yo; - int cix, ciy; - int stride; + struct di_info dii; + MagickWand *wd = NULL; struct panes *ps; - MagickBooleanType status; - MagickWand *wd; - int fmt[2]; - unsigned char *buf; - cairo_surface_t *surface; if (!ci->str) return Enoarg; - ps = find_pixmap(xd, ci->focus, &xo, &yo); + ps = find_pixmap(xd, ci->focus, &dii.xo, &dii.yo); if (!ps) return Einval; - if (!ps->ctx) - instantiate_pixmap(xd, ps); - ps->bg.g = -1; - if (!ps->ctx) + dii.ps = ps; + if (!dii.ps->ctx) + instantiate_pixmap(xd, dii.ps); + dii.ps->bg.g = -1; + if (!dii.ps->ctx) return Efail; if (strstarts(ci->str, "file:")) { + MagickBooleanType status; + wd = NewMagickWand(); status = MagickReadImage(wd, ci->str + 5); if (status == MagickFalse) { @@ -865,7 +908,9 @@ DEF_CMD(xcb_draw_image) return Efail; } } else if (strstarts(ci->str, "comm:")) { + MagickBooleanType status; struct call_return cr; + wd = NewMagickWand(); cr = call_ret(bytes, ci->str+5, ci->focus); if (!cr.s) { @@ -878,106 +923,19 @@ DEF_CMD(xcb_draw_image) DestroyMagickWand(wd); return Efail; } - } else + } + + if (!wd) return Einval; MagickAutoOrientImage(wd); - w = ci->focus->w; - h = ci->focus->h; - if (ci->num > 0 && ci->num2 > 0) { - w = ci->num; - h = ci->num2; - } else if (ci->num > 0) { - int ih = MagickGetImageHeight(wd); - int iw = MagickGetImageWidth(wd); - - if (iw <= 0 || iw <= 0) { - DestroyMagickWand(wd); - return Efail; - } - w = iw * ci->num / 1024; - h = ih * ci->num / 1024; - } else 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; - if (strchr(mode, 'B')) - /* bottom */ - y = h - ih; - else if (!strchr(mode, 'T')) - /* center */ - y = (h - ih) / 2; - h = ih; - } else { - /* image is too tall, use less width */ - iw = iw * h / ih; - if (strchr(mode, 'R')) - /* right */ - x = w - iw; - else if (!strchr(mode, 'L')) - x = (w - iw) / 2; - w = iw; - } - } - MagickAdaptiveResizeImage(wd, w, h); - pw = ci->focus->w; - ph = ci->focus->h; - cix = ci->x; - ciy = ci->y; - if (cix < 0) { - xo -= cix; - pw += cix; - cix = 0; - } - if (ciy < 0) { - yo -= ciy; - ph += ciy; - ciy = 0; - } - if (w - cix <= pw) - w -= cix; - else - w = pw; - if (h - ciy <= ph) - h -= ciy; - else - h = ph; - stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w); - buf = malloc(h * stride); - // Cairo expects 32bit values with A in the high byte, then RGB. - // Magick provides 8bit values in the order requests. - // So depending on byte order, a different string is needed + dii.c = xcb_draw_image_cb; + dii.wd = wd; + 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); - fmt[0] = ('A'<<24) | ('R' << 16) | ('G' << 8) | ('B' << 0); - fmt[1] = 0; - MagickExportImagePixels(wd, cix, ciy, w, h, - (char*)fmt, CharPixel, buf); - surface = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, - w, h, stride); - cairo_set_source_surface(ps->ctx, surface, x + xo, y + yo); - cairo_paint(ps->ctx); - cairo_surface_destroy(surface); - free(buf); - - if (ci->focus->cx >= 0) { - struct pane *p = ci->focus; - int rows, cols; - char *cl = strchr(mode, ':'); - if (cl && sscanf(cl, ":%dx%d", &cols, &rows) == 2) { - cairo_rectangle(ps->ctx, p->cx + xo, p->cy + yo, - w/cols, h/rows); - cairo_set_line_width(ps->ctx, 1.0); - cairo_set_source_rgb(ps->ctx, 1.0, 0.0, 0.0); - cairo_stroke(ps->ctx); - } - } DestroyMagickWand(wd); pane_damaged(ci->home, DAMAGED_POSTORDER); diff --git a/tests.d/02-presenter b/tests.d/02-presenter index f3dbc6c2..150ede91 100644 --- a/tests.d/02-presenter +++ b/tests.d/02-presenter @@ -130,41 +130,41 @@ Display 80,30 32AAA2452953CA412B6C501C049F17A9 41,0 Key ":C-V" Display 80,30 EDAF305E1201F1CEA222CE692A096833 41,14 Key ":C-V" -Display 80,30 50443615B49D117F5C027319CFA89B1E 41,23 +Display 80,30 24B378D77925D238A39E20FF8409DC58 41,23 Key ":C-V" Display 80,30 A9C2CE554971E61FCCBA577E0FAA2E51 41,23 Key ":C-V" -Display 80,30 B7BD5F8F519A164138FC3A744E87995B 41,19 +Display 80,30 80BFE9BD891136C6DA2F6E86C634C7A6 41,19 Key ":C-V" -Display 80,30 89F3E4969386562A4541DFE03E746047 41,25 +Display 80,30 5A34BD9963F7220D335814D0CF4CF6F0 41,25 Key ":C-V" -Display 80,30 8ECD5B33AD931522FD8942DD21B4DBBF 41,19 +Display 80,30 CD6FDF42EA8E3F33F2C724ABFE29BCD9 41,19 Key ":C-V" -Display 80,30 D98DD7B91EEEF2D35EAD485D2252054D 41,25 +Display 80,30 44B8E6837CEE52F8B5A39204CC7A0EA8 41,25 Key ":C-V" -Display 80,30 B825A7DE11DA8606F70EE48A96B8C89D 41,22 +Display 80,30 A10016532503907B42F429D381E2D554 41,22 Key ":C-V" -Display 80,30 EEF0EC05C62400521394262146B15B62 41,20 +Display 80,30 0F2D596198D3188EED67E6B0EFF4E860 41,20 Key ":C-V" -Display 80,30 C12CD388ED436FAB7AA25E6BD10EE7C9 41,27 +Display 80,30 9994CA0D1995DEB50903586F8911FEC3 41,27 Key ":A-v" -Display 80,30 57309EC1307757082E9DD0962C044601 41,19 +Display 80,30 A92659CC1C8F76FF3D7838FEC045B638 41,19 Key ":A-v" -Display 80,30 42C17C0D79F95153E760C3C7051E99B7 41,4 +Display 80,30 079832D06081B6AFAA6C1A50B088A02A 41,4 Key ":A-v" -Display 80,30 556C798DC3E58F49718F72B31CC43CCE 41,2 +Display 80,30 65A04A615A574E7A7D9CC550E20DC769 41,2 Key ":A-v" -Display 80,30 925B1518F50375FC3A53CF199F0763B3 41,5 +Display 80,30 308C19E289DE5E8F094FAB37B4D80861 41,5 Key ":C-X" -Display 80,30 C77A763803918CD43C14DE9BBC75FE7B 41,5 +Display 80,30 FA340030449E00D248815C79F8A5CA8C 41,5 Key "-o" -Display 80,30 925B1518F50375FC3A53CF199F0763B3 41,5 +Display 80,30 308C19E289DE5E8F094FAB37B4D80861 41,5 Key "- " -Display 80,30 8DE5E802C5FB540C1108886EEE7BD387 41,5 +Display 80,30 EF77D170B48154461AB517006E36C128 41,5 Key "- " Display 80,30 D05FA5555E5753EF7C63130BFCC5F298 41,5 Key ":Backspace" -Display 80,30 95609A412E56BB1A19FB84AA753E62B8 41,5 +Display 80,30 18512898A7A2054C3E506AA0412A8871 41,5 Key ":Backspace" Display 80,30 EB57713F78EB85789B0CAE8B35B59A6D 41,5 Key ":C-X" @@ -176,33 +176,33 @@ Display 80,30 FA86716DAC8F2E24B38E71C82185A6F6 41,0 Key ":C-V" Display 80,30 E95B1E8C501DBCB5CD04B4D94417CFE7 41,14 Key ":C-V" -Display 80,30 9A5DD296215402CC74D1D720F3F820F1 41,23 +Display 80,30 493C5A6D6986B8FF8616ACA771B1F12B 41,23 Key ":C-S" -Display 80,30 2097376AE950E385F190D8101FBDD47F 70,0 +Display 80,30 F0633C4ED34235C5B1D1B2AF0795ECE4 70,0 Key "-e" -Display 80,30 83ADA35DA249CA84904FD93978F13D88 71,0 -Display 80,30 9D6D90E19DFE188EBBE2DE863915312E 71,0 +Display 80,30 93F4C2ED181D80340B035CABA8C22F47 71,0 +Display 80,30 4EF4BFB068CFD0B574F4B469CD1F8804 71,0 Key "-m" -Display 80,30 F1B3D5B1AA800B752C37CCA8405B2095 72,0 +Display 80,30 FD535E0CA62186FE60D9791A859A3866 72,0 Key "-p" -Display 80,30 8045670F17ED3F441937988AA15F7548 73,0 -Display 80,30 EE2BB6009BBB06973E87D16C2F101F3F 73,0 +Display 80,30 41C3E4217288B4D8D4EC07031CC74AE5 73,0 +Display 80,30 A0E51F3255FA21B7ECE798CFEACD4960 73,0 Key ":Enter" -Display 80,30 7DB9F15A949DA58D7B427E7E38DABFC6 52,13 +Display 80,30 E80738A12817CC5CFDC4A1BFD34D8B2D 52,13 Key ":C-L" -Display 80,30 3F073FF1DC666B464A9F7A4BEB29E344 52,13 +Display 80,30 F683653F333FB5995F3F06E1973434BD 52,13 Key ":C-S" -Display 80,30 F446ED1B62EAB70A53390B79F6B917CD 70,0 +Display 80,30 BE6AA179DA2B5B277A025D8B15FC34B0 70,0 Key ":C-S" -Display 80,30 13E0C7059235BBCFCDFD055B29F062FD 73,0 -Display 80,30 7488B884D954DE9E856D7BCB50A5DF57 73,0 +Display 80,30 AFFACF34F3D48EEBE73A69FA87D24D5D 73,0 +Display 80,30 0D7BAB2BC9AF139F12C0CC87DB1F27AD 73,0 Key ":C-S" -Display 80,30 7752BD089F25A386DDE9926C81C71780 72,0 -Display 80,30 63BE4545AE7FF2A764814913C8CF31E2 72,0 +Display 80,30 A7A665D627FDC7D40FD3874DB5D9243D 72,0 +Display 80,30 D18D81F1F64602644D0A38A1767923D4 72,0 Key ":Enter" -Display 80,30 D60957D735072E7A20705B01CE156B1D 52,21 +Display 80,30 60607FF8A4916C216A7EB7739678B955 52,21 Key ":C-V" -Display 80,30 01D13EAA75BA12602218BB9F0B802907 41,25 +Display 80,30 5E2E4C433D958D3FCD42B6071B24E6B4 41,25 Key ":C-V" Display 80,30 90A6DF6667023AAFC1FC320CE20C1851 41,20 Key ":A->"