@elicdavis/node-flow 0.1.16 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +97 -4
- package/dist/index.d.ts +97 -4
- package/dist/index.js +674 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +668 -78
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/graph.ts +234 -41
- package/src/index.ts +16 -0
- package/src/input.ts +22 -14
- package/src/markdown/entry.ts +6 -2
- package/src/minimap.ts +178 -0
- package/src/node.ts +83 -1
- package/src/nodes/factory.ts +9 -5
- package/src/nodes/publisher.ts +39 -4
- package/src/nodes/subsystem.ts +214 -2
- package/src/notes/subsystem.ts +3 -0
- package/src/popup.ts +27 -6
- package/src/port.ts +17 -4
- package/src/render_scheduler.ts +49 -0
- package/src/theme.ts +8 -0
- package/src/types/text.ts +2 -0
- package/src/widgets/image.ts +2 -0
- package/src/widgets/number.ts +2 -1
- package/src/widgets/string.ts +3 -1
- package/src/widgets/toggle.ts +3 -1
- package/test/minimap.test.ts +103 -0
- package/test/node_menu_filter.test.ts +119 -0
- package/test/popup.test.ts +104 -0
- package/test/render_scheduler.test.ts +119 -0
- package/test/widget_click.test.ts +126 -0
- package/test/widget_construction.test.ts +48 -0
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ __export(index_exports, {
|
|
|
30
30
|
GlobalWidgetFactory: () => GlobalWidgetFactory,
|
|
31
31
|
ImageWidget: () => ImageWidget,
|
|
32
32
|
MessageType: () => MessageType,
|
|
33
|
+
Minimap: () => Minimap,
|
|
33
34
|
NodeFactory: () => NodeFactory,
|
|
34
35
|
NodeFlowGraph: () => NodeFlowGraph,
|
|
35
36
|
NodeState: () => NodeState,
|
|
@@ -43,7 +44,11 @@ __export(index_exports, {
|
|
|
43
44
|
Theme: () => Theme,
|
|
44
45
|
ToggleWidget: () => ToggleWidget,
|
|
45
46
|
WidgetFactory: () => WidgetFactory,
|
|
46
|
-
|
|
47
|
+
portConfigTypes: () => portConfigTypes,
|
|
48
|
+
portsCompatible: () => portsCompatible,
|
|
49
|
+
renderContinuously: () => renderContinuously,
|
|
50
|
+
requestRender: () => requestRender,
|
|
51
|
+
typeSetsCompatible: () => typeSetsCompatible
|
|
47
52
|
});
|
|
48
53
|
module.exports = __toCommonJS(index_exports);
|
|
49
54
|
|
|
@@ -109,6 +114,14 @@ var Theme = {
|
|
|
109
114
|
FontColor: "#afb9bb",
|
|
110
115
|
DisabledFontColor: "#4a585c"
|
|
111
116
|
},
|
|
117
|
+
Minimap: {
|
|
118
|
+
BackgroundColor: "rgba(10, 16, 18, 0.85)",
|
|
119
|
+
BorderColor: "#1c1c1c",
|
|
120
|
+
BorderRadius: 4,
|
|
121
|
+
Padding: 6,
|
|
122
|
+
NodeColor: "#6b7f85",
|
|
123
|
+
ViewportColor: "rgba(175, 185, 187, 0.25)"
|
|
124
|
+
},
|
|
112
125
|
Note: {
|
|
113
126
|
FontColor: "#afb9bb",
|
|
114
127
|
FontSize: 16,
|
|
@@ -650,6 +663,43 @@ var ContextMenu = class _ContextMenu {
|
|
|
650
663
|
}
|
|
651
664
|
};
|
|
652
665
|
|
|
666
|
+
// src/render_scheduler.ts
|
|
667
|
+
var subscribers = /* @__PURE__ */ new Set();
|
|
668
|
+
var frameQueued = false;
|
|
669
|
+
var continuous = 0;
|
|
670
|
+
var canSchedule = () => typeof requestAnimationFrame === "function";
|
|
671
|
+
function onRenderRequested(redraw) {
|
|
672
|
+
subscribers.add(redraw);
|
|
673
|
+
return () => {
|
|
674
|
+
subscribers.delete(redraw);
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
function requestRender() {
|
|
678
|
+
if (frameQueued || !canSchedule()) {
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
frameQueued = true;
|
|
682
|
+
requestAnimationFrame(() => {
|
|
683
|
+
frameQueued = false;
|
|
684
|
+
subscribers.forEach((redraw) => redraw());
|
|
685
|
+
if (continuous > 0) {
|
|
686
|
+
requestRender();
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
function renderContinuously() {
|
|
691
|
+
continuous++;
|
|
692
|
+
requestRender();
|
|
693
|
+
let released = false;
|
|
694
|
+
return () => {
|
|
695
|
+
if (released) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
released = true;
|
|
699
|
+
continuous--;
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
653
703
|
// src/input.ts
|
|
654
704
|
var LONG_PRESS_MS = 500;
|
|
655
705
|
var LONG_PRESS_SLOP = 12;
|
|
@@ -683,15 +733,19 @@ var MouseObserver = class {
|
|
|
683
733
|
this.#lastTouch = Zero();
|
|
684
734
|
this.#lastMousePosition = Zero();
|
|
685
735
|
ele.style.touchAction = "none";
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
ele.addEventListener("
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
736
|
+
const redraws = (handler) => (event) => {
|
|
737
|
+
handler(event);
|
|
738
|
+
requestRender();
|
|
739
|
+
};
|
|
740
|
+
ele.addEventListener("mousedown", redraws(this.#down.bind(this)), false);
|
|
741
|
+
ele.addEventListener("touchstart", redraws(this.#touchStart.bind(this)), { passive: false });
|
|
742
|
+
document.addEventListener("mouseup", redraws(this.#up.bind(this)), false);
|
|
743
|
+
document.addEventListener("touchend", redraws(this.#touchEnd.bind(this)), false);
|
|
744
|
+
document.addEventListener("touchcancel", redraws(this.#touchEnd.bind(this)), false);
|
|
745
|
+
ele.addEventListener("mousemove", redraws(this.#move.bind(this)), false);
|
|
746
|
+
ele.addEventListener("touchmove", redraws(this.#touchMove.bind(this)), { passive: false });
|
|
747
|
+
ele.addEventListener("wheel", redraws(this.#wheel.bind(this)), { passive: false });
|
|
748
|
+
ele.addEventListener("drop", redraws((ev) => {
|
|
695
749
|
ev.preventDefault();
|
|
696
750
|
if (ev.dataTransfer?.items) {
|
|
697
751
|
[...ev.dataTransfer.items].forEach((item, i) => {
|
|
@@ -703,18 +757,18 @@ var MouseObserver = class {
|
|
|
703
757
|
}
|
|
704
758
|
});
|
|
705
759
|
}
|
|
706
|
-
});
|
|
707
|
-
ele.addEventListener("dragover", (ev) => {
|
|
760
|
+
}));
|
|
761
|
+
ele.addEventListener("dragover", redraws((ev) => {
|
|
708
762
|
ev.preventDefault();
|
|
709
763
|
this.#moveCallback(this.#mousePos(ev));
|
|
710
|
-
});
|
|
711
|
-
ele.addEventListener("contextmenu", (evt) => {
|
|
764
|
+
}));
|
|
765
|
+
ele.addEventListener("contextmenu", redraws((evt) => {
|
|
712
766
|
evt.preventDefault();
|
|
713
767
|
if (Date.now() - this.#lastTouchAt < SUPPRESS_MOUSE_MS) {
|
|
714
768
|
return;
|
|
715
769
|
}
|
|
716
770
|
this.#contextMenu(this.#mousePos(evt));
|
|
717
|
-
}, false);
|
|
771
|
+
}), false);
|
|
718
772
|
}
|
|
719
773
|
#mousePos(event) {
|
|
720
774
|
const rect = this.#ele.getBoundingClientRect();
|
|
@@ -811,6 +865,7 @@ var MouseObserver = class {
|
|
|
811
865
|
this.#clicked = false;
|
|
812
866
|
this.#clickStop();
|
|
813
867
|
this.#contextMenu({ x, y });
|
|
868
|
+
requestRender();
|
|
814
869
|
}, LONG_PRESS_MS);
|
|
815
870
|
this.#clicked = true;
|
|
816
871
|
this.#moveCallback(pos);
|
|
@@ -1247,6 +1302,7 @@ var Text = class _Text {
|
|
|
1247
1302
|
if (!document.fonts.check(`16px "${this.#style.getFont()}"`)) {
|
|
1248
1303
|
document.fonts.addEventListener("loadingdone", () => {
|
|
1249
1304
|
this.#measured = false;
|
|
1305
|
+
requestRender();
|
|
1250
1306
|
});
|
|
1251
1307
|
}
|
|
1252
1308
|
}
|
|
@@ -1458,12 +1514,22 @@ function portsCompatible(a, b) {
|
|
|
1458
1514
|
if (!a || !b) {
|
|
1459
1515
|
return false;
|
|
1460
1516
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1517
|
+
return typeSetsCompatible(a.acceptedTypes(), b.acceptedTypes());
|
|
1518
|
+
}
|
|
1519
|
+
function typeSetsCompatible(a, b) {
|
|
1520
|
+
if (a.length === 0 || b.length === 0) {
|
|
1464
1521
|
return true;
|
|
1465
1522
|
}
|
|
1466
|
-
return
|
|
1523
|
+
return a.some((type) => b.includes(type));
|
|
1524
|
+
}
|
|
1525
|
+
function portConfigTypes(config) {
|
|
1526
|
+
if (config.anyType === true) {
|
|
1527
|
+
return [];
|
|
1528
|
+
}
|
|
1529
|
+
if (config.acceptedTypes !== void 0 && config.acceptedTypes.length > 0) {
|
|
1530
|
+
return config.acceptedTypes;
|
|
1531
|
+
}
|
|
1532
|
+
return [config.type === void 0 ? "" : config.type];
|
|
1467
1533
|
}
|
|
1468
1534
|
function fallbackColor(type, s) {
|
|
1469
1535
|
let value = 0;
|
|
@@ -1578,6 +1644,7 @@ var Port = class {
|
|
|
1578
1644
|
this.#filledStyle.fillColor = fallbackColor(this.#dataType, 1);
|
|
1579
1645
|
}
|
|
1580
1646
|
this.#dataTypePopupElement = this.#buildTooltip();
|
|
1647
|
+
requestRender();
|
|
1581
1648
|
}
|
|
1582
1649
|
setDataType(type) {
|
|
1583
1650
|
if (this.#dataType === type) {
|
|
@@ -1831,6 +1898,7 @@ var Popup = class {
|
|
|
1831
1898
|
#buttonCSS;
|
|
1832
1899
|
// Runtime ================================================================
|
|
1833
1900
|
#popup;
|
|
1901
|
+
#keyHandler;
|
|
1834
1902
|
constructor(config) {
|
|
1835
1903
|
this.#title = config.title;
|
|
1836
1904
|
this.#options = config.options;
|
|
@@ -1838,14 +1906,25 @@ var Popup = class {
|
|
|
1838
1906
|
this.#onClose = config.onClose;
|
|
1839
1907
|
this.#buttonCSS = config.buttonCSS === void 0 ? "flex-grow: 1; margin-right: 8px;" : config.buttonCSS;
|
|
1840
1908
|
this.#popup = null;
|
|
1909
|
+
this.#keyHandler = null;
|
|
1841
1910
|
}
|
|
1842
1911
|
Hide() {
|
|
1843
1912
|
if (this.#popup === null) {
|
|
1844
1913
|
return;
|
|
1845
1914
|
}
|
|
1915
|
+
if (this.#keyHandler !== null) {
|
|
1916
|
+
document.removeEventListener("keydown", this.#keyHandler, true);
|
|
1917
|
+
this.#keyHandler = null;
|
|
1918
|
+
}
|
|
1846
1919
|
document.body.removeChild(this.#popup);
|
|
1847
1920
|
this.#popup = null;
|
|
1848
1921
|
}
|
|
1922
|
+
#close(option) {
|
|
1923
|
+
this.Hide();
|
|
1924
|
+
if (this.#onClose !== void 0) {
|
|
1925
|
+
this.#onClose(option);
|
|
1926
|
+
}
|
|
1927
|
+
}
|
|
1849
1928
|
Show() {
|
|
1850
1929
|
this.#popup = document.createElement("div");
|
|
1851
1930
|
this.#popup.style.cssText = "position:absolute;top:0;width:100%;display:flex;height:100%;justify-content:center;align-items:center;background-color:#00000070;";
|
|
@@ -1867,14 +1946,20 @@ var Popup = class {
|
|
|
1867
1946
|
const button = document.createElement("button");
|
|
1868
1947
|
button.style.cssText = this.#buttonCSS;
|
|
1869
1948
|
button.textContent = this.#options[i];
|
|
1870
|
-
button.onclick = () =>
|
|
1871
|
-
this.Hide();
|
|
1872
|
-
if (this.#onClose !== void 0) {
|
|
1873
|
-
this.#onClose(this.#options[i]);
|
|
1874
|
-
}
|
|
1875
|
-
};
|
|
1949
|
+
button.onclick = () => this.#close(this.#options[i]);
|
|
1876
1950
|
buttonContainer.appendChild(button);
|
|
1877
1951
|
}
|
|
1952
|
+
this.#keyHandler = (e) => {
|
|
1953
|
+
if (e.key === "Enter") {
|
|
1954
|
+
e.preventDefault();
|
|
1955
|
+
this.#close(this.#options.length > 0 ? this.#options[0] : null);
|
|
1956
|
+
} else if (e.key === "Escape") {
|
|
1957
|
+
e.preventDefault();
|
|
1958
|
+
this.#close(null);
|
|
1959
|
+
}
|
|
1960
|
+
e.stopPropagation();
|
|
1961
|
+
};
|
|
1962
|
+
document.addEventListener("keydown", this.#keyHandler, true);
|
|
1878
1963
|
}
|
|
1879
1964
|
};
|
|
1880
1965
|
|
|
@@ -1983,8 +2068,8 @@ var NumberWidget = class {
|
|
|
1983
2068
|
},
|
|
1984
2069
|
text: { color: Theme.Widget.FontColor }
|
|
1985
2070
|
}));
|
|
1986
|
-
this.#callback = config?.callback;
|
|
1987
2071
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, 0));
|
|
2072
|
+
this.#callback = config?.callback;
|
|
1988
2073
|
if (this.#nodeProperty !== void 0) {
|
|
1989
2074
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
1990
2075
|
this.Set(newVal);
|
|
@@ -2426,8 +2511,8 @@ var StringWidget = class {
|
|
|
2426
2511
|
},
|
|
2427
2512
|
text: { color: Theme.Widget.FontColor }
|
|
2428
2513
|
}));
|
|
2429
|
-
this.#callback = config?.callback;
|
|
2430
2514
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, ""));
|
|
2515
|
+
this.#callback = config?.callback;
|
|
2431
2516
|
if (this.#nodeProperty !== void 0) {
|
|
2432
2517
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
2433
2518
|
this.Set(newVal);
|
|
@@ -2592,8 +2677,8 @@ var ToggleWidget = class {
|
|
|
2592
2677
|
lightBorderColor: config?.disabledStyle?.lightBorderColor,
|
|
2593
2678
|
lightColor: config?.disabledStyle?.lightColor === void 0 ? "#004400" : config?.enabledStyle?.lightColor
|
|
2594
2679
|
});
|
|
2595
|
-
this.#callback = config?.callback;
|
|
2596
2680
|
this.Set(startingWidgetValue(node, this.#nodeProperty, config?.value, false));
|
|
2681
|
+
this.#callback = config?.callback;
|
|
2597
2682
|
if (this.#nodeProperty !== void 0) {
|
|
2598
2683
|
this.#node.addPropertyChangeListener(this.#nodeProperty, (oldVal, newVal) => {
|
|
2599
2684
|
this.Set(newVal);
|
|
@@ -2656,6 +2741,7 @@ var ImageWidget = class {
|
|
|
2656
2741
|
img.src = url;
|
|
2657
2742
|
img.onload = () => {
|
|
2658
2743
|
this.#image = img;
|
|
2744
|
+
requestRender();
|
|
2659
2745
|
};
|
|
2660
2746
|
img.onerror = (event) => {
|
|
2661
2747
|
console.log("error loading image:", url, event);
|
|
@@ -3236,6 +3322,13 @@ function TimeExecution(name, callback) {
|
|
|
3236
3322
|
}
|
|
3237
3323
|
|
|
3238
3324
|
// src/nodes/publisher.ts
|
|
3325
|
+
function offersMatchingPort(config, filter) {
|
|
3326
|
+
const ports = filter.needs === "INPUT" /* Input */ ? config.inputs : config.outputs;
|
|
3327
|
+
if (ports === void 0) {
|
|
3328
|
+
return false;
|
|
3329
|
+
}
|
|
3330
|
+
return ports.some((port) => typeSetsCompatible(portConfigTypes(port), filter.types));
|
|
3331
|
+
}
|
|
3239
3332
|
var Publisher = class {
|
|
3240
3333
|
#name;
|
|
3241
3334
|
#description;
|
|
@@ -3261,19 +3354,23 @@ var Publisher = class {
|
|
|
3261
3354
|
unregister(nodeType) {
|
|
3262
3355
|
return this.#registeredNodes.delete(nodeType);
|
|
3263
3356
|
}
|
|
3264
|
-
#recurseBuildMenu(graph, name, subMenu, position) {
|
|
3357
|
+
#recurseBuildMenu(graph, name, subMenu, position, filter) {
|
|
3265
3358
|
const items = [];
|
|
3266
3359
|
const subMenus = /* @__PURE__ */ new Map();
|
|
3267
3360
|
for (let [key, nodeConfig] of subMenu) {
|
|
3268
3361
|
const slashIndex = key.indexOf("/");
|
|
3269
3362
|
const bracketIndex = key.indexOf("[");
|
|
3270
3363
|
if (slashIndex === -1 || bracketIndex !== -1 && bracketIndex < slashIndex) {
|
|
3364
|
+
if (filter !== void 0 && !offersMatchingPort(nodeConfig, filter)) {
|
|
3365
|
+
continue;
|
|
3366
|
+
}
|
|
3271
3367
|
items.push({
|
|
3272
3368
|
name: key,
|
|
3273
3369
|
callback: () => {
|
|
3274
3370
|
const node = new FlowNode(nodeConfig);
|
|
3275
3371
|
node.setPosition(position);
|
|
3276
3372
|
graph.addNode(node);
|
|
3373
|
+
filter?.onCreated?.(node);
|
|
3277
3374
|
}
|
|
3278
3375
|
});
|
|
3279
3376
|
} else {
|
|
@@ -3288,7 +3385,11 @@ var Publisher = class {
|
|
|
3288
3385
|
}
|
|
3289
3386
|
const menus = [];
|
|
3290
3387
|
for (let [key, nodes] of subMenus) {
|
|
3291
|
-
|
|
3388
|
+
const built = this.#recurseBuildMenu(graph, key, nodes, position, filter);
|
|
3389
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3390
|
+
continue;
|
|
3391
|
+
}
|
|
3392
|
+
menus.push(built);
|
|
3292
3393
|
}
|
|
3293
3394
|
return {
|
|
3294
3395
|
name,
|
|
@@ -3296,8 +3397,8 @@ var Publisher = class {
|
|
|
3296
3397
|
subMenus: menus
|
|
3297
3398
|
};
|
|
3298
3399
|
}
|
|
3299
|
-
contextMenu(graph, position) {
|
|
3300
|
-
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position);
|
|
3400
|
+
contextMenu(graph, position, filter) {
|
|
3401
|
+
return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position, filter);
|
|
3301
3402
|
}
|
|
3302
3403
|
create(nodeType) {
|
|
3303
3404
|
const config = this.#registeredNodes.get(nodeType);
|
|
@@ -3352,18 +3453,22 @@ var NodeFactory = class {
|
|
|
3352
3453
|
}
|
|
3353
3454
|
return node;
|
|
3354
3455
|
}
|
|
3355
|
-
newNodeSubmenus(graph, position) {
|
|
3456
|
+
newNodeSubmenus(graph, position, filter) {
|
|
3356
3457
|
const menus = [];
|
|
3357
3458
|
for (let [_, publisher] of this.#registeredPublishers) {
|
|
3358
|
-
|
|
3459
|
+
const built = publisher.contextMenu(graph, position, filter);
|
|
3460
|
+
if (filter !== void 0 && built.items?.length === 0 && built.subMenus?.length === 0) {
|
|
3461
|
+
continue;
|
|
3462
|
+
}
|
|
3463
|
+
menus.push(built);
|
|
3359
3464
|
}
|
|
3360
3465
|
return menus;
|
|
3361
3466
|
}
|
|
3362
|
-
openMenu(graph, position) {
|
|
3467
|
+
openMenu(graph, position, filter) {
|
|
3363
3468
|
return {
|
|
3364
3469
|
name: "New Node",
|
|
3365
3470
|
group: nodeFlowGroup,
|
|
3366
|
-
subMenus: this.newNodeSubmenus(graph, position)
|
|
3471
|
+
subMenus: this.newNodeSubmenus(graph, position, filter)
|
|
3367
3472
|
};
|
|
3368
3473
|
}
|
|
3369
3474
|
};
|
|
@@ -3502,6 +3607,9 @@ var NodeSubsystem2 = class {
|
|
|
3502
3607
|
CopyVector2(this.#boxSelectEnd_graphSpace, this.#boxSelectStart_graphSpace);
|
|
3503
3608
|
this.#boxSelect = true;
|
|
3504
3609
|
}
|
|
3610
|
+
if (!hoveringSomething && !ctrlKey) {
|
|
3611
|
+
this.unselectAllNodes();
|
|
3612
|
+
}
|
|
3505
3613
|
return hoveringSomething || ctrlKey;
|
|
3506
3614
|
}
|
|
3507
3615
|
if (this.#portHovering.InputPort) {
|
|
@@ -3561,6 +3669,102 @@ var NodeSubsystem2 = class {
|
|
|
3561
3669
|
}
|
|
3562
3670
|
}
|
|
3563
3671
|
}
|
|
3672
|
+
connectionsWithin(nodes) {
|
|
3673
|
+
const within = [];
|
|
3674
|
+
for (const connection of this.#connections) {
|
|
3675
|
+
const outNode = connection.outNode();
|
|
3676
|
+
const inNode = connection.inNode();
|
|
3677
|
+
if (outNode === null || inNode === null) {
|
|
3678
|
+
continue;
|
|
3679
|
+
}
|
|
3680
|
+
const from = nodes.indexOf(outNode);
|
|
3681
|
+
const to = nodes.indexOf(inNode);
|
|
3682
|
+
if (from === -1 || to === -1) {
|
|
3683
|
+
continue;
|
|
3684
|
+
}
|
|
3685
|
+
const outPort = connection.outPort();
|
|
3686
|
+
const inPort = connection.inPort();
|
|
3687
|
+
if (outPort === null || inPort === null) {
|
|
3688
|
+
continue;
|
|
3689
|
+
}
|
|
3690
|
+
within.push({
|
|
3691
|
+
fromNode: from,
|
|
3692
|
+
fromPort: this.#outputPortIndex(outNode, outPort),
|
|
3693
|
+
toNode: to,
|
|
3694
|
+
toPort: this.#inputPortIndex(inNode, inPort)
|
|
3695
|
+
});
|
|
3696
|
+
}
|
|
3697
|
+
return within;
|
|
3698
|
+
}
|
|
3699
|
+
#onConnectionReleased = null;
|
|
3700
|
+
setConnectionReleasedHandler(handler) {
|
|
3701
|
+
this.#onConnectionReleased = handler;
|
|
3702
|
+
}
|
|
3703
|
+
#describeDanglingConnection(conn) {
|
|
3704
|
+
const outNode = conn.outNode();
|
|
3705
|
+
const inNode = conn.inNode();
|
|
3706
|
+
if (outNode !== null && inNode === null) {
|
|
3707
|
+
const from = conn.outPort();
|
|
3708
|
+
if (from === null) {
|
|
3709
|
+
return null;
|
|
3710
|
+
}
|
|
3711
|
+
const fromIndex = this.#outputPortIndex(outNode, from);
|
|
3712
|
+
return {
|
|
3713
|
+
needs: "INPUT" /* Input */,
|
|
3714
|
+
types: from.acceptedTypes(),
|
|
3715
|
+
connectTo: (node) => {
|
|
3716
|
+
const to = this.#firstCompatiblePort(node, "INPUT" /* Input */, from);
|
|
3717
|
+
if (to !== -1 && fromIndex !== -1) {
|
|
3718
|
+
this.connectNodes(outNode, fromIndex, node, to);
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
};
|
|
3722
|
+
}
|
|
3723
|
+
if (inNode !== null && outNode === null) {
|
|
3724
|
+
const to = conn.inPort();
|
|
3725
|
+
if (to === null) {
|
|
3726
|
+
return null;
|
|
3727
|
+
}
|
|
3728
|
+
const toIndex = this.#inputPortIndex(inNode, to);
|
|
3729
|
+
return {
|
|
3730
|
+
needs: "OUTPUT" /* Output */,
|
|
3731
|
+
types: to.acceptedTypes(),
|
|
3732
|
+
connectTo: (node) => {
|
|
3733
|
+
const from = this.#firstCompatiblePort(node, "OUTPUT" /* Output */, to);
|
|
3734
|
+
if (from !== -1 && toIndex !== -1) {
|
|
3735
|
+
this.connectNodes(node, from, inNode, toIndex);
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
};
|
|
3739
|
+
}
|
|
3740
|
+
return null;
|
|
3741
|
+
}
|
|
3742
|
+
#outputPortIndex(node, port) {
|
|
3743
|
+
for (let i = 0; i < node.outputs(); i++) {
|
|
3744
|
+
if (node.outputPort(i) === port) {
|
|
3745
|
+
return i;
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
return -1;
|
|
3749
|
+
}
|
|
3750
|
+
#inputPortIndex(node, port) {
|
|
3751
|
+
for (let i = 0; i < node.inputs(); i++) {
|
|
3752
|
+
if (node.inputPort(i) === port) {
|
|
3753
|
+
return i;
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
return -1;
|
|
3757
|
+
}
|
|
3758
|
+
#firstCompatiblePort(node, side, against) {
|
|
3759
|
+
const count = side === "INPUT" /* Input */ ? node.inputs() : node.outputs();
|
|
3760
|
+
for (let i = 0; i < count; i++) {
|
|
3761
|
+
const port = side === "INPUT" /* Input */ ? node.inputPort(i) : node.outputPort(i);
|
|
3762
|
+
if (portsCompatible(port, against)) {
|
|
3763
|
+
return i;
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
return -1;
|
|
3767
|
+
}
|
|
3564
3768
|
clickEnd() {
|
|
3565
3769
|
for (let i = 0; i < this.#nodesGrabbed.Count(); i++) {
|
|
3566
3770
|
const node = this.#nodes[this.#nodesGrabbed.At(i)];
|
|
@@ -3575,14 +3779,20 @@ var NodeSubsystem2 = class {
|
|
|
3575
3779
|
this.#boxSelect = false;
|
|
3576
3780
|
}
|
|
3577
3781
|
if (this.#widgetCurrentlyClicking !== null) {
|
|
3578
|
-
this.#widgetCurrentlyClicking
|
|
3782
|
+
if (this.#widgetHovering === this.#widgetCurrentlyClicking) {
|
|
3783
|
+
this.#widgetCurrentlyClicking.ClickEnd();
|
|
3784
|
+
}
|
|
3579
3785
|
this.#widgetCurrentlyClicking = null;
|
|
3580
3786
|
}
|
|
3581
3787
|
if (this.#connectionSelected === null) {
|
|
3582
3788
|
return;
|
|
3583
3789
|
}
|
|
3584
3790
|
if (this.#portHovering === null) {
|
|
3791
|
+
const dangling = this.#describeDanglingConnection(this.#connectionSelected);
|
|
3585
3792
|
this.#clearCurrentlySelectedConnection();
|
|
3793
|
+
if (dangling !== null) {
|
|
3794
|
+
this.#onConnectionReleased?.(dangling);
|
|
3795
|
+
}
|
|
3586
3796
|
return;
|
|
3587
3797
|
}
|
|
3588
3798
|
const port = this.#portHovering.Port;
|
|
@@ -3649,6 +3859,7 @@ var NodeSubsystem2 = class {
|
|
|
3649
3859
|
this.#idleConnectionRenderer
|
|
3650
3860
|
);
|
|
3651
3861
|
this.#connections.push(connection);
|
|
3862
|
+
requestRender();
|
|
3652
3863
|
return connection;
|
|
3653
3864
|
}
|
|
3654
3865
|
getNodes() {
|
|
@@ -3709,6 +3920,7 @@ var NodeSubsystem2 = class {
|
|
|
3709
3920
|
}
|
|
3710
3921
|
addNode(node) {
|
|
3711
3922
|
this.#nodes.push(node);
|
|
3923
|
+
requestRender();
|
|
3712
3924
|
for (let i = 0; i < this.#registeredNodeAddedCallbacks.length; i++) {
|
|
3713
3925
|
const callback = this.#registeredNodeAddedCallbacks[i];
|
|
3714
3926
|
if (!callback) {
|
|
@@ -3755,6 +3967,7 @@ var NodeSubsystem2 = class {
|
|
|
3755
3967
|
this.#removeNodeConnections(nodeIndex);
|
|
3756
3968
|
const node = this.#nodes[nodeIndex];
|
|
3757
3969
|
this.#nodes.splice(nodeIndex, 1);
|
|
3970
|
+
requestRender();
|
|
3758
3971
|
for (let i = 0; i < this.#nodeRemovedCallbacks.length; i++) {
|
|
3759
3972
|
this.#nodeRemovedCallbacks[i](node);
|
|
3760
3973
|
}
|
|
@@ -3764,6 +3977,7 @@ var NodeSubsystem2 = class {
|
|
|
3764
3977
|
this.#connections[index].clearPorts();
|
|
3765
3978
|
}
|
|
3766
3979
|
this.#connections.splice(index, 1);
|
|
3980
|
+
requestRender();
|
|
3767
3981
|
}
|
|
3768
3982
|
#removeConnection(connection, clearPorts) {
|
|
3769
3983
|
const index = this.#connections.indexOf(connection);
|
|
@@ -3809,7 +4023,8 @@ var NodeSubsystem2 = class {
|
|
|
3809
4023
|
this.#nodeFactory.openMenu(this, position)
|
|
3810
4024
|
]
|
|
3811
4025
|
};
|
|
3812
|
-
|
|
4026
|
+
const selectedCount = this.#nodesSelected().length;
|
|
4027
|
+
if (selectedCount > 0) {
|
|
3813
4028
|
organizeNodesSubMenu.items?.push({
|
|
3814
4029
|
name: "Selected Nodes",
|
|
3815
4030
|
group: nodeFlowGroup,
|
|
@@ -3817,6 +4032,13 @@ var NodeSubsystem2 = class {
|
|
|
3817
4032
|
this.#organizeSelected(ctx);
|
|
3818
4033
|
}
|
|
3819
4034
|
});
|
|
4035
|
+
config.items?.push({
|
|
4036
|
+
name: selectedCount === 1 ? "Delete Selected Node" : `Delete ${selectedCount} Selected Nodes`,
|
|
4037
|
+
group: nodeFlowGroup,
|
|
4038
|
+
callback: () => {
|
|
4039
|
+
this.removeSelectedNodes();
|
|
4040
|
+
}
|
|
4041
|
+
});
|
|
3820
4042
|
}
|
|
3821
4043
|
if (this.#nodeHovering > -1) {
|
|
3822
4044
|
const nodeToReview = this.#nodeHovering;
|
|
@@ -3890,6 +4112,29 @@ var NodeSubsystem2 = class {
|
|
|
3890
4112
|
this.#selectNode(inputs[i], false);
|
|
3891
4113
|
}
|
|
3892
4114
|
}
|
|
4115
|
+
/** Drops the selection entirely. */
|
|
4116
|
+
unselectAllNodes() {
|
|
4117
|
+
let changed = false;
|
|
4118
|
+
for (let i = 0; i < this.#nodes.length; i++) {
|
|
4119
|
+
if (this.#nodes[i].selected()) {
|
|
4120
|
+
this.#nodes[i].unselect();
|
|
4121
|
+
changed = true;
|
|
4122
|
+
}
|
|
4123
|
+
}
|
|
4124
|
+
if (changed) {
|
|
4125
|
+
requestRender();
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
/**
|
|
4129
|
+
* Removes every selected node, and the connections that touched them.
|
|
4130
|
+
*/
|
|
4131
|
+
removeSelectedNodes() {
|
|
4132
|
+
const removed = this.getSelectedNodes();
|
|
4133
|
+
for (const node of removed) {
|
|
4134
|
+
this.removeNode(node);
|
|
4135
|
+
}
|
|
4136
|
+
return removed;
|
|
4137
|
+
}
|
|
3893
4138
|
#selectNodeByIndex(nodeIndex, unselectOthers) {
|
|
3894
4139
|
this.#selectNode(this.#nodes[nodeIndex], unselectOthers);
|
|
3895
4140
|
}
|
|
@@ -3927,8 +4172,16 @@ var NodeSubsystem2 = class {
|
|
|
3927
4172
|
this.#nodeHovering = -1;
|
|
3928
4173
|
this.#boxSelectionNodes.Clear();
|
|
3929
4174
|
const selectedBox_Screenspace = this.#boxSelectionScreenspaceBox(camera);
|
|
4175
|
+
const canvas = {
|
|
4176
|
+
Position: { x: 0, y: 0 },
|
|
4177
|
+
Size: { x: ctx.canvas.width, y: ctx.canvas.height }
|
|
4178
|
+
};
|
|
3930
4179
|
for (let i = 0; i < this.#nodes.length; i++) {
|
|
3931
4180
|
let state = 0 /* Idle */;
|
|
4181
|
+
const nodeBounds = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4182
|
+
if (!BoxIntersection(nodeBounds, canvas) && this.#nodes[i].layoutPortsWithoutDrawing(nodeBounds, camera.zoom)) {
|
|
4183
|
+
continue;
|
|
4184
|
+
}
|
|
3932
4185
|
if (mousePosition !== void 0 && !this.#boxSelect) {
|
|
3933
4186
|
const intersection = this.#nodes[i].inBounds(ctx, camera, mousePosition);
|
|
3934
4187
|
if (intersection.Node !== void 0 && intersection.PortIndex === void 0 && intersection.Widget === void 0) {
|
|
@@ -3949,8 +4202,8 @@ var NodeSubsystem2 = class {
|
|
|
3949
4202
|
};
|
|
3950
4203
|
}
|
|
3951
4204
|
} else if (this.#boxSelect) {
|
|
3952
|
-
const
|
|
3953
|
-
if (BoxIntersection(selectedBox_Screenspace,
|
|
4205
|
+
const nodeBounds2 = this.#nodes[i].calculateBounds(ctx, camera);
|
|
4206
|
+
if (BoxIntersection(selectedBox_Screenspace, nodeBounds2)) {
|
|
3954
4207
|
state = 1 /* MouseOver */;
|
|
3955
4208
|
this.#boxSelectionNodes.Push(i);
|
|
3956
4209
|
}
|
|
@@ -3972,12 +4225,16 @@ var NodeSubsystem2 = class {
|
|
|
3972
4225
|
render(ctx, camera, mousePosition) {
|
|
3973
4226
|
this.#lastCtx = ctx;
|
|
3974
4227
|
this.#cursor = "default" /* Default */;
|
|
4228
|
+
const awaitingLayout = this.#nodes.some((node) => !node.hasBeenLaidOut());
|
|
3975
4229
|
TimeExecution("Render_Connections", () => {
|
|
3976
4230
|
this.#renderConnections(ctx, camera, mousePosition);
|
|
3977
4231
|
});
|
|
3978
4232
|
TimeExecution("Render_Nodes", () => {
|
|
3979
4233
|
this.#renderNodes(ctx, camera, mousePosition);
|
|
3980
4234
|
});
|
|
4235
|
+
if (awaitingLayout) {
|
|
4236
|
+
requestRender();
|
|
4237
|
+
}
|
|
3981
4238
|
if (this.#boxSelect) {
|
|
3982
4239
|
const box = this.#boxSelectionScreenspaceBox(camera);
|
|
3983
4240
|
ctx.setLineDash([Theme.BoxSelect.LineDashLength]);
|
|
@@ -4253,6 +4510,7 @@ var FlowNode = class {
|
|
|
4253
4510
|
return;
|
|
4254
4511
|
}
|
|
4255
4512
|
this.#selected = true;
|
|
4513
|
+
requestRender();
|
|
4256
4514
|
for (let i = 0; i < this.#onSelect.length; i++) {
|
|
4257
4515
|
this.#onSelect[i]();
|
|
4258
4516
|
}
|
|
@@ -4298,6 +4556,7 @@ var FlowNode = class {
|
|
|
4298
4556
|
return;
|
|
4299
4557
|
}
|
|
4300
4558
|
this.#data[name] = value;
|
|
4559
|
+
requestRender();
|
|
4301
4560
|
for (let i = 0; i < this.#registeredAnyPropertyChangeCallbacks.length; i++) {
|
|
4302
4561
|
this.#registeredAnyPropertyChangeCallbacks[i](name, oldValue, value);
|
|
4303
4562
|
}
|
|
@@ -4558,6 +4817,7 @@ var FlowNode = class {
|
|
|
4558
4817
|
return;
|
|
4559
4818
|
}
|
|
4560
4819
|
this.#selected = false;
|
|
4820
|
+
requestRender();
|
|
4561
4821
|
for (let i = 0; i < this.#onUnselect.length; i++) {
|
|
4562
4822
|
this.#onUnselect[i]();
|
|
4563
4823
|
}
|
|
@@ -4587,6 +4847,7 @@ var FlowNode = class {
|
|
|
4587
4847
|
}
|
|
4588
4848
|
setPosition(position) {
|
|
4589
4849
|
CopyVector2(this.#position, position);
|
|
4850
|
+
requestRender();
|
|
4590
4851
|
}
|
|
4591
4852
|
getPosition() {
|
|
4592
4853
|
return this.#position;
|
|
@@ -4649,10 +4910,12 @@ var FlowNode = class {
|
|
|
4649
4910
|
}
|
|
4650
4911
|
addWidget(widget) {
|
|
4651
4912
|
this.#widgets.push(widget);
|
|
4913
|
+
requestRender();
|
|
4652
4914
|
}
|
|
4653
4915
|
insertWidget(index, widget) {
|
|
4654
4916
|
const at = Math.max(0, Math.min(index, this.#widgets.length));
|
|
4655
4917
|
this.#widgets.splice(at, 0, widget);
|
|
4918
|
+
requestRender();
|
|
4656
4919
|
}
|
|
4657
4920
|
removeWidget(widget) {
|
|
4658
4921
|
const index = this.#widgets.indexOf(widget, 0);
|
|
@@ -4660,12 +4923,15 @@ var FlowNode = class {
|
|
|
4660
4923
|
throw new Error("node does not contain widget");
|
|
4661
4924
|
}
|
|
4662
4925
|
this.#widgets.splice(index, 1);
|
|
4926
|
+
requestRender();
|
|
4663
4927
|
}
|
|
4664
4928
|
removeWidgetAt(index) {
|
|
4665
4929
|
if (index < 0 || index >= this.#widgets.length) {
|
|
4666
4930
|
return void 0;
|
|
4667
4931
|
}
|
|
4668
|
-
|
|
4932
|
+
const removed = this.#widgets.splice(index, 1)[0];
|
|
4933
|
+
requestRender();
|
|
4934
|
+
return removed;
|
|
4669
4935
|
}
|
|
4670
4936
|
moveWidget(from, to) {
|
|
4671
4937
|
if (from < 0 || from >= this.#widgets.length) {
|
|
@@ -4676,9 +4942,11 @@ var FlowNode = class {
|
|
|
4676
4942
|
}
|
|
4677
4943
|
const [widget] = this.#widgets.splice(from, 1);
|
|
4678
4944
|
this.#widgets.splice(to, 0, widget);
|
|
4945
|
+
requestRender();
|
|
4679
4946
|
}
|
|
4680
4947
|
clearWidgets() {
|
|
4681
4948
|
this.#widgets.length = 0;
|
|
4949
|
+
requestRender();
|
|
4682
4950
|
}
|
|
4683
4951
|
getWidget(index) {
|
|
4684
4952
|
return this.#widgets[index];
|
|
@@ -4750,6 +5018,7 @@ var FlowNode = class {
|
|
|
4750
5018
|
return;
|
|
4751
5019
|
}
|
|
4752
5020
|
this.#title.set(cleaned);
|
|
5021
|
+
requestRender();
|
|
4753
5022
|
for (let i = 0; i < this.#titleChangeCallback.length; i++) {
|
|
4754
5023
|
const callback = this.#titleChangeCallback[i];
|
|
4755
5024
|
callback(this, old, cleaned);
|
|
@@ -4768,6 +5037,7 @@ var FlowNode = class {
|
|
|
4768
5037
|
}
|
|
4769
5038
|
const old = this.#infoText;
|
|
4770
5039
|
this.#infoText = cleaned;
|
|
5040
|
+
requestRender();
|
|
4771
5041
|
for (let i = 0; i < this.#infoChangeCallback.length; i++) {
|
|
4772
5042
|
const callback = this.#infoChangeCallback[i];
|
|
4773
5043
|
callback(this, old, cleaned);
|
|
@@ -4807,7 +5077,12 @@ var FlowNode = class {
|
|
|
4807
5077
|
clearMessages() {
|
|
4808
5078
|
this.#messages = [];
|
|
4809
5079
|
}
|
|
5080
|
+
hasBeenLaidOut() {
|
|
5081
|
+
return this.#laidOut;
|
|
5082
|
+
}
|
|
5083
|
+
#laidOut = false;
|
|
4810
5084
|
render(ctx, camera, state, mousePosition, postProcess) {
|
|
5085
|
+
this.#laidOut = true;
|
|
4811
5086
|
VectorPool.run(() => {
|
|
4812
5087
|
const tempMeasurement = VectorPool.get();
|
|
4813
5088
|
this.#inputPortPositions.Clear();
|
|
@@ -4943,8 +5218,58 @@ var FlowNode = class {
|
|
|
4943
5218
|
const message = this.#messages[i];
|
|
4944
5219
|
messageStart.y += message.render(ctx, camera.zoom, messageStart, !(state === 0 /* Idle */)) + 10 * camera.zoom;
|
|
4945
5220
|
}
|
|
5221
|
+
this.#rememberPortOffsets(nodeBounds, camera.zoom);
|
|
4946
5222
|
});
|
|
4947
5223
|
}
|
|
5224
|
+
#portOffsets = { input: [], output: [] };
|
|
5225
|
+
#rememberPortOffsets(bounds, zoom) {
|
|
5226
|
+
if (zoom <= 0) {
|
|
5227
|
+
return;
|
|
5228
|
+
}
|
|
5229
|
+
const record = (positions, into) => {
|
|
5230
|
+
into.length = 0;
|
|
5231
|
+
for (let i = 0; i < positions.Count(); i++) {
|
|
5232
|
+
const box = positions.At(i);
|
|
5233
|
+
into.push({
|
|
5234
|
+
Position: {
|
|
5235
|
+
x: (box.Position.x - bounds.Position.x) / zoom,
|
|
5236
|
+
y: (box.Position.y - bounds.Position.y) / zoom
|
|
5237
|
+
},
|
|
5238
|
+
Size: {
|
|
5239
|
+
x: box.Size.x / zoom,
|
|
5240
|
+
y: box.Size.y / zoom
|
|
5241
|
+
}
|
|
5242
|
+
});
|
|
5243
|
+
}
|
|
5244
|
+
};
|
|
5245
|
+
record(this.#inputPortPositions, this.#portOffsets.input);
|
|
5246
|
+
record(this.#outputPortPositions, this.#portOffsets.output);
|
|
5247
|
+
}
|
|
5248
|
+
layoutPortsWithoutDrawing(bounds, zoom) {
|
|
5249
|
+
if (this.#portOffsets.input.length === 0 && this.#portOffsets.output.length === 0) {
|
|
5250
|
+
return false;
|
|
5251
|
+
}
|
|
5252
|
+
const project = (offsets, into) => {
|
|
5253
|
+
into.Clear();
|
|
5254
|
+
for (let i = 0; i < offsets.length; i++) {
|
|
5255
|
+
const offset = offsets[i];
|
|
5256
|
+
into.Push({
|
|
5257
|
+
Position: {
|
|
5258
|
+
x: bounds.Position.x + offset.Position.x * zoom,
|
|
5259
|
+
y: bounds.Position.y + offset.Position.y * zoom
|
|
5260
|
+
},
|
|
5261
|
+
Size: {
|
|
5262
|
+
x: offset.Size.x * zoom,
|
|
5263
|
+
y: offset.Size.y * zoom
|
|
5264
|
+
}
|
|
5265
|
+
});
|
|
5266
|
+
}
|
|
5267
|
+
};
|
|
5268
|
+
project(this.#portOffsets.input, this.#inputPortPositions);
|
|
5269
|
+
project(this.#portOffsets.output, this.#outputPortPositions);
|
|
5270
|
+
this.#widgetPositions.Clear();
|
|
5271
|
+
return true;
|
|
5272
|
+
}
|
|
4948
5273
|
};
|
|
4949
5274
|
|
|
4950
5275
|
// src/markdown/token.ts
|
|
@@ -5085,7 +5410,10 @@ function onFontsLoaded(callback) {
|
|
|
5085
5410
|
if (typeof document === "undefined" || document.fonts === void 0) {
|
|
5086
5411
|
return;
|
|
5087
5412
|
}
|
|
5088
|
-
document.fonts.addEventListener("loadingdone", () =>
|
|
5413
|
+
document.fonts.addEventListener("loadingdone", () => {
|
|
5414
|
+
callback();
|
|
5415
|
+
requestRender();
|
|
5416
|
+
});
|
|
5089
5417
|
}
|
|
5090
5418
|
var CodeBlockEntry = class {
|
|
5091
5419
|
#text;
|
|
@@ -5835,6 +6163,7 @@ var NoteSubsystem = class {
|
|
|
5835
6163
|
return;
|
|
5836
6164
|
}
|
|
5837
6165
|
this.#notes.push(note);
|
|
6166
|
+
requestRender();
|
|
5838
6167
|
for (let i = 0; i < this.#onNoteAddedCallbacks.length; i++) {
|
|
5839
6168
|
this.#onNoteAddedCallbacks[i](note);
|
|
5840
6169
|
}
|
|
@@ -5957,6 +6286,7 @@ var NoteSubsystem = class {
|
|
|
5957
6286
|
if (index > -1) {
|
|
5958
6287
|
const noteRemoved = this.#notes[index];
|
|
5959
6288
|
this.#notes.splice(index, 1);
|
|
6289
|
+
requestRender();
|
|
5960
6290
|
for (let i = 0; i < this.#onNoteRemovedCallbacks.length; i++) {
|
|
5961
6291
|
this.#onNoteRemovedCallbacks[i](noteRemoved);
|
|
5962
6292
|
}
|
|
@@ -6293,6 +6623,124 @@ var QuickMenu = class {
|
|
|
6293
6623
|
}
|
|
6294
6624
|
};
|
|
6295
6625
|
|
|
6626
|
+
// src/minimap.ts
|
|
6627
|
+
var Minimap = class {
|
|
6628
|
+
#enabled;
|
|
6629
|
+
#width;
|
|
6630
|
+
#height;
|
|
6631
|
+
#margin;
|
|
6632
|
+
#backgroundColor;
|
|
6633
|
+
#borderColor;
|
|
6634
|
+
#nodeColor;
|
|
6635
|
+
#viewportColor;
|
|
6636
|
+
#box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };
|
|
6637
|
+
#scale = 1;
|
|
6638
|
+
#originX = 0;
|
|
6639
|
+
#originY = 0;
|
|
6640
|
+
// The padding the last frame was laid out with, so a click maps back
|
|
6641
|
+
// through the same geometry it was drawn with.
|
|
6642
|
+
#padding = Theme.Minimap.Padding;
|
|
6643
|
+
#drawn = false;
|
|
6644
|
+
constructor(config) {
|
|
6645
|
+
this.#enabled = config?.enabled === true;
|
|
6646
|
+
this.#width = config?.width === void 0 ? 200 : config.width;
|
|
6647
|
+
this.#height = config?.height === void 0 ? 150 : config.height;
|
|
6648
|
+
this.#margin = config?.margin === void 0 ? 16 : config.margin;
|
|
6649
|
+
this.#backgroundColor = config?.backgroundColor;
|
|
6650
|
+
this.#borderColor = config?.borderColor;
|
|
6651
|
+
this.#nodeColor = config?.nodeColor;
|
|
6652
|
+
this.#viewportColor = config?.viewportColor;
|
|
6653
|
+
}
|
|
6654
|
+
enabled() {
|
|
6655
|
+
return this.#enabled;
|
|
6656
|
+
}
|
|
6657
|
+
setEnabled(enabled) {
|
|
6658
|
+
this.#enabled = enabled;
|
|
6659
|
+
this.#drawn = false;
|
|
6660
|
+
}
|
|
6661
|
+
contains(position) {
|
|
6662
|
+
return this.#enabled && this.#drawn && InBox(this.#box, position);
|
|
6663
|
+
}
|
|
6664
|
+
graphPositionOf(position, out) {
|
|
6665
|
+
out.x = (position.x - this.#box.Position.x - this.#padding) / this.#scale + this.#originX;
|
|
6666
|
+
out.y = (position.y - this.#box.Position.y - this.#padding) / this.#scale + this.#originY;
|
|
6667
|
+
}
|
|
6668
|
+
render(ctx, canvas, camera, nodes) {
|
|
6669
|
+
if (!this.#enabled) {
|
|
6670
|
+
this.#drawn = false;
|
|
6671
|
+
return;
|
|
6672
|
+
}
|
|
6673
|
+
const flat = new Camera();
|
|
6674
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
6675
|
+
const boxes = [];
|
|
6676
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
6677
|
+
const bounds = nodes[i].calculateBounds(ctx, flat);
|
|
6678
|
+
boxes.push(bounds);
|
|
6679
|
+
minX = Math.min(minX, bounds.Position.x);
|
|
6680
|
+
minY = Math.min(minY, bounds.Position.y);
|
|
6681
|
+
maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);
|
|
6682
|
+
maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);
|
|
6683
|
+
}
|
|
6684
|
+
const topLeft = { x: 0, y: 0 };
|
|
6685
|
+
const bottomRight = { x: 0, y: 0 };
|
|
6686
|
+
camera.screenSpaceToGraphSpace({ x: 0, y: 0 }, topLeft);
|
|
6687
|
+
camera.screenSpaceToGraphSpace({ x: canvas.width, y: canvas.height }, bottomRight);
|
|
6688
|
+
minX = Math.min(minX, topLeft.x);
|
|
6689
|
+
minY = Math.min(minY, topLeft.y);
|
|
6690
|
+
maxX = Math.max(maxX, bottomRight.x);
|
|
6691
|
+
maxY = Math.max(maxY, bottomRight.y);
|
|
6692
|
+
if (!isFinite(minX) || maxX <= minX || maxY <= minY) {
|
|
6693
|
+
this.#drawn = false;
|
|
6694
|
+
return;
|
|
6695
|
+
}
|
|
6696
|
+
this.#box.Size.x = this.#width;
|
|
6697
|
+
this.#box.Size.y = this.#height;
|
|
6698
|
+
this.#box.Position.x = canvas.width - this.#width - this.#margin;
|
|
6699
|
+
this.#box.Position.y = canvas.height - this.#height - this.#margin;
|
|
6700
|
+
this.#padding = Theme.Minimap.Padding;
|
|
6701
|
+
const usableWidth = this.#width - this.#padding * 2;
|
|
6702
|
+
const usableHeight = this.#height - this.#padding * 2;
|
|
6703
|
+
this.#scale = Math.min(usableWidth / (maxX - minX), usableHeight / (maxY - minY));
|
|
6704
|
+
this.#originX = minX;
|
|
6705
|
+
this.#originY = minY;
|
|
6706
|
+
const left = this.#box.Position.x + this.#padding;
|
|
6707
|
+
const top = this.#box.Position.y + this.#padding;
|
|
6708
|
+
const toMapX = (x) => left + (x - minX) * this.#scale;
|
|
6709
|
+
const toMapY = (y) => top + (y - minY) * this.#scale;
|
|
6710
|
+
ctx.fillStyle = this.#backgroundColor ?? Theme.Minimap.BackgroundColor;
|
|
6711
|
+
ctx.strokeStyle = this.#borderColor ?? Theme.Minimap.BorderColor;
|
|
6712
|
+
ctx.lineWidth = 1;
|
|
6713
|
+
ctx.beginPath();
|
|
6714
|
+
ctx.roundRect(
|
|
6715
|
+
this.#box.Position.x,
|
|
6716
|
+
this.#box.Position.y,
|
|
6717
|
+
this.#width,
|
|
6718
|
+
this.#height,
|
|
6719
|
+
Theme.Minimap.BorderRadius
|
|
6720
|
+
);
|
|
6721
|
+
ctx.fill();
|
|
6722
|
+
ctx.stroke();
|
|
6723
|
+
ctx.fillStyle = this.#nodeColor ?? Theme.Minimap.NodeColor;
|
|
6724
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
6725
|
+
const b = boxes[i];
|
|
6726
|
+
ctx.fillRect(
|
|
6727
|
+
toMapX(b.Position.x),
|
|
6728
|
+
toMapY(b.Position.y),
|
|
6729
|
+
Math.max(1, b.Size.x * this.#scale),
|
|
6730
|
+
Math.max(1, b.Size.y * this.#scale)
|
|
6731
|
+
);
|
|
6732
|
+
}
|
|
6733
|
+
ctx.fillStyle = this.#viewportColor ?? Theme.Minimap.ViewportColor;
|
|
6734
|
+
ctx.fillRect(
|
|
6735
|
+
toMapX(topLeft.x),
|
|
6736
|
+
toMapY(topLeft.y),
|
|
6737
|
+
Math.max(1, (bottomRight.x - topLeft.x) * this.#scale),
|
|
6738
|
+
Math.max(1, (bottomRight.y - topLeft.y) * this.#scale)
|
|
6739
|
+
);
|
|
6740
|
+
this.#drawn = true;
|
|
6741
|
+
}
|
|
6742
|
+
};
|
|
6743
|
+
|
|
6296
6744
|
// src/graph.ts
|
|
6297
6745
|
function BuildBackgroundRenderer(backgroundColor) {
|
|
6298
6746
|
return (canvas, context, position, scale) => {
|
|
@@ -6430,7 +6878,13 @@ var NodeFlowGraph = class {
|
|
|
6430
6878
|
const backgroundColor = config?.backgroundColor === void 0 ? Theme.Graph.BackgroundColor : config.backgroundColor;
|
|
6431
6879
|
this.#backgroundRenderer = BuildBackgroundRenderer(backgroundColor);
|
|
6432
6880
|
}
|
|
6433
|
-
|
|
6881
|
+
this.#minimap = new Minimap(config?.minimap);
|
|
6882
|
+
this.#mainNodeSubsystem.setConnectionReleasedHandler((dangling) => {
|
|
6883
|
+
this.#openScopedMenu(dangling);
|
|
6884
|
+
});
|
|
6885
|
+
this.#watchCanvasSize();
|
|
6886
|
+
this.#stopRendering = onRenderRequested(this.#render.bind(this));
|
|
6887
|
+
requestRender();
|
|
6434
6888
|
new MouseObserver(
|
|
6435
6889
|
this.#canvas,
|
|
6436
6890
|
this.#mouseDragEvent.bind(this),
|
|
@@ -6448,39 +6902,90 @@ var NodeFlowGraph = class {
|
|
|
6448
6902
|
document.addEventListener(
|
|
6449
6903
|
"keydown",
|
|
6450
6904
|
(e) => {
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6905
|
+
this.#keyDown(e);
|
|
6906
|
+
requestRender();
|
|
6907
|
+
}
|
|
6908
|
+
);
|
|
6909
|
+
}
|
|
6910
|
+
#copyCallbacks = [];
|
|
6911
|
+
#pasteCallbacks = [];
|
|
6912
|
+
addCopyListener(callback) {
|
|
6913
|
+
this.#copyCallbacks.push(callback);
|
|
6914
|
+
}
|
|
6915
|
+
addPasteListener(callback) {
|
|
6916
|
+
this.#pasteCallbacks.push(callback);
|
|
6917
|
+
}
|
|
6918
|
+
#raiseCopy() {
|
|
6919
|
+
const nodes = this.#mainNodeSubsystem.getSelectedNodes();
|
|
6920
|
+
if (nodes.length === 0) {
|
|
6921
|
+
return;
|
|
6922
|
+
}
|
|
6923
|
+
const connections = this.#mainNodeSubsystem.connectionsWithin(nodes);
|
|
6924
|
+
this.#copyCallbacks.forEach((callback) => callback(nodes, connections));
|
|
6925
|
+
}
|
|
6926
|
+
#raisePaste() {
|
|
6927
|
+
const position = this.#mousePosition === void 0 ? { x: 0, y: 0 } : this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6928
|
+
this.#pasteCallbacks.forEach((callback) => callback(position));
|
|
6929
|
+
}
|
|
6930
|
+
#deleteKey(e) {
|
|
6931
|
+
return e.code === "Delete" || e.code === "Backspace" || e.key === "Delete" || e.key === "Backspace";
|
|
6932
|
+
}
|
|
6933
|
+
#keyDown(e) {
|
|
6934
|
+
if (document.activeElement) {
|
|
6935
|
+
if (["INPUT", "TEXTAREA"].includes(document.activeElement.tagName)) return;
|
|
6936
|
+
}
|
|
6937
|
+
if (this.#deleteKey(e)) {
|
|
6938
|
+
if (this.#mainNodeSubsystem.getSelectedNodes().length > 0) {
|
|
6939
|
+
e.preventDefault();
|
|
6940
|
+
this.#mainNodeSubsystem.removeSelectedNodes();
|
|
6941
|
+
return;
|
|
6942
|
+
}
|
|
6943
|
+
}
|
|
6944
|
+
if (e.ctrlKey || e.metaKey) {
|
|
6945
|
+
const letter = e.code.startsWith("Key") ? e.code.substring(3).toLowerCase() : (e.key ?? "").toLowerCase();
|
|
6946
|
+
switch (letter) {
|
|
6947
|
+
case "c":
|
|
6948
|
+
this.#raiseCopy();
|
|
6465
6949
|
return;
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
if (!spacePressed) {
|
|
6950
|
+
case "v":
|
|
6951
|
+
this.#raisePaste();
|
|
6469
6952
|
return;
|
|
6470
|
-
|
|
6471
|
-
|
|
6953
|
+
// duplicate
|
|
6954
|
+
case "d":
|
|
6955
|
+
e.preventDefault();
|
|
6956
|
+
this.#raiseCopy();
|
|
6957
|
+
this.#raisePaste();
|
|
6472
6958
|
return;
|
|
6473
|
-
}
|
|
6474
|
-
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6475
|
-
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6476
|
-
this.#openQuickMenu = {
|
|
6477
|
-
Menu: new QuickMenu({
|
|
6478
|
-
subMenus: items
|
|
6479
|
-
}),
|
|
6480
|
-
Position: contextMenuPosition
|
|
6481
|
-
};
|
|
6482
6959
|
}
|
|
6483
|
-
|
|
6960
|
+
}
|
|
6961
|
+
if (this.#openQuickMenu) {
|
|
6962
|
+
if (e.code === "Escape") {
|
|
6963
|
+
this.#openQuickMenu = null;
|
|
6964
|
+
return;
|
|
6965
|
+
}
|
|
6966
|
+
if (e.code === "Enter") {
|
|
6967
|
+
this.#openQuickMenu.Menu.execute();
|
|
6968
|
+
this.#openQuickMenu = null;
|
|
6969
|
+
return;
|
|
6970
|
+
}
|
|
6971
|
+
this.#openQuickMenu.Menu.keyboardEvent(e);
|
|
6972
|
+
return;
|
|
6973
|
+
}
|
|
6974
|
+
const spacePressed = e.key == " " || e.code == "Space";
|
|
6975
|
+
if (!spacePressed) {
|
|
6976
|
+
return;
|
|
6977
|
+
}
|
|
6978
|
+
if (!this.#mousePosition) {
|
|
6979
|
+
return;
|
|
6980
|
+
}
|
|
6981
|
+
const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
6982
|
+
let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);
|
|
6983
|
+
this.#openQuickMenu = {
|
|
6984
|
+
Menu: new QuickMenu({
|
|
6985
|
+
subMenus: items
|
|
6986
|
+
}),
|
|
6987
|
+
Position: contextMenuPosition
|
|
6988
|
+
};
|
|
6484
6989
|
}
|
|
6485
6990
|
#fileDrop(file) {
|
|
6486
6991
|
if (this.currentView().fileDrop(file)) {
|
|
@@ -6546,8 +7051,25 @@ var NodeFlowGraph = class {
|
|
|
6546
7051
|
this.#openQuickMenu = null;
|
|
6547
7052
|
this.#contextMenuEntryHovering = null;
|
|
6548
7053
|
this.#mousePosition = mousePosition;
|
|
7054
|
+
if (this.#minimap.contains(mousePosition)) {
|
|
7055
|
+
this.#lookAtFromMinimap(mousePosition);
|
|
7056
|
+
this.#draggingMinimap = true;
|
|
7057
|
+
return;
|
|
7058
|
+
}
|
|
6549
7059
|
this.currentView().clickStart(mousePosition, this.#camera, ctrlKey);
|
|
6550
7060
|
}
|
|
7061
|
+
#draggingMinimap = false;
|
|
7062
|
+
#lookAtFromMinimap(mousePosition) {
|
|
7063
|
+
const target = { x: 0, y: 0 };
|
|
7064
|
+
this.#minimap.graphPositionOf(mousePosition, target);
|
|
7065
|
+
this.#camera.position.x = -(target.x * this.#camera.zoom) + this.#canvas.width / 2;
|
|
7066
|
+
this.#camera.position.y = -(target.y * this.#camera.zoom) + this.#canvas.height / 2;
|
|
7067
|
+
requestRender();
|
|
7068
|
+
}
|
|
7069
|
+
/** The minimap, so it can be turned on and sized by the host. */
|
|
7070
|
+
minimap() {
|
|
7071
|
+
return this.#minimap;
|
|
7072
|
+
}
|
|
6551
7073
|
currentView() {
|
|
6552
7074
|
return this.#views[this.#currentView];
|
|
6553
7075
|
}
|
|
@@ -6567,6 +7089,12 @@ var NodeFlowGraph = class {
|
|
|
6567
7089
|
getSelectedNodes() {
|
|
6568
7090
|
return this.#mainNodeSubsystem.getSelectedNodes();
|
|
6569
7091
|
}
|
|
7092
|
+
unselectAllNodes() {
|
|
7093
|
+
this.#mainNodeSubsystem.unselectAllNodes();
|
|
7094
|
+
}
|
|
7095
|
+
removeSelectedNodes() {
|
|
7096
|
+
return this.#mainNodeSubsystem.removeSelectedNodes();
|
|
7097
|
+
}
|
|
6570
7098
|
/**
|
|
6571
7099
|
* Returns a copy of the current camera orientation (screen-space pan + zoom).
|
|
6572
7100
|
*/
|
|
@@ -6682,10 +7210,37 @@ var NodeFlowGraph = class {
|
|
|
6682
7210
|
Position: contextMenuPosition
|
|
6683
7211
|
};
|
|
6684
7212
|
}
|
|
7213
|
+
#openScopedMenu(dangling) {
|
|
7214
|
+
if (this.#mousePosition === void 0) {
|
|
7215
|
+
return;
|
|
7216
|
+
}
|
|
7217
|
+
const position = this.#sceenPositionToGraphPosition(this.#mousePosition);
|
|
7218
|
+
const menu = this.#mainNodeSubsystem.nodeFactory().openMenu(
|
|
7219
|
+
this.#mainNodeSubsystem,
|
|
7220
|
+
position,
|
|
7221
|
+
{
|
|
7222
|
+
needs: dangling.needs,
|
|
7223
|
+
types: dangling.types,
|
|
7224
|
+
onCreated: dangling.connectTo
|
|
7225
|
+
}
|
|
7226
|
+
);
|
|
7227
|
+
this.#openedContextMenu = {
|
|
7228
|
+
Menu: new ContextMenu(menu),
|
|
7229
|
+
Position: position
|
|
7230
|
+
};
|
|
7231
|
+
requestRender();
|
|
7232
|
+
}
|
|
6685
7233
|
#clickEnd() {
|
|
7234
|
+
this.#draggingMinimap = false;
|
|
6686
7235
|
this.currentView().clickEnd();
|
|
6687
7236
|
}
|
|
6688
7237
|
#mouseDragEvent(delta) {
|
|
7238
|
+
if (this.#draggingMinimap) {
|
|
7239
|
+
if (this.#mousePosition !== void 0) {
|
|
7240
|
+
this.#lookAtFromMinimap(this.#mousePosition);
|
|
7241
|
+
}
|
|
7242
|
+
return;
|
|
7243
|
+
}
|
|
6689
7244
|
let draggingSomething = this.currentView().mouseDragEvent(delta, this.#camera.zoom);
|
|
6690
7245
|
if (!draggingSomething) {
|
|
6691
7246
|
this.#camera.position.x += delta.x;
|
|
@@ -6694,12 +7249,45 @@ var NodeFlowGraph = class {
|
|
|
6694
7249
|
}
|
|
6695
7250
|
#lastFrameCursor;
|
|
6696
7251
|
#cursor;
|
|
6697
|
-
#
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
7252
|
+
#minimap;
|
|
7253
|
+
#stopRendering;
|
|
7254
|
+
#sizeObserver;
|
|
7255
|
+
#matchCanvasToParent() {
|
|
7256
|
+
const parent = this.#canvas.parentNode;
|
|
7257
|
+
if (parent === null) {
|
|
7258
|
+
return;
|
|
7259
|
+
}
|
|
7260
|
+
const rect = parent.getBoundingClientRect();
|
|
7261
|
+
if (this.#canvas.width === rect.width && this.#canvas.height === rect.height) {
|
|
7262
|
+
return;
|
|
6702
7263
|
}
|
|
7264
|
+
this.#canvas.width = rect.width;
|
|
7265
|
+
this.#canvas.height = rect.height;
|
|
7266
|
+
}
|
|
7267
|
+
#watchCanvasSize() {
|
|
7268
|
+
this.#matchCanvasToParent();
|
|
7269
|
+
const parent = this.#canvas.parentNode;
|
|
7270
|
+
if (parent === null || typeof ResizeObserver === "undefined") {
|
|
7271
|
+
return;
|
|
7272
|
+
}
|
|
7273
|
+
this.#sizeObserver = new ResizeObserver(() => {
|
|
7274
|
+
this.#matchCanvasToParent();
|
|
7275
|
+
requestRender();
|
|
7276
|
+
});
|
|
7277
|
+
this.#sizeObserver.observe(parent);
|
|
7278
|
+
}
|
|
7279
|
+
requestRender() {
|
|
7280
|
+
requestRender();
|
|
7281
|
+
}
|
|
7282
|
+
renderContinuously() {
|
|
7283
|
+
return renderContinuously();
|
|
7284
|
+
}
|
|
7285
|
+
dispose() {
|
|
7286
|
+
this.#stopRendering();
|
|
7287
|
+
this.#sizeObserver?.disconnect();
|
|
7288
|
+
}
|
|
7289
|
+
#render() {
|
|
7290
|
+
this.#matchCanvasToParent();
|
|
6703
7291
|
this.#cursor = "default" /* Default */;
|
|
6704
7292
|
TimeExecution("Render_Background", this.#renderBackground.bind(this));
|
|
6705
7293
|
TimeExecution("Render_View_" + this.#currentView, () => {
|
|
@@ -6708,13 +7296,15 @@ var NodeFlowGraph = class {
|
|
|
6708
7296
|
this.#cursor = results?.cursorStyle;
|
|
6709
7297
|
}
|
|
6710
7298
|
});
|
|
7299
|
+
TimeExecution("Render_Minimap", () => {
|
|
7300
|
+
this.#minimap.render(this.#ctx, this.#canvas, this.#camera, this.#mainNodeSubsystem.getNodes());
|
|
7301
|
+
});
|
|
6711
7302
|
TimeExecution("Render_Context", this.#renderContextMenu.bind(this));
|
|
6712
7303
|
TimeExecution("Render_QuickMenu", this.#renderQuickMenu.bind(this));
|
|
6713
7304
|
if (this.#lastFrameCursor !== this.#cursor) {
|
|
6714
7305
|
this.#canvas.style.cursor = this.#cursor;
|
|
6715
7306
|
}
|
|
6716
7307
|
this.#lastFrameCursor = this.#cursor;
|
|
6717
|
-
window.requestAnimationFrame(this.#render.bind(this));
|
|
6718
7308
|
}
|
|
6719
7309
|
#renderBackground() {
|
|
6720
7310
|
this.#backgroundRenderer(this.#canvas, this.#ctx, this.#camera.position, this.#camera.zoom);
|
|
@@ -6756,6 +7346,7 @@ var NodeFlowGraph = class {
|
|
|
6756
7346
|
GlobalWidgetFactory,
|
|
6757
7347
|
ImageWidget,
|
|
6758
7348
|
MessageType,
|
|
7349
|
+
Minimap,
|
|
6759
7350
|
NodeFactory,
|
|
6760
7351
|
NodeFlowGraph,
|
|
6761
7352
|
NodeState,
|
|
@@ -6769,6 +7360,10 @@ var NodeFlowGraph = class {
|
|
|
6769
7360
|
Theme,
|
|
6770
7361
|
ToggleWidget,
|
|
6771
7362
|
WidgetFactory,
|
|
6772
|
-
|
|
7363
|
+
portConfigTypes,
|
|
7364
|
+
portsCompatible,
|
|
7365
|
+
renderContinuously,
|
|
7366
|
+
requestRender,
|
|
7367
|
+
typeSetsCompatible
|
|
6773
7368
|
});
|
|
6774
7369
|
//# sourceMappingURL=index.js.map
|