2 * Copyright Neil Brown ©2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * Display an image and allow it to be scaled and panned.
9 #define PANE_DATA_TYPE struct imageview_data
12 struct imageview_data {
14 int w,h; /* size of image */
15 int scale; /* 1024 * displayed-size / actual size */
16 int cx,cy; /* image co-ordinates at center of pane.
17 * Kept stable during zoom
19 short px,py; /* number of pixels in each pane cell */
20 bool integral; /* Use integral scales */
22 #include "core-pane.h"
24 DEF_CMD_CLOSED(imageview_close)
26 struct imageview_data *ivd = ci->home->data;
33 static int fix_scale(struct imageview_data *ivd safe, int scale)
41 return 1024 / (1024 / scale);
45 DEF_CMD(imageview_refresh)
47 struct imageview_data *ivd = ci->home->data;
48 char *img = ivd->image;
50 int pw = ci->home->w * ivd->px;
51 int ph = ci->home->h * ivd->py;
53 call("Draw:clear", ci->focus, 0, NULL, "bg:black");
56 img = pane_attr_get(ci->focus, "imageview:image-source");
58 img = "comm:doc:get-bytes";
60 ivd->image = strdup(img);
64 struct call_return cr = call_ret(all, "Draw:image-size",
70 i = pane_attr_get(ci->focus, "imageview:integral");
71 ivd->integral = (i && strcmp(i, "yes") == 0);
73 if (ivd->w <= 0 || ivd->h <= 0)
76 if (ivd->scale <= 0) {
77 int xs = pw * 1024 / ivd->w;
78 int ys = ph * 1024 / ivd->h;
79 ivd->scale = fix_scale(ivd, xs > ys ? ys : xs);
82 x = (ivd->cx * ivd->scale) - pw * 1024 / 2;
83 y = (ivd->cy * ivd->scale) - ph * 1024 / 2;
85 if (ivd->scale * ivd->w < pw * 1024)
86 /* Doesn't use full width, so centre */
87 x = -(pw * 1024 - ivd->scale * ivd->w) / 2;
89 /* Does use full width, so avoid margins */
92 if (x > ivd->w * ivd->scale - pw * 1024)
93 x = ivd->w * ivd->scale - pw * 1024;
95 if (ivd->scale * ivd->h < ph * 1024)
96 y = -(ph * 1024 - ivd->scale * ivd->h) / 2;
100 if (y > ivd->h * ivd->scale - ph * 1024)
101 y = ivd->h * ivd->scale - ph * 1024;
104 ivd->cx = (pw * 1024 / 2 + x) / ivd->scale;
105 ivd->cy = (ph * 1024 / 2 + y) / ivd->scale;
107 call("Draw:image", ci->focus, ivd->scale, NULL, img,
108 0, NULL, NULL, x / 1024, y / 1024);
113 DEF_CMD(imageview_refresh_size)
115 struct imageview_data *ivd = ci->home->data;
116 int pw = ci->home->w * ivd->px;
117 int ph = ci->home->h * ivd->py;
119 if (ivd->scale * ivd->w < pw * 1024 &&
120 ivd->scale * ivd->h < ph * 1024)
121 /* Scale it too small to make use of space - reset */
123 pane_damaged(ci->home, DAMAGED_REFRESH);
128 DEF_CMD(imageview_zoom)
130 /* Keep the centre of the pane at the same pixel when
133 struct imageview_data *ivd = ci->home->data;
134 int scale = ivd->scale;
136 if (strcmp(ci->key, "K-+") == 0) {
138 ivd->scale = fix_scale(ivd, scale + scale / 10);
139 if (ivd->scale == scale)
143 ivd->scale = fix_scale(ivd, scale - scale / 11);
144 if (ivd->scale == scale && scale > 1 && scale <= 1024)
145 ivd->scale = 1024 / (1024 / scale + 1);
148 pane_damaged(ci->home, DAMAGED_REFRESH);
152 DEF_CMD(imageview_pan)
154 struct imageview_data *ivd = ci->home->data;
155 int pw = ci->home->w * ivd->px;
156 int ph = ci->home->h * ivd->py;
158 switch (ci->key[2]) {
160 ivd->cx -= pw * 1024 / ivd->scale / 10;
163 ivd->cx += pw * 1024 / ivd->scale / 10;
166 ivd->cy -= ph * 1024 / ivd->scale / 10;
169 ivd->cy += ph * 1024 / ivd->scale / 10;
172 pane_damaged(ci->home, DAMAGED_REFRESH);
176 DEF_CMD(imageview_reset)
178 struct imageview_data *ivd = ci->home->data;
182 pane_damaged(ci->home, DAMAGED_REFRESH);
186 DEF_CMD(imageview_quit)
188 call("Tile:close", ci->focus);
192 static struct map *iv_map;
193 DEF_LOOKUP_CMD(iv_handle, iv_map);
195 DEF_CMD(imageview_attach)
198 struct imageview_data *ivd;
201 p = pane_register(ci->focus, 0, &iv_handle.c);
206 ivd->image = strdup(ci->str);
208 ivd->integral = False;
209 pxl = pane_attr_get(p, "Display:pixels");
210 if (sscanf(pxl ?: "1x1", "%hdx%hx", &ivd->px, &ivd->py) != 2)
211 ivd->px = ivd->py = 1;
213 pane_damaged(p, DAMAGED_REFRESH);
215 return comm_call(ci->comm2, "cb", p);
218 void edlib_init(struct pane *ed safe)
220 call_comm("global-set-command", ed, &imageview_attach, 0, NULL,
221 "attach-render-imageview");
222 iv_map = key_alloc();
223 key_add(iv_map, "Close", &imageview_close);
224 key_add(iv_map, "Refresh", &imageview_refresh);
225 key_add(iv_map, "Refresh:size", &imageview_refresh_size);
227 key_add(iv_map, "K-+", &imageview_zoom);
228 key_add(iv_map, "K--", &imageview_zoom);
230 key_add(iv_map, "K:Left", &imageview_pan);
231 key_add(iv_map, "K:Right", &imageview_pan);
232 key_add(iv_map, "K:Up", &imageview_pan);
233 key_add(iv_map, "K:Down", &imageview_pan);
234 key_add(iv_map, "K:Home", &imageview_reset);
235 key_add(iv_map, "K-.", &imageview_reset);
237 key_add(iv_map, "K:ESC", &imageview_quit);
238 key_add(iv_map, "K-q", &imageview_quit);