From 705c06b6303ea1ec2931aeed4bee20565783b8cf Mon Sep 17 00:00:00 2001 From: Michael Mauderer Date: Mon, 20 Nov 2023 12:59:50 +0000 Subject: [PATCH] Implement output port double click. --- app/gui2/src/components/GraphEditor.vue | 61 ++++++++++++++----- .../src/components/GraphEditor/GraphNode.vue | 27 +++++++- .../src/components/GraphEditor/GraphNodes.vue | 7 ++- 3 files changed, 76 insertions(+), 19 deletions(-) diff --git a/app/gui2/src/components/GraphEditor.vue b/app/gui2/src/components/GraphEditor.vue index fe16b2633eb90..f52e5feee862b 100644 --- a/app/gui2/src/components/GraphEditor.vue +++ b/app/gui2/src/components/GraphEditor.vue @@ -35,6 +35,7 @@ const EXECUTION_MODES = ['design', 'live'] const COMPONENT_BROWSER_TO_NODE_OFFSET = new Vec2(20, 35) // Assumed size of a newly created node. This is used to place the component browser. const DEFAULT_NODE_SIZE = new Vec2(0, 24) +const gapBetweenNodes = 48.0 const viewportNode = ref() const graphNavigator = provideGraphNavigator(viewportNode) @@ -58,6 +59,20 @@ const interactionBindingsHandler = interactionBindings.handler({ click: (e) => (e instanceof MouseEvent ? interaction.handleClick(e, graphNavigator) : false), }) +function environmentForNodes(nodeIds: IterableIterator): Environment { + const nodeRects = [...graphStore.nodeRects.values()] + const selectedNodeRects: Iterable = [...nodeIds] + .map((id) => graphStore.nodeRects.get(id)) + .filter((item): item is Rect => item !== undefined) + const screenBounds = graphNavigator.viewport + const mousePosition = graphNavigator.sceneMousePos + return { nodeRects, selectedNodeRects, screenBounds, mousePosition } as Environment +} + +const placementEnvironment = computed(() => { + return environmentForNodes(nodeSelection.selected.values()) +}) + // Return the position for a new node, assuming there are currently nodes selected. If there are no nodes // selected, return undefined. function placementPositionForSelection() { @@ -90,10 +105,12 @@ function targetComponentBrowserPosition() { // This is the current position of the component browser. const componentBrowserPosition = ref(Vec2.Zero) -const graphEditorSourceNode = computed(() => { +function sourceNodeForSelection() { if (graphStore.editedNodeInfo != null) return undefined return nodeSelection.selected.values().next().value -}) +} + +const componentBrowserSourceNode = ref(sourceNodeForSelection()) useEvent(window, 'keydown', (event) => { interactionBindingsHandler(event) || graphBindingsHandler(event) || codeEditorHandler(event) @@ -206,21 +223,10 @@ const editingNode: Interaction = { const nodeIsBeingEdited = computed(() => graphStore.editedNodeInfo != null) interaction.setWhen(nodeIsBeingEdited, editingNode) -const placementEnvironment = computed(() => { - const mousePosition = graphNavigator.sceneMousePos ?? Vec2.Zero - const nodeRects = [...graphStore.nodeRects.values()] - const selectedNodesIter = nodeSelection.selected.values() - const selectedNodeRects: Iterable = [...selectedNodesIter] - .map((id) => graphStore.nodeRects.get(id)) - .filter((item): item is Rect => item !== undefined) - const screenBounds = graphNavigator.viewport - const environment: Environment = { mousePosition, nodeRects, selectedNodeRects, screenBounds } - return environment -}) - const creatingNode: Interaction = { init: () => { componentBrowserInputContent.value = '' + componentBrowserSourceNode.value = sourceNodeForSelection() componentBrowserPosition.value = targetComponentBrowserPosition() componentBrowserVisible.value = true }, @@ -244,6 +250,16 @@ const creatingNodeFromButton: Interaction = { }, } +const creatingNodeFromPortDoubleClick: Interaction = { + init: () => { + componentBrowserInputContent.value = '' + componentBrowserVisible.value = true + }, + cancel: () => { + // Nothing to do here. We just don't create a node and the component browser will close itself. + }, +} + async function handleFileDrop(event: DragEvent) { // A vertical gap between created nodes when multiple files were dropped together. const MULTIPLE_FILES_GAP = 50 @@ -403,6 +419,19 @@ async function readNodeFromClipboard() { console.warn('No valid expression in clipboard.') } } + +function handleNodeOutputPortDoubleClick(id: ExprId) { + componentBrowserSourceNode.value = id + const placementEnvironment = environmentForNodes([id].values()) + componentBrowserPosition.value = previousNodeDictatedPlacement( + DEFAULT_NODE_SIZE, + placementEnvironment, + { + gap: gapBetweenNodes, + }, + ).position + interaction.setCurrent(creatingNodeFromPortDoubleClick) +}