Skip to content

Commit

Permalink
[NME] Different selection priorities for nodes and frames dependent o…
Browse files Browse the repository at this point in the history
…f marquee or click selecting (#12373)

* [NME] Different preferences for selecting graph nodes and graph frames depending if we're marquee selecting or not

* Fix logic to avoid adding the same element multiple times per selection.

* Fix linting.
  • Loading branch information
carolhmj authored Apr 12, 2022
1 parent 69920ea commit 78e0ac2
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 35 deletions.
89 changes: 58 additions & 31 deletions packages/tools/nodeEditor/src/diagram/graphCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,23 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
return this._frameContainer;
}

// There is a selection conflict between nodes and frames if any selected node is inside any selected frame
private _selectedFrameAndNodesConflict(frameSelection: GraphFrame[], nodeSelection: GraphNode[]) {
for (const frame of frameSelection) {
for (const node of nodeSelection) {
if (frame.nodes.includes(node)) {
return true;
}
}
}
return false;
}

constructor(props: IGraphCanvasComponentProps) {
super(props);

props.globalState.onSelectionChangedObservable.add((options) => {
const { selection, forceKeepSelection } = options || {};
const { selection, forceKeepSelection, marqueeSelection = false } = options || {};
if (!selection) {
this._selectedNodes = [];
this._selectedLink = null;
Expand All @@ -188,36 +200,6 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
this._selectedFrames = [];
this._selectedLink = selection;
this._selectedPort = null;
} else if (selection instanceof GraphFrame && !this._selectedNodes.length) {
if (selection.isCollapsed) {
if (this._ctrlKeyIsPressed || forceKeepSelection) {
if (this._selectedFrames.indexOf(selection) === -1) {
this._selectedFrames.push(selection);
}
} else {
this._selectedFrames = [selection];
this._selectedNodes = [];
this._selectedLink = null;
this._selectedPort = null;
}
} else {
this._selectedNodes = [];
this._selectedFrames = [selection];
this._selectedLink = null;
this._selectedPort = null;
}
} else if (selection instanceof GraphNode) {
if (this._ctrlKeyIsPressed || forceKeepSelection) {
if (this._selectedNodes.indexOf(selection) === -1) {
this._selectedNodes.push(selection);
this._selectedFrames = [];
}
} else {
this._selectedNodes = [selection];
this._selectedFrames = [];
this._selectedLink = null;
this._selectedPort = null;
}
} else if (selection instanceof NodePort) {
this._selectedNodes = [];
this._selectedFrames = [];
Expand All @@ -228,6 +210,51 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
this._selectedFrames = [];
this._selectedLink = null;
this._selectedPort = selection.port;
} else if (selection instanceof GraphNode || selection instanceof GraphFrame) {
// If in marquee selection mode, always prioritize selecting nodes. Otherwise, always prioritize selecting the type of
// the selected element
if (marqueeSelection) {
if (selection instanceof GraphFrame && !this._selectedFrames.includes(selection)) {
this._selectedFrames.push(selection);
} else if (selection instanceof GraphNode && !this._selectedNodes.includes(selection)) {
this._selectedNodes.push(selection);
}
if (this._selectedFrameAndNodesConflict(this.selectedFrames, this.selectedNodes)) {
const framesToRemove = new Set();
for (const selectedNode of this._selectedNodes) {
for (const selectedFrame of this._selectedFrames) {
if (selectedFrame.nodes.includes(selectedNode)) {
framesToRemove.add(selectedFrame);
}
}
}
this._selectedFrames = this._selectedFrames.filter((f) => !framesToRemove.has(f));
}
} else {
if (selection instanceof GraphFrame) {
if (this._ctrlKeyIsPressed || forceKeepSelection) {
if (!this._selectedFrameAndNodesConflict([selection], this._selectedNodes) && !this._selectedFrames.includes(selection)) {
this._selectedFrames.push(selection);
}
} else {
this._selectedFrames = [selection];
this._selectedNodes = [];
this._selectedLink = null;
this._selectedPort = null;
}
} else if (selection instanceof GraphNode) {
if (this._ctrlKeyIsPressed || forceKeepSelection) {
if (!this._selectedFrameAndNodesConflict(this._selectedFrames, [selection]) && !this._selectedNodes.includes(selection)) {
this._selectedNodes.push(selection);
}
} else {
this._selectedFrames = [];
this._selectedNodes = [selection];
this._selectedLink = null;
this._selectedPort = null;
}
}
}
}
}
});
Expand Down
2 changes: 1 addition & 1 deletion packages/tools/nodeEditor/src/diagram/graphFrame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ export class GraphFrame {
const rect2 = this.element.getBoundingClientRect();
const overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);
if (overlap) {
canvas.globalState.onSelectionChangedObservable.notifyObservers({ selection: this, forceKeepSelection: true });
canvas.globalState.onSelectionChangedObservable.notifyObservers({ selection: this, forceKeepSelection: true, marqueeSelection: true });
}
});

Expand Down
10 changes: 7 additions & 3 deletions packages/tools/nodeEditor/src/diagram/graphNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ export class GraphNode {
}

public set isSelected(value: boolean) {
this.setIsSelected(value, false);
}

public setIsSelected(value: boolean, marqueeSelection: boolean) {
if (this._isSelected === value) {
return;
}
Expand All @@ -172,7 +176,7 @@ export class GraphNode {
this._ownerCanvas.selectedNodes.splice(indexInSelection, 1);
}
} else {
this._globalState.onSelectionChangedObservable.notifyObservers({ selection: this });
this._globalState.onSelectionChangedObservable.notifyObservers({ selection: this, marqueeSelection });
}
}

Expand Down Expand Up @@ -203,7 +207,7 @@ export class GraphNode {
const rect2 = this._visual.getBoundingClientRect();
const overlap = !(rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom);

this.isSelected = overlap;
this.setIsSelected(overlap, true);
});

this._onFrameCreatedObserver = this._globalState.onFrameCreatedObservable.add((frame) => {
Expand Down Expand Up @@ -326,7 +330,7 @@ export class GraphNode {
if (indexInSelection === -1) {
this._globalState.onSelectionChangedObservable.notifyObservers({ selection: this });
} else if (evt.ctrlKey) {
this.isSelected = false;
this.setIsSelected(false, false);
}

evt.stopPropagation();
Expand Down
1 change: 1 addition & 0 deletions packages/tools/nodeEditor/src/globalState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ParticleSystem } from "core/Particles/particleSystem";
export class ISelectionChangedOptions {
selection: Nullable<GraphNode | NodeLink | GraphFrame | NodePort | FramePortData>;
forceKeepSelection?: boolean;
marqueeSelection?: boolean;
}

export class GlobalState {
Expand Down

0 comments on commit 78e0ac2

Please sign in to comment.