Skip to content

Commit 38a544d

Browse files
authored
Merge pull request #47 from ut-code/node-pins-and-component-pins
refactored Pin into ComponentPin and NodePin for better modularity
2 parents 1ae7db4 + ffbf74d commit 38a544d

23 files changed

+2210
-1318
lines changed

src/App.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import { Box } from "@mui/material";
22
import { useState } from "react";
33
import "@pixi/math-extras";
44
import GlobalHeader from "./components/GlobalHeader";
5-
import { useStore } from "./store/react";
65
import type { CCComponentId } from "./store/component";
76
import EditPage from "./pages/edit";
87
import HomePage from "./pages/home";
98

109
export default function App() {
11-
const store = useStore();
1210
const [editedComponentId, setEditedComponentId] =
13-
useState<CCComponentId | null>(store.components.rootComponentId);
11+
useState<CCComponentId | null>(null);
1412

1513
return (
1614
<Box

src/pages/edit/Editor/index.tsx

+24-17
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
KeyboardDoubleArrowRight,
1919
PlayArrow,
2020
} from "@mui/icons-material";
21+
import nullthrows from "nullthrows";
2122
import { useStore } from "../../../store/react";
2223
import CCComponentEditorRenderer from "./renderer";
2324
import { CCComponentStore, type CCComponentId } from "../../../store/component";
@@ -44,7 +45,7 @@ function CCComponentEditorContent({
4445
const rendererRef = useRef<CCComponentEditorRenderer>();
4546
const containerRef = useRef<HTMLDivElement>(null);
4647
const overlayAreaRef = useRef<HTMLDivElement>(null);
47-
const store = useStore();
48+
const { store } = useStore();
4849
const componentEditorStore = useComponentEditorStore();
4950
const componentEditorState = componentEditorStore();
5051
const component = store.components.get(componentId);
@@ -211,6 +212,7 @@ function CCComponentEditorContent({
211212
const newComponent = CCComponentStore.create({
212213
name: "New Component",
213214
});
215+
store.components.register(newComponent);
214216
const oldToNewNodeIdMap = new Map<CCNodeId, CCNodeId>();
215217
const newNodes = oldNodes.map<CCNode>((oldNode) => {
216218
const newNode = CCNodeStore.create({
@@ -223,31 +225,35 @@ function CCComponentEditorContent({
223225
oldToNewNodeIdMap.set(oldNode.id, newNode.id);
224226
return newNode;
225227
});
228+
for (const node of newNodes) store.nodes.register(node);
226229
const newConnections = oldConnections.flatMap<CCConnection>(
227230
(oldConnection) => {
228-
const fromNodeId = oldToNewNodeIdMap.get(
229-
oldConnection.from.nodeId
231+
const oldFromNodePin = nullthrows(
232+
store.nodePins.get(oldConnection.from)
233+
);
234+
const oldToNodePin = nullthrows(
235+
store.nodePins.get(oldConnection.to)
230236
);
231-
const toNodeId = oldToNewNodeIdMap.get(
232-
oldConnection.to.nodeId
237+
const newFromNodeId = nullthrows(
238+
oldToNewNodeIdMap.get(oldFromNodePin.nodeId)
239+
);
240+
const newToNodeId = nullthrows(
241+
oldToNewNodeIdMap.get(oldToNodePin.nodeId)
233242
);
234-
if (!fromNodeId || !toNodeId) return [];
235243
return CCConnectionStore.create({
236244
parentComponentId: newComponent.id,
237-
from: {
238-
nodeId: fromNodeId,
239-
pinId: oldConnection.from.pinId,
240-
},
241-
to: {
242-
nodeId: toNodeId,
243-
pinId: oldConnection.to.pinId,
244-
},
245+
from: store.nodePins.getByImplementationNodeIdAndPinId(
246+
newFromNodeId,
247+
oldFromNodePin.componentPinId
248+
).id,
249+
to: store.nodePins.getByImplementationNodeIdAndPinId(
250+
newToNodeId,
251+
oldToNodePin.componentPinId
252+
).id,
245253
bentPortion: oldConnection.bentPortion,
246254
});
247255
}
248256
);
249-
store.components.register(newComponent);
250-
for (const node of newNodes) store.nodes.register(node);
251257
for (const connection of newConnections)
252258
store.connections.register(connection);
253259
store.connections.unregister([
@@ -332,8 +338,9 @@ function CCComponentEditorContent({
332338
}
333339

334340
export default function CCComponentEditor(props: CCComponentEditorProps) {
341+
const { componentId } = props;
335342
return (
336-
<ComponentEditorStoreProvider>
343+
<ComponentEditorStoreProvider componentId={componentId}>
337344
<CCComponentEditorContent {...props} />
338345
</ComponentEditorStoreProvider>
339346
);

src/pages/edit/Editor/renderer/componentPin.ts

+42-48
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as PIXI from "pixi.js";
22
import invariant from "tiny-invariant";
33
import type { EditorModePlay } from "../store";
44
import type { CCNodeId } from "../../../../store/node";
5-
import type { CCPinId } from "../../../../store/pin";
5+
import type { CCComponentPinId } from "../../../../store/componentPin";
66
import {
77
activeColor,
88
editorGridColor,
@@ -18,18 +18,15 @@ type CCComponentEditorRendererComponentPinProps = {
1818
context: CCComponentEditorRendererContext;
1919
pixiParentContainer: PIXI.Container;
2020
nodeId: CCNodeId; // TODO: this might be unnecessary
21-
pinId: CCPinId;
21+
pinId: CCComponentPinId;
2222
position: PIXI.Point;
23-
simulation: () => Map<CCPinId, boolean[]> | null;
2423
};
2524

2625
/**
2726
* Class for rendering component pin
2827
*/
2928
export default class CCComponentEditorRendererComponentPin extends CCComponentEditorRendererBase {
30-
readonly #nodeId: CCNodeId;
31-
32-
readonly #pinId: CCPinId;
29+
readonly #componentPinId: CCComponentPinId;
3330

3431
position: PIXI.Point;
3532

@@ -45,8 +42,6 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
4542

4643
readonly #unsubscribeComponentEditorStore: () => void;
4744

48-
readonly #simulation: () => Map<CCPinId, boolean[]> | null;
49-
5045
#valueBoxWidth: number;
5146

5247
private static readonly drawingConstants = {
@@ -65,15 +60,16 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
6560
*/
6661
constructor(props: CCComponentEditorRendererComponentPinProps) {
6762
super(props.context);
68-
this.#nodeId = props.nodeId;
69-
this.#pinId = props.pinId;
63+
this.#componentPinId = props.pinId;
7064
this.position = props.position;
71-
this.#simulation = props.simulation;
7265
this.#pixiParentContainer = props.pixiParentContainer;
7366
this.#pixiContainer = new PIXI.Container();
7467
this.#pixiParentContainer.addChild(this.#pixiContainer);
7568
this.#pixiGraphics = new PIXI.Graphics();
76-
if (this.context.store.pins.get(this.#pinId)!.type === "input") {
69+
if (
70+
this.context.store.componentPins.get(this.#componentPinId)!.type ===
71+
"input"
72+
) {
7773
// this.#pixiGraphics.interactive = true;
7874
this.#pixiGraphics.eventMode = "dynamic";
7975
this.#pixiGraphics.cursor = "pointer";
@@ -85,7 +81,9 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
8581
pixiParentContainer: this.#pixiContainer,
8682
});
8783
this.#pixiLabelTextBox.onChange = (value) => {
88-
this.context.store.pins.update(this.#pinId, { name: value });
84+
this.context.store.componentPins.update(this.#componentPinId, {
85+
name: value,
86+
});
8987
};
9088
this.registerChildRenderer(this.#pixiLabelTextBox);
9189
this.#pixiLabelTextBox.fontSize =
@@ -96,7 +94,10 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
9694
this.#pixiValueText.style.fill =
9795
CCComponentEditorRendererComponentPin.drawingConstants.valueColor;
9896
this.#pixiValueText.anchor.set(0.5, 0.5);
99-
if (this.context.store.pins.get(this.#pinId)!.type === "input") {
97+
if (
98+
this.context.store.componentPins.get(this.#componentPinId)!.type ===
99+
"input"
100+
) {
100101
// this.#pixiValueText.interactive = true;
101102
this.#pixiValueText.eventMode = "dynamic";
102103
this.#pixiValueText.cursor = "pointer";
@@ -108,8 +109,8 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
108109
this.context.componentEditorStore.subscribe(this.render);
109110
this.#valueBoxWidth =
110111
CCComponentEditorRendererComponentPin.drawingConstants.valueBoxWidthUnit;
111-
this.context.store.pins.on("didUpdate", (pin) => {
112-
if (pin.id === this.#pinId) this.render();
112+
this.context.store.componentPins.on("didUpdate", (pin) => {
113+
if (pin.id === this.#componentPinId) this.render();
113114
});
114115
this.render();
115116
}
@@ -119,12 +120,14 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
119120
* @param e event
120121
*/
121122
onClick = (e: PIXI.FederatedPointerEvent) => {
122-
const editorState = this.context.componentEditorStore.getState();
123-
const previousValue = editorState.getInputValue(
124-
this.#nodeId,
125-
this.#pinId,
126-
this.context.store.pins.get(this.#pinId)!.bits
123+
const componentPin = this.context.store.componentPins.get(
124+
this.#componentPinId
127125
);
126+
invariant(componentPin);
127+
invariant(componentPin.implementation);
128+
const editorState = this.context.componentEditorStore.getState();
129+
const previousValue = editorState.getInputValue(this.#componentPinId);
130+
invariant(previousValue);
128131
const increaseValue = (value: boolean[]) => {
129132
const newValue = [...value];
130133
for (let i = newValue.length - 1; i >= 0; i -= 1) {
@@ -134,8 +137,7 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
134137
return newValue;
135138
};
136139
editorState.setInputValue(
137-
this.#nodeId,
138-
this.#pinId,
140+
this.#componentPinId,
139141
increaseValue(previousValue)
140142
);
141143
e.preventDefault();
@@ -145,7 +147,7 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
145147
* Render the pin
146148
*/
147149
render = () => {
148-
const pin = this.context.store.pins.get(this.#pinId);
150+
const pin = this.context.store.componentPins.get(this.#componentPinId);
149151
if (!pin) return;
150152

151153
this.#pixiGraphics.clear();
@@ -171,34 +173,26 @@ export default class CCComponentEditorRendererComponentPin extends CCComponentEd
171173
this.#pixiLabelTextBox.isEditable = false;
172174
if (pin.type === "input") {
173175
this.#valueBoxWidth = c.valueBoxWidthUnit;
174-
const input = editorState.getInputValue(
175-
this.#nodeId,
176-
this.#pinId,
177-
pin.bits
178-
);
176+
const input = editorState.getInputValue(this.#componentPinId);
177+
invariant(input);
179178
this.#pixiValueText.text = input.map((v) => (v ? "1" : "0")).join("");
180179
this.#pixiGraphics.beginFill(activeColor);
181180
} else {
182-
const output = this.#simulation();
183-
if (output) {
184-
const createValueText = (values: boolean[]) => {
185-
let valueText = "";
186-
for (let i = 0; i < values.length; i += 1) {
187-
valueText += values[i] ? "1" : "0";
188-
}
189-
return valueText;
190-
};
191-
invariant(pin.implementation.type === "user");
192-
const implementationPinId = pin.implementation.pinId;
193-
for (const [key, values] of output) {
194-
if (key === implementationPinId) {
195-
this.#pixiValueText.text = createValueText(values);
196-
this.#valueBoxWidth =
197-
c.valueBoxWidthUnit +
198-
((values.length - 1) * c.valueBoxWidthUnit) / 4;
199-
break;
200-
}
181+
const createValueText = (values: boolean[]) => {
182+
let valueText = "";
183+
for (let i = 0; i < values.length; i += 1) {
184+
valueText += values[i] ? "1" : "0";
201185
}
186+
return valueText;
187+
};
188+
const outputValue = editorState.getComponentPinValue(
189+
this.#componentPinId
190+
);
191+
if (outputValue) {
192+
this.#pixiValueText.text = createValueText(outputValue);
193+
this.#valueBoxWidth =
194+
c.valueBoxWidthUnit +
195+
((outputValue.length - 1) * c.valueBoxWidthUnit) / 4;
202196
this.#pixiGraphics.beginFill(grayColor.darken2);
203197
} else {
204198
this.#pixiValueText.text = "";

0 commit comments

Comments
 (0)