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 "./style.css";
|
||||||
import Canvas from "./Canvas";
|
import Canvas from "./Canvas";
|
||||||
import { Editor } from "./Editor";
|
import { Editor } from "./Editor";
|
||||||
import Toolbar from "./Toolbar";
|
import Toolbar from "./Toolbar";
|
||||||
|
|
||||||
function App(): ReactElement {
|
function App(): ReactElement {
|
||||||
const [editor] = useState(new Editor());
|
const [editor] = useState(() => new Editor());
|
||||||
|
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>nandsim</h1>
|
<h1>nandsim</h1>
|
||||||
<div className="Editor">
|
<div className="Editor">
|
||||||
<Toolbar editor={editor} />
|
<Toolbar editor={editor} canvasRef={canvasRef} />
|
||||||
<Canvas editor={editor} />
|
<Canvas editor={editor} canvasRef={canvasRef} />
|
||||||
</div>
|
</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";
|
import { V2, type Editor } from "./Editor";
|
||||||
|
|
||||||
type Props = { editor: Editor };
|
type Props = { editor: Editor; canvasRef: RefObject<HTMLCanvasElement | null> };
|
||||||
|
|
||||||
function Canvas({ editor }: Props): ReactElement {
|
|
||||||
const ref = useRef<HTMLCanvasElement | null>(null);
|
|
||||||
|
|
||||||
|
function Canvas({ editor, canvasRef }: Props): ReactElement {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ref.current) return;
|
if (!canvasRef.current) return;
|
||||||
|
|
||||||
editor.render(ref.current);
|
editor.render(canvasRef.current);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="Canvas">
|
<div className="Canvas">
|
||||||
<canvas
|
<canvas
|
||||||
ref={ref}
|
ref={canvasRef}
|
||||||
width={1000}
|
width={1000}
|
||||||
height={1000}
|
height={1000}
|
||||||
style={{ width: 1000, height: 1000, backgroundColor: "black" }}
|
style={{ width: 1000, height: 1000, backgroundColor: "black" }}
|
||||||
|
|||||||
@ -136,8 +136,8 @@ class Cx {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
transitionTo<S extends { new (cx: Cx): State }>(S: S) {
|
transitionTo(newState: State) {
|
||||||
this.state = new S(this);
|
this.state = newState;
|
||||||
this.notifyListeners();
|
this.notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,19 +188,21 @@ class Normal implements State {
|
|||||||
selectTool(tool: Tool): void {
|
selectTool(tool: Tool): void {
|
||||||
switch (tool) {
|
switch (tool) {
|
||||||
case "pan":
|
case "pan":
|
||||||
this.cx.transitionTo(Panning);
|
this.cx.transitionTo(new Panning(this.cx));
|
||||||
break;
|
break;
|
||||||
|
case "and":
|
||||||
|
this.cx.transitionTo(new Placing(this.cx, "and"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(pos: V2): void {
|
onMouseDown(pos: V2): void {
|
||||||
this.cx.addSelectionRect(pos);
|
this.cx.addSelectionRect(pos);
|
||||||
this.cx.transitionTo(Selecting);
|
this.cx.transitionTo(new Selecting(this.cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyDown(key: string): void {
|
onKeyDown(key: string): void {
|
||||||
if (key === "Shift") {
|
if (key === "Shift") {
|
||||||
this.cx.transitionTo(Panning);
|
this.cx.transitionTo(new Panning(this.cx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,20 +233,20 @@ class Panning implements State {
|
|||||||
|
|
||||||
onKeyDown(key: string): void {
|
onKeyDown(key: string): void {
|
||||||
if (key === "Escape") {
|
if (key === "Escape") {
|
||||||
this.cx.transitionTo(Normal);
|
this.cx.transitionTo(new Normal(this.cx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onKeyUp(key: string): void {
|
onKeyUp(key: string): void {
|
||||||
if (key === "Shift") {
|
if (key === "Shift") {
|
||||||
this.cx.transitionTo(Normal);
|
this.cx.transitionTo(new Normal(this.cx));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectTool(tool: Tool): void {
|
selectTool(tool: Tool): void {
|
||||||
this.cx.transitionTo(Normal);
|
this.cx.transitionTo(new Normal(this.cx));
|
||||||
this.cx.selectTool(tool);
|
this.cx.selectTool(tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +265,7 @@ class Selecting implements State {
|
|||||||
|
|
||||||
onMouseUp(_pos: V2): void {
|
onMouseUp(_pos: V2): void {
|
||||||
this.cx.removeSelectionRect();
|
this.cx.removeSelectionRect();
|
||||||
this.cx.transitionTo(Normal);
|
this.cx.transitionTo(new Normal(this.cx));
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove(deltaPos: V2): void {
|
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";
|
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";
|
import type { Editor } from "./Editor";
|
||||||
|
|
||||||
type Props = { editor: Editor };
|
type Props = { editor: Editor; canvasRef: RefObject<HTMLCanvasElement | null> };
|
||||||
|
|
||||||
function useUpdate(): [number, () => void] {
|
function useUpdate(): [number, () => void] {
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(0);
|
||||||
return [value, () => setValue(value + 1)] as const;
|
return [value, () => setValue(value + 1)] as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Toolbar({ editor }: Props): ReactElement {
|
function Toolbar({ editor, canvasRef }: Props): ReactElement {
|
||||||
const [uid, update] = useUpdate();
|
const [uid, update] = useUpdate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -23,7 +23,10 @@ function Toolbar({ editor }: Props): ReactElement {
|
|||||||
<button
|
<button
|
||||||
key={`${uid}${key}`}
|
key={`${uid}${key}`}
|
||||||
className={editor.selectedTool() === tool ? "active" : ""}
|
className={editor.selectedTool() === tool ? "active" : ""}
|
||||||
onClick={() => editor.selectTool(tool)}
|
onClick={() => {
|
||||||
|
editor.selectTool(tool);
|
||||||
|
canvasRef.current?.focus();
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tool}
|
{tool}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user