Repository navigation
Expand file tree
/
Copy pathimage-viewer.ts
More file actions
57 lines (51 loc) · 1.96 KB
/
Copy pathimage-viewer.ts
File metadata and controls
57 lines (51 loc) · 1.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { getDefaultSmallFont, type BdfFont } from "../../graphics/bdffont";
import { truncateText } from "../../graphics/textwrap";
import { GrayImage } from "../../graphics/image";
import { loadImageFileAsGray } from "../../native/image-files";
import { GESTURE_DOUBLE_CLICK } from "../gestures";
import { Layer, type DashboardInputEvent, type LayerContext } from "../layers";
const MARGIN_X = 18;
const TITLE_Y = 8;
const BODY_TOP = 24;
const BODY_MARGIN = 2;
/**
* Image viewer for a file on disk: title line, then the image decoded to
* grayscale and downscaled to fit the remaining area (never upscaled).
* Double-click closes it. Sized to its hosting stack (a Files document
* window, or pushed over the file browser for view-in-place).
*/
export class ImageViewerLayer implements Layer {
private image: GrayImage | null = null;
private loadAttempted = false;
constructor(
private readonly path: string,
private readonly title: string,
) {}
paint(ctx: LayerContext): GrayImage {
const font = getDefaultSmallFont();
const { width, height } = ctx.stack.getBaseSize();
const out = new GrayImage(width, height, 0);
out.drawText(font, MARGIN_X, TITLE_Y, truncateText(font, this.title, width - 2 * MARGIN_X), 220);
const bodyHeight = height - BODY_TOP - BODY_MARGIN;
if (!this.loadAttempted) {
this.loadAttempted = true;
this.image = loadImageFileAsGray(this.path, width - 2 * BODY_MARGIN, bodyHeight);
}
if (!this.image) {
out.drawText(font, MARGIN_X, BODY_TOP + 16, "(could not load image)", 160);
out.drawText(font, MARGIN_X, height - 16, `${GESTURE_DOUBLE_CLICK} back`, 110);
return out;
}
out.bitBlt(
this.image,
Math.round((width - this.image.width) / 2),
BODY_TOP + Math.round((bodyHeight - this.image.height) / 2),
);
return out;
}
handleInput(event: DashboardInputEvent, ctx: LayerContext): void {
if (event.type === "double-click") {
ctx.stack.pop();
}
}
}