add placing

This commit is contained in:
sfja 2026-05-11 23:36:53 +02:00
parent 3a38e90178
commit 70ad562bde
4 changed files with 52 additions and 25 deletions

View File

@ -1,18 +1,19 @@
import { useState, type ReactElement } from "react";
import { useRef, useState, type ReactElement } from "react";
import "./style.css";
import Canvas from "./Canvas";
import { Editor } from "./Editor";
import Toolbar from "./Toolbar";
function App(): ReactElement {
const [editor] = useState(new Editor());
const [editor] = useState(() => new Editor());
const canvasRef = useRef<HTMLCanvasElement | null>(null);
return (
<>
<h1>nandsim</h1>
<div className="Editor">
<Toolbar editor={editor} />
<Canvas editor={editor} />
<Toolbar editor={editor} canvasRef={canvasRef} />
<Canvas editor={editor} canvasRef={canvasRef} />
</div>
</>
);

View File

@ -1,22 +1,20 @@
import { useEffect, useRef, type ReactElement } from "react";
import { useEffect, useRef, type ReactElement, type RefObject } from "react";
import { V2, type Editor } from "./Editor";
type Props = { editor: Editor };
function Canvas({ editor }: Props): ReactElement {
const ref = useRef<HTMLCanvasElement | null>(null);
type Props = { editor: Editor; canvasRef: RefObject<HTMLCanvasElement | null> };
function Canvas({ editor, canvasRef }: Props): ReactElement {
useEffect(() => {
if (!ref.current) return;
if (!canvasRef.current) return;
editor.render(ref.current);
editor.render(canvasRef.current);
});
return (
<>
<div className="Canvas">
<canvas
ref={ref}
ref={canvasRef}
width={1000}
height={1000}
style={{ width: 1000, height: 1000, backgroundColor: "black" }}

View File

@ -136,8 +136,8 @@ class Cx {
);
}
transitionTo<S extends { new (cx: Cx): State }>(S: S) {
this.state = new S(this);
transitionTo(newState: State) {
this.state = newState;
this.notifyListeners();
}
@ -188,19 +188,21 @@ class Normal implements State {
selectTool(tool: Tool): void {
switch (tool) {
case "pan":
this.cx.transitionTo(Panning);
this.cx.transitionTo(new Panning(this.cx));
break;
case "and":
this.cx.transitionTo(new Placing(this.cx, "and"));
}
}
onMouseDown(pos: V2): void {
this.cx.addSelectionRect(pos);
this.cx.transitionTo(Selecting);
this.cx.transitionTo(new Selecting(this.cx));
}
onKeyDown(key: string): void {
if (key === "Shift") {
this.cx.transitionTo(Panning);
this.cx.transitionTo(new Panning(this.cx));
return;
}
}
@ -231,20 +233,20 @@ class Panning implements State {
onKeyDown(key: string): void {
if (key === "Escape") {
this.cx.transitionTo(Normal);
this.cx.transitionTo(new Normal(this.cx));
return;
}
}
onKeyUp(key: string): void {
if (key === "Shift") {
this.cx.transitionTo(Normal);
this.cx.transitionTo(new Normal(this.cx));
return;
}
}
selectTool(tool: Tool): void {
this.cx.transitionTo(Normal);
this.cx.transitionTo(new Normal(this.cx));
this.cx.selectTool(tool);
}
@ -263,7 +265,7 @@ class Selecting implements State {
onMouseUp(_pos: V2): void {
this.cx.removeSelectionRect();
this.cx.transitionTo(Normal);
this.cx.transitionTo(new Normal(this.cx));
}
onMouseMove(deltaPos: V2): void {
@ -275,4 +277,27 @@ class Selecting implements State {
}
}
class Placing implements State {
constructor(
private cx: Cx,
private tool: Tool,
) {}
onMouseUp(pos: V2): void {
this.cx.transitionTo(new Normal(this.cx));
console.log("place");
}
onKeyDown(key: string): void {
if (key === "Escape") {
this.cx.transitionTo(new Normal(this.cx));
return;
}
}
selectedTool(): Tool | null {
return this.tool;
}
}
type Tool = "select" | "pan" | "and";

View File

@ -1,14 +1,14 @@
import { useEffect, useState, type ReactElement } from "react";
import { useEffect, useState, type ReactElement, type RefObject } from "react";
import type { Editor } from "./Editor";
type Props = { editor: Editor };
type Props = { editor: Editor; canvasRef: RefObject<HTMLCanvasElement | null> };
function useUpdate(): [number, () => void] {
const [value, setValue] = useState(0);
return [value, () => setValue(value + 1)] as const;
}
function Toolbar({ editor }: Props): ReactElement {
function Toolbar({ editor, canvasRef }: Props): ReactElement {
const [uid, update] = useUpdate();
useEffect(() => {
@ -23,7 +23,10 @@ function Toolbar({ editor }: Props): ReactElement {
<button
key={`${uid}${key}`}
className={editor.selectedTool() === tool ? "active" : ""}
onClick={() => editor.selectTool(tool)}
onClick={() => {
editor.selectTool(tool);
canvasRef.current?.focus();
}}
>
{tool}
</button>