From 6ead8c97e21d0c799d7d11c067719df1cc71bf56 Mon Sep 17 00:00:00 2001 From: sfja Date: Wed, 7 May 2025 17:13:43 +0200 Subject: [PATCH] delegate handlers --- src/canvas.ts | 17 ++++++++++++ src/grid.ts | 20 ++++++++++++++ src/painter.ts | 17 +++++++++--- src/renderer.ts | 12 ++++++++- src/simulator.ts | 70 ++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 127 insertions(+), 9 deletions(-) diff --git a/src/canvas.ts b/src/canvas.ts index ddb2cab..76abd2e 100644 --- a/src/canvas.ts +++ b/src/canvas.ts @@ -26,6 +26,20 @@ export class CanvasRenderer implements Renderer { g.fillRect(x, y, w, h); } + strokeRect( + x: number, + y: number, + w: number, + h: number, + color: string, + lineWidth: number, + ): void { + const { g } = this; + g.strokeStyle = color; + g.lineWidth = lineWidth; + g.strokeRect(x, y, w, h); + } + fillCirc(x: number, y: number, radius: number, color: string): void { const { g } = this; g.fillStyle = color; @@ -40,9 +54,12 @@ export class CanvasRenderer implements Renderer { y: number, w = data.width, h = data.height, + alpha = 1, ): void { const { g } = this; + g.globalAlpha = alpha; g.drawImage(data, x, y, w, h); + g.globalAlpha = 1.0; } } diff --git a/src/grid.ts b/src/grid.ts index 08d6f2a..9d7a7ce 100644 --- a/src/grid.ts +++ b/src/grid.ts @@ -169,6 +169,24 @@ class TransformingRenderer implements Renderer { const { r, t: { s, ox, oy } } = this; r.fillRect(x * s + ox, y * s + oy, w * s, h * s, color); } + strokeRect( + x: number, + y: number, + w: number, + h: number, + color: string, + lineWidth: number, + ): void { + const { r, t: { s, ox, oy } } = this; + r.strokeRect( + x * s + ox, + y * s + oy, + w * s, + h * s, + color, + lineWidth * s, + ); + } fillCirc(x: number, y: number, radius: number, color: string): void { const { r, t: { s, ox, oy } } = this; r.fillCirc(x * s + ox, y * s + oy, radius * s, color); @@ -179,6 +197,7 @@ class TransformingRenderer implements Renderer { y: number, w = data.width, h = data.width, + alpha = 1, ): void { const { r, t: { s, ox, oy } } = this; @@ -188,6 +207,7 @@ class TransformingRenderer implements Renderer { y * s + oy, w * s, h * s, + alpha, ); } } diff --git a/src/painter.ts b/src/painter.ts index 142065b..1ee3722 100644 --- a/src/painter.ts +++ b/src/painter.ts @@ -15,8 +15,8 @@ export class Painter implements Renderer { ); } - render(r: Renderer, x: number, y: number) { - r.putImage(this.c, x, y, this.c.width, this.c.height); + render(r: Renderer, x: number, y: number, alpha = 1) { + r.putImage(this.c, x, y, this.c.width, this.c.height, alpha); } get width(): number { @@ -31,6 +31,16 @@ export class Painter implements Renderer { fillRect(x: number, y: number, w: number, h: number, color: string): void { this.r.fillRect(x, y, w, h, color); } + strokeRect( + x: number, + y: number, + w: number, + h: number, + color: string, + lineWidth: number, + ): void { + this.r.strokeRect(x, y, w, h, color, lineWidth); + } fillCirc(x: number, y: number, radius: number, color: string): void { this.r.fillCirc(x, y, radius, color); } @@ -40,7 +50,8 @@ export class Painter implements Renderer { y: number, w = data.width, h = data.height, + alpha = 1, ): void { - this.r.putImage(data, x, y, w, h); + this.r.putImage(data, x, y, w, h, alpha); } } diff --git a/src/renderer.ts b/src/renderer.ts index c571e13..bc215e4 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -10,6 +10,16 @@ export interface Renderer { get height(): N; clear(color: string): void; fillRect(x: N, y: N, w: N, h: N, color: string): void; + strokeRect(x: N, y: N, w: N, h: N, color: string, lineWidth: number): void; fillCirc(x: N, y: N, radius: N, color: string): void; - putImage(data: RendererImage, x: N, y: N, w?: N, h?: N): void; + putImage(data: RendererImage, x: N, y: N): void; + putImage(data: RendererImage, x: N, y: N, w: N, h: N): void; + putImage( + data: RendererImage, + x: N, + y: N, + w: N, + h: N, + alpha: number, + ): void; } diff --git a/src/simulator.ts b/src/simulator.ts index 442e803..48dd179 100644 --- a/src/simulator.ts +++ b/src/simulator.ts @@ -20,9 +20,10 @@ export class Simulator { render(r: Renderer) { hover: { - if (this.toolbar.hover(this.mouse.x, this.mouse.y) === "break") { + if (this.toolbar.hover() === "break") { break hover; } + document.body.style.cursor = "default"; } r.clear("black"); @@ -54,6 +55,14 @@ class Toolbar { this.mouse.addOnPress(() => { const { x, y } = this.mouse; + + if ( + !(x >= 0 && y >= this.lastHeight - 200 && x < this.lastWidth && + y < this.lastHeight) + ) { + return "bubble"; + } + for (const [i, component] of this.previews.entries()) { if ( x >= i * 128 + 96 - 48 && @@ -65,7 +74,8 @@ class Toolbar { return "stop"; } } - return "bubble"; + this.tooltip.deselect(); + return "stop"; }); } @@ -74,7 +84,8 @@ class Toolbar { this.previews = this.tools as unknown as Component[]; } - hover(x: number, y: number): "continue" | "break" { + hover(): "continue" | "break" { + const { x, y } = this.mouse; for (const [i, component] of this.previews.entries()) { if ( x >= i * 128 + 96 - 48 && @@ -83,6 +94,7 @@ class Toolbar { y < this.lastHeight - 100 + component.height * 32 + 32 ) { this.hoveringComponentIdx = i; + document.body.style.cursor = "pointer"; return "break"; } } @@ -96,6 +108,14 @@ class Toolbar { r.fillRect(0, r.height - 200, r.width, 200, "#aaa"); for (const [i, component] of this.previews.entries()) { + r.strokeRect( + i * 128 + 96 - 48, + r.height - 100 - 48, + 96, + 96, + "#777", + 1, + ); if (i === this.hoveringComponentIdx) { r.fillRect( i * 128 + 96 - 48, @@ -113,6 +133,8 @@ class Toolbar { class Tooltip { private selectedComponent?: Component; + private shouldHover = false; + constructor( private circuit: Circuit, public mouse: Mouse, @@ -125,18 +147,37 @@ class Tooltip { const x = Math.floor(this.mouse.x / 32); const y = Math.floor(this.mouse.y / 32); this.circuit.place(this.selectedComponent, x, y); - this.selectedComponent = undefined; return "stop"; }); } + hover(): "continue" | "break" { + if (!this.selectedComponent) { + return "continue"; + } + const x = Math.floor(this.mouse.x / 32); + const y = Math.floor(this.mouse.y / 32); + if (!this.circuit.placeIsOccupied(x, y)) { + this.shouldHover = true; + return "break"; + } + + return "continue"; + } + render(r: Renderer): void { - this.selectedComponent?.render(r, this.mouse.x, this.mouse.y); + const x = Math.floor(this.mouse.x / 32); + const y = Math.floor(this.mouse.y / 32); + this.selectedComponent?.renderTransparent(r, x * 32 + 16, y * 32 + 16); } select(component: Component): void { this.selectedComponent = component; } + + deselect(): void { + this.selectedComponent = undefined; + } } type PlacedComponent = { @@ -173,6 +214,14 @@ class Circuit { }); } + placeIsOccupied(x: number, y: number): boolean { + return this.components.some((c) => c.x == x && c.y == y); + } + + hover(): "continue" | "break" { + return "continue"; + } + place(component: Component, x: number, y: number): void { this.components.push({ component, x, y }); } @@ -188,6 +237,7 @@ interface Component { get width(): number; get height(): number; render(r: Renderer, x: number, y: number): void; + renderTransparent(r: Renderer, x: number, y: number): void; click?(x: number, y: number): void; } @@ -223,6 +273,11 @@ class SwitchComponent implements Component, ComponentFactory { graphic.render(r, x - 48, y - 32); } + renderTransparent(r: Renderer, x: number, y: number): void { + const graphic = this.switchOn ? this.graphicOn : this.graphicOff; + graphic.render(r, x - 48, y - 32, 0.5); + } + click(x: number, y: number): void { const onButton = Math.sqrt( (x - 16) ** 2 + (y - 16) ** 2, @@ -261,4 +316,9 @@ class LedComponent implements Component, ComponentFactory { const graphic = this.switchOn ? this.graphicOn : this.graphicOff; graphic.render(r, x - 48, y - 32); } + + renderTransparent(r: Renderer, x: number, y: number): void { + const graphic = this.switchOn ? this.graphicOn : this.graphicOff; + graphic.render(r, x - 48, y - 32, 0.5); + } }