forked from jimrandomh/faceclaw
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodal-layer.ts
More file actions
57 lines (50 loc) · 2.27 KB
/
Copy pathmodal-layer.ts
File metadata and controls
57 lines (50 loc) · 2.27 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 { GrayImage } from "../../graphics/image";
import { DashboardInputEvent, Layer, LayerActions, LayerContext, LayerStack, PaintBelow } from "../layers";
import { appViewportRect, appViewportSize, SHELL_OPAQUE_BLACK } from "./geometry";
// The modal covers most of the min-height app viewport, leaving a little of
// the foreground app visible around the edges. Its size is fixed (min-height
// windows have a fixed viewport size); its position follows the vertical
// position setting, so it is computed per paint.
const MODAL_MARGIN = 14;
const MODAL_PADDING = 4;
export const MODAL_INTERIOR = {
width: appViewportSize("min").width - 2 * MODAL_MARGIN - 2 * MODAL_PADDING,
height: appViewportSize("min").height - 2 * MODAL_MARGIN - 2 * MODAL_PADDING,
} as const;
/** Screen rect of the modal box, aligned to the min-height window band. */
export function modalRect(): { x: number; y: number; width: number; height: number } {
const viewport = appViewportRect("min");
return {
x: viewport.x + MODAL_MARGIN,
y: viewport.y + MODAL_MARGIN,
width: viewport.width - 2 * MODAL_MARGIN,
height: viewport.height - 2 * MODAL_MARGIN,
};
}
/**
* A shell overlay hosting an inner layer stack in a bordered box over the
* app viewport (used for new-notification popups). The inner stack paints at
* the modal's interior size; its pixels blit onto an opaque black backdrop,
* so inner value-0 pixels read as black, not transparent.
*/
export class ShellModalLayer implements Layer {
private readonly stack: LayerStack;
constructor(baseLayer: Layer, actions: LayerActions) {
this.stack = new LayerStack(baseLayer, actions, {
width: MODAL_INTERIOR.width,
height: MODAL_INTERIOR.height,
});
}
paint(ctx: LayerContext, paintBelow: PaintBelow): GrayImage {
const image = paintBelow();
const inner = this.stack.paint();
const rect = modalRect();
image.fillRoundedRect(rect.x, rect.y, rect.width, rect.height, SHELL_OPAQUE_BLACK, 8);
image.drawRoundedRect(rect.x, rect.y, rect.width, rect.height, 110, 8);
image.bitBlt(inner, rect.x + MODAL_PADDING, rect.y + MODAL_PADDING, { transparentZero: true });
return image;
}
async handleInput(event: DashboardInputEvent, ctx: LayerContext): Promise<void> {
await this.stack.handleInput(event);
}
}