- [ ] 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
### Large
-- [ ] image-display pane
+- [X] image-display pane
- [ ] git-mode
- [ ] render-markdown.py
- [X] lib-menu
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
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.
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;
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");
}
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;
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);
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) {
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) {
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);
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"
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->"