add placing
This commit is contained in:
parent
3a38e90178
commit
70ad562bde
@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@ -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" }}
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user