From f8412eaa4f43e5a071b43f92c400499e661b8f59 Mon Sep 17 00:00:00 2001 From: chelproc Date: Sat, 31 Oct 2026 11:59:09 +0900 Subject: [PATCH] Add a dedicated renderer for the Input and Output nodes The label of the component pin implemented by an Input or Output node used to be drawn by the node pin renderer on top of a default node. Move it into a renderer shared by the two nodes, which also gives them a compact layout. It shows the name of the component pin in edit mode and its value in play mode, where clicking the value of an Input node increments it. --- .../Editor/renderer/ComponentPin/index.tsx | 101 ------------------ .../Node/components/Interface/geometry.ts | 31 ++++++ .../Node/components/Interface/index.tsx | 91 ++++++++++++++++ .../edit/Editor/renderer/Node/geometry.ts | 5 + src/pages/edit/Editor/renderer/Node/index.tsx | 5 + .../edit/Editor/renderer/NodePin/index.tsx | 7 -- 6 files changed, 132 insertions(+), 108 deletions(-) delete mode 100644 src/pages/edit/Editor/renderer/ComponentPin/index.tsx create mode 100644 src/pages/edit/Editor/renderer/Node/components/Interface/geometry.ts create mode 100644 src/pages/edit/Editor/renderer/Node/components/Interface/index.tsx diff --git a/src/pages/edit/Editor/renderer/ComponentPin/index.tsx b/src/pages/edit/Editor/renderer/ComponentPin/index.tsx deleted file mode 100644 index a91daee..0000000 --- a/src/pages/edit/Editor/renderer/ComponentPin/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import nullthrows from "nullthrows"; -import { theme } from "../../../../../common/theme"; -import type { CCNodePinId } from "../../../../../store/nodePin"; -import { useStore } from "../../../../../store/react"; -import { wrappingIncrementSimulationValue } from "../../../../../store/simulation"; -import { useComponentEditorStore } from "../../store"; -import { stringifySimulationValue } from "../../store/slices/core"; -import { getCCComponentEditorRendererNodeGeometry } from "./../Node/geometry"; -export type CCComponentEditorRendererComponentPinProps = { - nodePinId: CCNodePinId; -}; -export default function CCComponentEditorRendererComponentPin({ - nodePinId, -}: CCComponentEditorRendererComponentPinProps) { - const { store } = useStore(); - const componentEditorState = useComponentEditorStore()(); - const nodePin = nullthrows(store.nodePins.get(nodePinId)); - const interfaceComponentPin = nullthrows( - store.componentPins.getByImplementation(nodePinId), - ); - const type = interfaceComponentPin.type; - - const { label, onClick } = - componentEditorState.editorMode === "edit" - ? { - label: interfaceComponentPin.name, - onClick: null, - } - : { - label: stringifySimulationValue( - type === "input" - ? nullthrows( - componentEditorState.getInputValue({ - componentPinId: interfaceComponentPin.id, - timeStep: componentEditorState.timeStep, - }), - ) - : nullthrows(componentEditorState.getNodePinValue(nodePinId)), - ), - onClick: - type === "input" - ? () => { - const nodePinValue = nullthrows( - componentEditorState.getInputValue({ - componentPinId: interfaceComponentPin.id, - timeStep: componentEditorState.timeStep, - }), - ); - componentEditorState.setInputValue( - { - componentPinId: interfaceComponentPin.id, - timeStep: componentEditorState.timeStep, - }, - wrappingIncrementSimulationValue(nodePinValue), - ); - } - : null, - }; - - const nodePinPosition = nullthrows( - getCCComponentEditorRendererNodeGeometry( - store, - nodePin.nodeId, - ).nodePinPositionById.get(nodePinId), - ); - const direction = type === "input" ? -1 : 1; - - return ( - <> - - - {label} - - - ); -} diff --git a/src/pages/edit/Editor/renderer/Node/components/Interface/geometry.ts b/src/pages/edit/Editor/renderer/Node/components/Interface/geometry.ts new file mode 100644 index 0000000..bdc65b7 --- /dev/null +++ b/src/pages/edit/Editor/renderer/Node/components/Interface/geometry.ts @@ -0,0 +1,31 @@ +import { type Vector2, vector2 } from "../../../../../../../common/vector2"; +import type { CCNodePinId } from "../../../../../../../store/nodePin"; +import type { + CCComponentEditorRendererNodeLayout, + CCComponentEditorRendererNodeLayoutSource, +} from "../../types"; + +export const ccComponentEditorRendererNodeInterfaceLayoutConstants = { + width: 70, + height: 30, + labelWidth: 54, + labelHeight: 16, +}; + +export function ccComponentRendererNodeInterfaceLayoutCalculator( + source: CCComponentEditorRendererNodeLayoutSource, +): CCComponentEditorRendererNodeLayout { + const { width, height } = + ccComponentEditorRendererNodeInterfaceLayoutConstants; + return { + size: vector2.create(width, height), + nodePinOffsetById: new Map([ + ...source.inputNodePinIds.map( + (id) => [id, vector2.create(0, height / 2)] as const, + ), + ...source.outputNodePinIds.map( + (id) => [id, vector2.create(width, height / 2)] as const, + ), + ]), + }; +} diff --git a/src/pages/edit/Editor/renderer/Node/components/Interface/index.tsx b/src/pages/edit/Editor/renderer/Node/components/Interface/index.tsx new file mode 100644 index 0000000..d572fc4 --- /dev/null +++ b/src/pages/edit/Editor/renderer/Node/components/Interface/index.tsx @@ -0,0 +1,91 @@ +import nullthrows from "nullthrows"; +import { theme } from "../../../../../../../common/theme"; +import { useStore } from "../../../../../../../store/react"; +import { wrappingIncrementSimulationValue } from "../../../../../../../store/simulation"; +import { useComponentEditorStore } from "../../../../store"; +import { stringifySimulationValue } from "../../../../store/slices/core"; +import type { CCComponentEditorRendererNodeRendererProps } from "../../types"; +import { CCComponentEditorRendererNodeDefaultRenderer } from "../Default"; +import { ccComponentEditorRendererNodeInterfaceLayoutConstants as constants } from "./geometry"; + +export function CCComponentEditorRendererNodeInterfaceRenderer( + props: CCComponentEditorRendererNodeRendererProps, +) { + const { store } = useStore(); + const editorState = useComponentEditorStore()(); + + const nodePin = nullthrows( + store.nodePins.getManyByNodeId(props.node.id)[0], + `Interface node ${props.node.id} is missing its pin`, + ); + const componentPin = nullthrows( + store.componentPins.getByImplementation(nodePin.id), + ); + + const { label, onClick } = + editorState.editorMode === "edit" + ? { label: componentPin.name, onClick: null } + : componentPin.type === "input" + ? (() => { + const inputValueKey = { + componentPinId: componentPin.id, + timeStep: editorState.timeStep, + }; + const value = nullthrows(editorState.getInputValue(inputValueKey)); + return { + label: stringifySimulationValue(value), + onClick: () => + editorState.setInputValue( + inputValueKey, + wrappingIncrementSimulationValue(value), + ), + }; + })() + : { + label: stringifySimulationValue( + nullthrows(editorState.getNodePinValue(nodePin.id)), + ), + onClick: null, + }; + + const { width, height, labelWidth, labelHeight } = constants; + + return ( + <> + + { + // Prevent the node from being selected or dragged + e.stopPropagation(); + onClick(); + }, + style: { cursor: "pointer" }, + } + : {})} + /> + + {label} + + + ); +} diff --git a/src/pages/edit/Editor/renderer/Node/geometry.ts b/src/pages/edit/Editor/renderer/Node/geometry.ts index 45c6853..2a29851 100644 --- a/src/pages/edit/Editor/renderer/Node/geometry.ts +++ b/src/pages/edit/Editor/renderer/Node/geometry.ts @@ -9,6 +9,7 @@ import type { CCNodeId } from "../../../../../store/node"; import { ccComponentRendererNodeConstLayoutCalculator } from "./components/Const/geometry"; import { ccComponentRendererNodeDefaultLayoutCalculator } from "./components/Default/geometry"; import { ccComponentRendererNodeDisplayLayoutCalculator } from "./components/Display/geometry"; +import { ccComponentRendererNodeInterfaceLayoutCalculator } from "./components/Interface/geometry"; import type { CCComponentEditorRendererNodeGeometry, CCComponentEditorRendererNodeLayout, @@ -24,6 +25,10 @@ const specialLayoutCalculators: { ccComponentRendererNodeDisplayLayoutCalculator, [ccIntrinsicComponentTypes.CONST]: ccComponentRendererNodeConstLayoutCalculator, + [ccIntrinsicComponentTypes.INPUT]: + ccComponentRendererNodeInterfaceLayoutCalculator, + [ccIntrinsicComponentTypes.OUTPUT]: + ccComponentRendererNodeInterfaceLayoutCalculator, }; export function getCCComponentEditorRendererNodeLayout( diff --git a/src/pages/edit/Editor/renderer/Node/index.tsx b/src/pages/edit/Editor/renderer/Node/index.tsx index 9a09029..2926b85 100644 --- a/src/pages/edit/Editor/renderer/Node/index.tsx +++ b/src/pages/edit/Editor/renderer/Node/index.tsx @@ -13,6 +13,7 @@ import CCComponentEditorRendererNodePin from "../NodePin"; import { CCComponentEditorRendererNodeConstRenderer } from "./components/Const"; import { CCComponentEditorRendererNodeDefaultRenderer } from "./components/Default"; import { CCComponentEditorRendererNodeDisplayRenderer } from "./components/Display"; +import { CCComponentEditorRendererNodeInterfaceRenderer } from "./components/Interface"; import { ccComponentEditorRendererLayoutToGeometry, getCCComponentEditorRendererNodeLayout, @@ -31,6 +32,10 @@ const specialRenderers: Partial< [ccIntrinsicComponentTypes.DISPLAY]: CCComponentEditorRendererNodeDisplayRenderer, [ccIntrinsicComponentTypes.CONST]: CCComponentEditorRendererNodeConstRenderer, + [ccIntrinsicComponentTypes.INPUT]: + CCComponentEditorRendererNodeInterfaceRenderer, + [ccIntrinsicComponentTypes.OUTPUT]: + CCComponentEditorRendererNodeInterfaceRenderer, }; export type CCComponentEditorRendererNodeProps = { diff --git a/src/pages/edit/Editor/renderer/NodePin/index.tsx b/src/pages/edit/Editor/renderer/NodePin/index.tsx index c1a5c98..433f526 100644 --- a/src/pages/edit/Editor/renderer/NodePin/index.tsx +++ b/src/pages/edit/Editor/renderer/NodePin/index.tsx @@ -9,7 +9,6 @@ import { input, output } from "../../../../../store/intrinsics/definitions"; import type { CCNodePinId } from "../../../../../store/nodePin"; import { useStore } from "../../../../../store/react"; import { useComponentEditorStore } from "../../store"; -import CCComponentEditorRendererComponentPin from "./../ComponentPin"; import { CCComponentEditorRendererConnectionCore, type CCComponentEditorRendererConnectionEndpoint, @@ -146,14 +145,8 @@ export default function CCComponentEditorRendererNodePin({ }, }); - const interfaceComponentPin = - store.componentPins.getByImplementation(nodePinId); - return ( <> - {interfaceComponentPin && ( - - )}