this repo has no description

add multi-select

phaz.uk 60049985 d17ed172

verified
Changed files
+88 -37
src
+54 -13
src/App.tsx
··· 13 14 import * as keybinds from './keybinds'; 15 import { listen } from "@tauri-apps/api/event"; 16 17 let App = () => { 18 - let [ selectedNode, setSelectedNode ] = createSignal<Node | null>(null); 19 20 let canvas!: HTMLCanvasElement; 21 let ctx: CanvasRenderingContext2D; ··· 57 } 58 59 onMount(async () => { 60 - NodeManager.Instance.HookTabChange(() => setSelectedNode(null)); 61 62 ctx = canvas.getContext('2d')!; 63 ··· 100 } 101 102 if(clickedNode){ 103 - contextMenu.items = NodeContextMenu(clickedNode, selectedNode, setSelectedNode); 104 } else{ 105 contextMenu.items = CanvasContextMenu; 106 } ··· 121 return; 122 } 123 124 - if(e.shiftKey){ 125 - // TODO: Multi-select 126 - return; 127 - } 128 - 129 if(contextMenu.visible){ 130 let submenus: ContextMenu[] = []; 131 contextMenu.items.map(x => x.menu ? submenus.push(x.menu): null); ··· 160 161 if(nodes){ 162 nodes.map(node => { 163 - node.selected = false; 164 165 if(isPointInRectApplyOffset(canvas, { x: offset[0], y: offset[1], scale }, 166 e.clientX, e.clientY, ··· 220 221 movingNode = clickedNode; 222 223 - if(clickedNode){ 224 clickedNode.selected = true; 225 - setSelectedNode(clickedNode); 226 } 227 228 isMouseDown = true; ··· 230 } 231 232 canvas.onmousemove = ( e ) => { 233 if(isMouseDown){ 234 if(isDrawing){ 235 drawingTo = screenToWorldSpace(canvas, { x: offset[0], y: offset[1], scale }, e.clientX - 10 * scale, e.clientY - 10 * scale) as [ number, number ]; ··· 321 isMouseDown = false; 322 } 323 324 - keybinds.load(selectedNode, setSelectedNode); 325 requestAnimationFrame(update); 326 327 let unlisten_0 = await listen('hide-window', () => { ··· 378 379 return ( 380 <> 381 <TabMenu /> 382 - <ControlBar node={selectedNode} lockMovement={( lock ) => lockMovement = lock} /> 383 <canvas ref={canvas}/> 384 </> 385 );
··· 13 14 import * as keybinds from './keybinds'; 15 import { listen } from "@tauri-apps/api/event"; 16 + import { ConfirmationPopup } from "./components/ConfirmationPopup"; 17 18 let App = () => { 19 + let [ selectedNodes, setSelectedNodes ] = createSignal<Node[]>([]); 20 21 let canvas!: HTMLCanvasElement; 22 let ctx: CanvasRenderingContext2D; ··· 58 } 59 60 onMount(async () => { 61 + NodeManager.Instance.HookTabChange(() => setSelectedNodes([])); 62 63 ctx = canvas.getContext('2d')!; 64 ··· 101 } 102 103 if(clickedNode){ 104 + contextMenu.items = NodeContextMenu(clickedNode, selectedNodes, setSelectedNodes); 105 } else{ 106 contextMenu.items = CanvasContextMenu; 107 } ··· 122 return; 123 } 124 125 if(contextMenu.visible){ 126 let submenus: ContextMenu[] = []; 127 contextMenu.items.map(x => x.menu ? submenus.push(x.menu): null); ··· 156 157 if(nodes){ 158 nodes.map(node => { 159 + if(!e.shiftKey)node.selected = false; 160 161 if(isPointInRectApplyOffset(canvas, { x: offset[0], y: offset[1], scale }, 162 e.clientX, e.clientY, ··· 216 217 movingNode = clickedNode; 218 219 + if(!e.shiftKey){ 220 + if(clickedNode){ 221 + clickedNode.selected = true; 222 + setSelectedNodes([ clickedNode ]); 223 + } else{ 224 + setSelectedNodes([]); 225 + } 226 + } else{ 227 clickedNode.selected = true; 228 + 229 + let snodes = selectedNodes(); 230 + if(!snodes.find(x => x.id === clickedNode!.id)){ 231 + snodes.push(clickedNode); 232 + clickedNode.selected = true; 233 + 234 + setSelectedNodes(snodes); 235 + } 236 } 237 238 isMouseDown = true; ··· 240 } 241 242 canvas.onmousemove = ( e ) => { 243 + if(e.shiftKey && isMouseDown){ 244 + let nodes = NodeManager.Instance.GetNodes(); 245 + let hoveredNode: Node | null = null; 246 + 247 + if(nodes){ 248 + nodes.map(node => { 249 + if(isPointInRectApplyOffset(canvas, { x: offset[0], y: offset[1], scale }, 250 + e.clientX, e.clientY, 251 + node.x - 20, node.y, node.w + 40, node.h 252 + )){ 253 + hoveredNode = node; 254 + return; 255 + } 256 + }) 257 + } 258 + 259 + if(hoveredNode !== null){ 260 + let snodes = selectedNodes(); 261 + if(!snodes.find(x => x.id === hoveredNode!.id)){ 262 + snodes.push(hoveredNode); 263 + 264 + // @ts-ignore 265 + hoveredNode.selected = true; 266 + setSelectedNodes(snodes); 267 + } 268 + } 269 + 270 + return; 271 + } 272 + 273 if(isMouseDown){ 274 if(isDrawing){ 275 drawingTo = screenToWorldSpace(canvas, { x: offset[0], y: offset[1], scale }, e.clientX - 10 * scale, e.clientY - 10 * scale) as [ number, number ]; ··· 361 isMouseDown = false; 362 } 363 364 + keybinds.load(selectedNodes, setSelectedNodes); 365 requestAnimationFrame(update); 366 367 let unlisten_0 = await listen('hide-window', () => { ··· 418 419 return ( 420 <> 421 + <ConfirmationPopup /> 422 <TabMenu /> 423 + <ControlBar node={selectedNodes} lockMovement={( lock ) => lockMovement = lock} /> 424 <canvas ref={canvas}/> 425 </> 426 );
+11 -2
src/ContextMenu/Node.tsx
··· 3 import { PositionInfo } from "../renderer"; 4 import { Node } from "../structs/node"; 5 6 - export let NodeContextMenu = ( clickedNode: Node, selectedNode: Accessor<Node | null>, setSelectedNode: Setter<Node | null> ) => [ 7 { 8 text: "Delete Node", 9 clicked: ( _e: MouseEvent, _canvas: HTMLCanvasElement, _position: PositionInfo ) => { ··· 20 }) 21 22 let selected = selectedNode(); 23 - if(selected && clickedNode.id === selected.id)setSelectedNode(null); 24 25 NodeManager.Instance.RemoveNode(clickedNode!) 26 },
··· 3 import { PositionInfo } from "../renderer"; 4 import { Node } from "../structs/node"; 5 6 + export let NodeContextMenu = ( clickedNode: Node, selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => [ 7 { 8 text: "Delete Node", 9 clicked: ( _e: MouseEvent, _canvas: HTMLCanvasElement, _position: PositionInfo ) => { ··· 20 }) 21 22 let selected = selectedNode(); 23 + for (let i = 0; i < selected.length; i++) { 24 + let node = selected[i]; 25 + 26 + if(node.id === clickedNode.id){ 27 + selected.splice(i, 1); 28 + setSelectedNode(selected); 29 + 30 + break; 31 + } 32 + } 33 34 NodeManager.Instance.RemoveNode(clickedNode!) 35 },
+1 -1
src/components/ConfirmationPopup.tsx
··· 10 <div class="confirmation-popup"> 11 <h2>{ConfirmationManager.Instance.Text()}</h2> 12 <p>{ConfirmationManager.Instance.Body()}</p> 13 - 14 <div class="confirmation-buttons"> 15 <For each={ConfirmationManager.Instance.Buttons()}> 16 { item =>
··· 10 <div class="confirmation-popup"> 11 <h2>{ConfirmationManager.Instance.Text()}</h2> 12 <p>{ConfirmationManager.Instance.Body()}</p> 13 + 14 <div class="confirmation-buttons"> 15 <For each={ConfirmationManager.Instance.Buttons()}> 16 { item =>
+7 -7
src/components/ControlBar.tsx
··· 9 import { NodeManager } from '../Mangers/NodeManager'; 10 11 export interface ControlBarProps{ 12 - node: Accessor<Node | null>, 13 lockMovement: ( lock: boolean ) => void 14 } 15 ··· 20 21 return ( 22 <div class="control-bar"> 23 - <For each={props.node()?.statics}> 24 { ( item ) => { 25 let [ popupOpen, setPopupOpen ] = createSignal(false); 26 ··· 36 value={item.value || ''} 37 onChange={( el ) => { 38 let value = el.target.value; 39 - let node = props.node()!; 40 41 item.value = value; 42 node.onStaticsUpdate(node); ··· 54 value={item.value !== undefined ? item.value : ''} 55 onChange={( el ) => { 56 let value = el.target.value; 57 - let node = props.node()!; 58 59 item.value = parseInt(value); 60 node.onStaticsUpdate(node); ··· 72 value={item.value !== undefined ? item.value : ''} 73 onChange={( el ) => { 74 let value = el.target.value; 75 - let node = props.node()!; 76 77 item.value = parseFloat(value); 78 node.onStaticsUpdate(node); ··· 92 return addresses.map(x => x.address).filter(x => x.toLowerCase().includes(text.toLowerCase())); 93 }} 94 change={( text ) => { 95 - let node = props.node()!; 96 97 item.value = text; 98 node.onStaticsUpdate(node); ··· 118 }} 119 value={item.value} 120 changed={( value ) => { 121 - let node = props.node()!; 122 123 item.value = value; 124 node.onStaticsUpdate(node);
··· 9 import { NodeManager } from '../Mangers/NodeManager'; 10 11 export interface ControlBarProps{ 12 + node: Accessor<Node[]>, 13 lockMovement: ( lock: boolean ) => void 14 } 15 ··· 20 21 return ( 22 <div class="control-bar"> 23 + <For each={props.node()[0]?.statics}> 24 { ( item ) => { 25 let [ popupOpen, setPopupOpen ] = createSignal(false); 26 ··· 36 value={item.value || ''} 37 onChange={( el ) => { 38 let value = el.target.value; 39 + let node = props.node()[0]!; 40 41 item.value = value; 42 node.onStaticsUpdate(node); ··· 54 value={item.value !== undefined ? item.value : ''} 55 onChange={( el ) => { 56 let value = el.target.value; 57 + let node = props.node()[0]!; 58 59 item.value = parseInt(value); 60 node.onStaticsUpdate(node); ··· 72 value={item.value !== undefined ? item.value : ''} 73 onChange={( el ) => { 74 let value = el.target.value; 75 + let node = props.node()[0]!; 76 77 item.value = parseFloat(value); 78 node.onStaticsUpdate(node); ··· 92 return addresses.map(x => x.address).filter(x => x.toLowerCase().includes(text.toLowerCase())); 93 }} 94 change={( text ) => { 95 + let node = props.node()[0]!; 96 97 item.value = text; 98 node.onStaticsUpdate(node); ··· 118 }} 119 value={item.value} 120 changed={( value ) => { 121 + let node = props.node()[0]!; 122 123 item.value = value; 124 node.onStaticsUpdate(node);
+15 -14
src/keybinds.ts
··· 4 5 let isKeyDown: any = {}; 6 7 - export let load = ( selectedNode: Accessor<Node | null>, setSelectedNode: Setter<Node | null> ) => { 8 // TODO: Copy / paste 9 // TODO: Add undo / redo -ing 10 ··· 15 16 switch(e.key){ 17 case 'Delete': 18 - let node = selectedNode(); 19 - if(!node)return; 20 21 - node.inputs.map(input => { 22 - input.connections.map(partner => { 23 - partner.connections = partner.connections.filter(x => x != input); 24 }) 25 - }) 26 27 - node.outputs.map(output => { 28 - output.connections.map(partner => { 29 - partner.connections = partner.connections.filter(x => x != output); 30 - }) 31 - }) 32 33 - setSelectedNode(null); 34 - NodeManager.Instance.RemoveNode(node); 35 break; 36 case 's': 37 if(e.ctrlKey){
··· 4 5 let isKeyDown: any = {}; 6 7 + export let load = ( selectedNode: Accessor<Node[]>, setSelectedNode: Setter<Node[]> ) => { 8 // TODO: Copy / paste 9 // TODO: Add undo / redo -ing 10 ··· 15 16 switch(e.key){ 17 case 'Delete': 18 + let nodes = selectedNode(); 19 + for(let node of nodes){ 20 + node.inputs.map(input => { 21 + input.connections.map(partner => { 22 + partner.connections = partner.connections.filter(x => x != input); 23 + }) 24 + }) 25 26 + node.outputs.map(output => { 27 + output.connections.map(partner => { 28 + partner.connections = partner.connections.filter(x => x != output); 29 + }) 30 }) 31 32 + NodeManager.Instance.RemoveNode(node); 33 + } 34 35 + setSelectedNode([]); 36 break; 37 case 's': 38 if(e.ctrlKey){