diff --git a/src/App.tsx b/src/App.tsx index 0795797..712840c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -13,9 +13,10 @@ import { TabMenu } from "./components/TabMenu"; import * as keybinds from './keybinds'; import { listen } from "@tauri-apps/api/event"; +import { ConfirmationPopup } from "./components/ConfirmationPopup"; let App = () => { - let [ selectedNode, setSelectedNode ] = createSignal(null); + let [ selectedNodes, setSelectedNodes ] = createSignal([]); let canvas!: HTMLCanvasElement; let ctx: CanvasRenderingContext2D; @@ -57,7 +58,7 @@ let App = () => { } onMount(async () => { - NodeManager.Instance.HookTabChange(() => setSelectedNode(null)); + NodeManager.Instance.HookTabChange(() => setSelectedNodes([])); ctx = canvas.getContext('2d')!; @@ -100,7 +101,7 @@ let App = () => { } if(clickedNode){ - contextMenu.items = NodeContextMenu(clickedNode, selectedNode, setSelectedNode); + contextMenu.items = NodeContextMenu(clickedNode, selectedNodes, setSelectedNodes); } else{ contextMenu.items = CanvasContextMenu; } @@ -121,11 +122,6 @@ let App = () => { return; } - if(e.shiftKey){ - // TODO: Multi-select - return; - } - if(contextMenu.visible){ let submenus: ContextMenu[] = []; contextMenu.items.map(x => x.menu ? submenus.push(x.menu): null); @@ -160,7 +156,7 @@ let App = () => { if(nodes){ nodes.map(node => { - node.selected = false; + if(!e.shiftKey)node.selected = false; if(isPointInRectApplyOffset(canvas, { x: offset[0], y: offset[1], scale }, e.clientX, e.clientY, @@ -220,9 +216,23 @@ let App = () => { movingNode = clickedNode; - if(clickedNode){ + if(!e.shiftKey){ + if(clickedNode){ + clickedNode.selected = true; + setSelectedNodes([ clickedNode ]); + } else{ + setSelectedNodes([]); + } + } else{ clickedNode.selected = true; - setSelectedNode(clickedNode); + + let snodes = selectedNodes(); + if(!snodes.find(x => x.id === clickedNode!.id)){ + snodes.push(clickedNode); + clickedNode.selected = true; + + setSelectedNodes(snodes); + } } isMouseDown = true; @@ -230,6 +240,36 @@ let App = () => { } canvas.onmousemove = ( e ) => { + if(e.shiftKey && isMouseDown){ + let nodes = NodeManager.Instance.GetNodes(); + let hoveredNode: Node | null = null; + + if(nodes){ + nodes.map(node => { + if(isPointInRectApplyOffset(canvas, { x: offset[0], y: offset[1], scale }, + e.clientX, e.clientY, + node.x - 20, node.y, node.w + 40, node.h + )){ + hoveredNode = node; + return; + } + }) + } + + if(hoveredNode !== null){ + let snodes = selectedNodes(); + if(!snodes.find(x => x.id === hoveredNode!.id)){ + snodes.push(hoveredNode); + + // @ts-ignore + hoveredNode.selected = true; + setSelectedNodes(snodes); + } + } + + return; + } + if(isMouseDown){ if(isDrawing){ drawingTo = screenToWorldSpace(canvas, { x: offset[0], y: offset[1], scale }, e.clientX - 10 * scale, e.clientY - 10 * scale) as [ number, number ]; @@ -321,7 +361,7 @@ let App = () => { isMouseDown = false; } - keybinds.load(selectedNode, setSelectedNode); + keybinds.load(selectedNodes, setSelectedNodes); requestAnimationFrame(update); let unlisten_0 = await listen('hide-window', () => { @@ -378,8 +418,9 @@ let App = () => { return ( <> + - lockMovement = lock} /> + lockMovement = lock} /> ); diff --git a/src/ContextMenu/Node.tsx b/src/ContextMenu/Node.tsx index 42fcefc..8b3d111 100644 --- a/src/ContextMenu/Node.tsx +++ b/src/ContextMenu/Node.tsx @@ -3,7 +3,7 @@ import { NodeManager } from "../Mangers/NodeManager"; import { PositionInfo } from "../renderer"; import { Node } from "../structs/node"; -export let NodeContextMenu = ( clickedNode: Node, selectedNode: Accessor, setSelectedNode: Setter ) => [ +export let NodeContextMenu = ( clickedNode: Node, selectedNode: Accessor, setSelectedNode: Setter ) => [ { text: "Delete Node", clicked: ( _e: MouseEvent, _canvas: HTMLCanvasElement, _position: PositionInfo ) => { @@ -20,7 +20,16 @@ export let NodeContextMenu = ( clickedNode: Node, selectedNode: Accessor {

{ConfirmationManager.Instance.Text()}

{ConfirmationManager.Instance.Body()}

- +
{ item => diff --git a/src/components/ControlBar.tsx b/src/components/ControlBar.tsx index f8a03f9..de94516 100644 --- a/src/components/ControlBar.tsx +++ b/src/components/ControlBar.tsx @@ -9,7 +9,7 @@ import { ParameterList } from './ParameterList'; import { NodeManager } from '../Mangers/NodeManager'; export interface ControlBarProps{ - node: Accessor, + node: Accessor, lockMovement: ( lock: boolean ) => void } @@ -20,7 +20,7 @@ export let ControlBar = ( props: ControlBarProps ) => { return (
- + { ( item ) => { let [ popupOpen, setPopupOpen ] = createSignal(false); @@ -36,7 +36,7 @@ export let ControlBar = ( props: ControlBarProps ) => { value={item.value || ''} onChange={( el ) => { let value = el.target.value; - let node = props.node()!; + let node = props.node()[0]!; item.value = value; node.onStaticsUpdate(node); @@ -54,7 +54,7 @@ export let ControlBar = ( props: ControlBarProps ) => { value={item.value !== undefined ? item.value : ''} onChange={( el ) => { let value = el.target.value; - let node = props.node()!; + let node = props.node()[0]!; item.value = parseInt(value); node.onStaticsUpdate(node); @@ -72,7 +72,7 @@ export let ControlBar = ( props: ControlBarProps ) => { value={item.value !== undefined ? item.value : ''} onChange={( el ) => { let value = el.target.value; - let node = props.node()!; + let node = props.node()[0]!; item.value = parseFloat(value); node.onStaticsUpdate(node); @@ -92,7 +92,7 @@ export let ControlBar = ( props: ControlBarProps ) => { return addresses.map(x => x.address).filter(x => x.toLowerCase().includes(text.toLowerCase())); }} change={( text ) => { - let node = props.node()!; + let node = props.node()[0]!; item.value = text; node.onStaticsUpdate(node); @@ -118,7 +118,7 @@ export let ControlBar = ( props: ControlBarProps ) => { }} value={item.value} changed={( value ) => { - let node = props.node()!; + let node = props.node()[0]!; item.value = value; node.onStaticsUpdate(node); diff --git a/src/keybinds.ts b/src/keybinds.ts index 33780da..c9aa2d9 100644 --- a/src/keybinds.ts +++ b/src/keybinds.ts @@ -4,7 +4,7 @@ import { Node } from "./structs/node"; let isKeyDown: any = {}; -export let load = ( selectedNode: Accessor, setSelectedNode: Setter ) => { +export let load = ( selectedNode: Accessor, setSelectedNode: Setter ) => { // TODO: Copy / paste // TODO: Add undo / redo -ing @@ -15,23 +15,24 @@ export let load = ( selectedNode: Accessor, setSelectedNode: Setter switch(e.key){ case 'Delete': - let node = selectedNode(); - if(!node)return; - - node.inputs.map(input => { - input.connections.map(partner => { - partner.connections = partner.connections.filter(x => x != input); + let nodes = selectedNode(); + for(let node of nodes){ + node.inputs.map(input => { + input.connections.map(partner => { + partner.connections = partner.connections.filter(x => x != input); + }) }) - }) - node.outputs.map(output => { - output.connections.map(partner => { - partner.connections = partner.connections.filter(x => x != output); + node.outputs.map(output => { + output.connections.map(partner => { + partner.connections = partner.connections.filter(x => x != output); + }) }) - }) - setSelectedNode(null); - NodeManager.Instance.RemoveNode(node); + NodeManager.Instance.RemoveNode(node); + } + + setSelectedNode([]); break; case 's': if(e.ctrlKey){