PageRenderTime 74ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/xf/nucled/Graph.d

https://bitbucket.org/h3r3tic/boxen
D | 1478 lines | 1094 code | 287 blank | 97 comment | 203 complexity | c2a232ce94c2c9177abfbcd9820bc40d MD5 | raw file
  1. module xf.nucled.Graph;
  2. private {
  3. import xf.Common;
  4. import xf.nucleus.Param;
  5. import xf.nucleus.TypeSystem;
  6. import xf.nucleus.kdef.model.IKDefUtilParser;
  7. import xf.nucleus.kdef.model.KDefInvalidation;
  8. import xf.nucleus.kdef.model.IKDefRegistry;
  9. import xf.nucleus.kdef.Common : KDefGraph = GraphDef, KDefGraphNode = GraphDefNode, ParamListValue, GraphDefValue, KernelDefValue, KernelDef, KernelImpl;
  10. import xf.nucleus.Value;
  11. import xf.nucleus.Function;
  12. import xf.nucleus.Nucleus;
  13. import xf.nucled.DataProvider;
  14. import xf.hybrid.Hybrid;
  15. import xf.hybrid.Common;
  16. import xf.hybrid.CustomWidget;
  17. import xf.omg.core.LinearAlgebra;
  18. import xf.nucled.Widgets;
  19. import xf.nucled.Misc;
  20. import xf.nucled.Settings;
  21. import xf.nucled.Log : log = nucledLog;
  22. import xf.nucled.DynamicGridInput;
  23. import xf.utils.Array : arrayRemove = remove;
  24. import xf.mem.ChunkQueue;
  25. import xf.mem.Gather;
  26. static import xf.utils.Array;
  27. //import xf.utils.OldCfg : Config = Array;
  28. import xf.core.Registry;
  29. import tango.text.convert.Format;
  30. import TextUtil = tango.text.Util;
  31. import tango.io.stream.Format;
  32. import tango.io.vfs.model.Vfs : VfsFolder, VfsFile;
  33. import tango.io.device.File : FileConduit = File;
  34. import tango.io.stream.Lines : Lines;
  35. import tango.io.Stdout;
  36. }
  37. class Graph {
  38. this(GraphMngr mngr) {
  39. this._mngr = mngr;
  40. mngr.register(this);
  41. }
  42. void addNode(GraphNode node) {
  43. _nodes ~= node;
  44. node._mngr = this._mngr;
  45. }
  46. void clearNodes() {
  47. // TODO: clean up the nodes?
  48. _nodes.length = 0;
  49. }
  50. int iterAllConnections(int delegate(ref Connection) dg) {
  51. foreach (n; _nodes) {
  52. foreach (o; n.outgoing) {
  53. if (auto r = dg(o)) {
  54. return r;
  55. }
  56. }
  57. }
  58. return 0;
  59. }
  60. GraphNode[] nodes() {
  61. return _nodes;
  62. }
  63. void doGUI() {
  64. GraphNode nodeToDelete = null;
  65. foreach (n; _nodes) {
  66. if (!n.doGUI) {
  67. nodeToDelete = n;
  68. }
  69. }
  70. if (nodeToDelete !is null) {
  71. _nodes.arrayRemove(nodeToDelete);
  72. nodeToDelete.unlink;
  73. }
  74. }
  75. void dump(KDefGraph kdef, IKDefRegistry reg) {
  76. kdef._name = null; // TODO
  77. kdef._nodes = kdef.mem.allocArrayNoInit!(KDefGraphNode)(this.nodes.length);
  78. kdef._nodeNames = kdef.mem.allocArrayNoInit!(cstring)(this.nodes.length);
  79. foreach (ni, n; this.nodes) {
  80. VarDef[1] vars;
  81. vars[0] = VarDef("type", kdef.mem._new!(IdentifierValue)(n.typeName()));
  82. kdef._nodes[ni] = kdef.mem._new!(KDefGraphNode)(
  83. vars[],
  84. kdef.mem._allocator
  85. );
  86. n.dump(kdef._nodes[ni], reg);
  87. kdef._nodeNames[ni] = kdef.mem.dupString(n.label);
  88. }
  89. {
  90. alias GraphDef.NodeConnection NC;
  91. gatherArrays!(NC)(kdef.mem,
  92. (void delegate(lazy NC) gen) {
  93. foreach (n; nodes) {
  94. foreach (con; n.outgoing) {
  95. foreach (flow; con.flow) {
  96. if (depOutputConnectorName == flow.from) {
  97. gen(NC(
  98. kdef._nodes[xf.utils.Array.indexOf(nodes, con.from)],
  99. kdef._nodes[xf.utils.Array.indexOf(nodes, con.to)]
  100. ));
  101. }
  102. }
  103. }
  104. }
  105. },
  106. (NC[] nodeCons) {
  107. kdef.nodeConnections = nodeCons;
  108. });
  109. }
  110. {
  111. alias GraphDef.NodeFieldConnection NFC;
  112. gatherArrays!(NFC)(kdef.mem,
  113. (void delegate(lazy NFC) gen) {
  114. foreach (n; nodes) {
  115. foreach (con; n.outgoing) {
  116. foreach (flow; con.flow) {
  117. if (depOutputConnectorName != flow.from) {
  118. gen(NFC(
  119. kdef._nodes[xf.utils.Array.indexOf(nodes, con.from)],
  120. kdef._nodes[xf.utils.Array.indexOf(nodes, con.to)],
  121. // duplicated later --->
  122. flow.from,
  123. flow.to
  124. ));
  125. }
  126. }
  127. }
  128. }
  129. },
  130. (NFC[] nodeCons) {
  131. foreach (ref c; nodeCons) {
  132. // <---
  133. c.from = kdef.mem.dupString(c.from);
  134. c.to = kdef.mem.dupString(c.to);
  135. }
  136. kdef.nodeFieldConnections = nodeCons;
  137. });
  138. }
  139. {
  140. alias GraphDef.NoAutoFlow NAF;
  141. gatherArrays!(NAF)(kdef.mem,
  142. (void delegate(lazy NAF) gen) {
  143. foreach (ni, n; nodes) {
  144. foreach (i; n.inputs) {
  145. if (i.noAutoFlow) {
  146. gen(NAF(
  147. kdef._nodes[ni],
  148. kdef.mem.dupString(i.name)
  149. ));
  150. }
  151. }
  152. }
  153. },
  154. (NAF[] noAutoFlow) {
  155. kdef.noAutoFlow = noAutoFlow;
  156. });
  157. }
  158. }
  159. void load(KDefGraph source) {
  160. Stdout.formatln("Graph.load() called");
  161. GraphNode[void*] def2node;
  162. foreach (nname, kdefNode; source.nodes) {
  163. auto node = new GraphNode(kdefNode);
  164. def2node[cast(void*)kdefNode] = node;
  165. node.label = nname.dup;
  166. addNode(node);
  167. Stdout.formatln("loading a graph node");
  168. }
  169. foreach (ncon; source.nodeConnections) {
  170. new Connection(
  171. def2node[cast(void*)ncon.from],
  172. def2node[cast(void*)ncon.to],
  173. DataFlow(depOutputConnectorName, depInputConnectorName)
  174. );
  175. }
  176. foreach (nfcon; source.nodeFieldConnections) {
  177. new Connection(
  178. def2node[cast(void*)nfcon.fromNode],
  179. def2node[cast(void*)nfcon.toNode],
  180. DataFlow(nfcon.from.dup, nfcon.to.dup)
  181. );
  182. }
  183. foreach (naf; source.noAutoFlow) {
  184. final node = def2node[cast(void*)naf.toNode];
  185. foreach (ref input; node.inputs) {
  186. if (naf.to == input.name) {
  187. input.noAutoFlow = true;
  188. }
  189. }
  190. }
  191. foreach (lo; loadObservers) {
  192. lo(this);
  193. }
  194. }
  195. protected {
  196. GraphMngr _mngr;
  197. GraphNode[] _nodes;
  198. }
  199. public {
  200. void delegate(Graph)[] loadObservers;
  201. }
  202. }
  203. class ConnectorInfo {
  204. char[] name;
  205. GraphNode node;
  206. vec2 windowPos = vec2.zero;
  207. bool noAutoFlow = false;
  208. this(Param param, GraphNode node) {
  209. this.name = param.name.dup;
  210. this.node = node;
  211. }
  212. }
  213. interface NodeContents {
  214. void doGUI();
  215. void refresh();
  216. }
  217. struct DataFlow {
  218. char[] from;
  219. char[] to;
  220. }
  221. class Connection {
  222. this(GraphNode from, GraphNode to, DataFlow[] flow ...) {
  223. this.from = from;
  224. this.to = to;
  225. this.flow = flow.dup;
  226. from.addOutgoingConnection(this);
  227. to.addIncomingConnection(this);
  228. }
  229. void unlink() {
  230. void remFrom(ref Connection[] cl) {
  231. foreach (i, c; cl) {
  232. if (this is c) {
  233. cl[i] = cl[$-1];
  234. cl = cl[0..$-1];
  235. return;
  236. }
  237. }
  238. assert (false, `not found`);
  239. }
  240. assert (from !is null);
  241. assert (to !is null);
  242. remFrom(from.outgoing);
  243. remFrom(to.incoming);
  244. }
  245. GraphNode from;
  246. GraphNode to;
  247. DataFlow[] flow;
  248. }
  249. ConnectorInfo find(ConnectorInfo[] arr, char[] name) {
  250. foreach (ref x; arr) {
  251. if (x.name == name) {
  252. return x;
  253. }
  254. }
  255. return null;
  256. }
  257. class GraphNode {
  258. enum Type {
  259. Calc,
  260. Data,
  261. GPUWrap,
  262. Demux,
  263. Query,
  264. Input,
  265. Output
  266. }
  267. this(Type t) {
  268. _mem.initialize();
  269. this._id = g_nextId++;
  270. this.data = new DataCommons;
  271. this.data.params._allocator = &_mem.pushBack;
  272. this.type = t;
  273. if (type != Type.Input && type != Type.Data) {
  274. Param meh;
  275. // works because the arg is a const string
  276. meh.unsafeOverrideName(depInputConnectorName);
  277. this.inputs ~= new ConnectorInfo(meh, this);
  278. }
  279. if (type != Type.Output) {
  280. Param meh;
  281. // works because the arg is a const string
  282. meh.unsafeOverrideName(depOutputConnectorName);
  283. this.outputs ~= new ConnectorInfo(meh, this);
  284. }
  285. }
  286. this(Type t, char[] kernelName) {
  287. this(t);
  288. this._kernelName = kernelName;
  289. if (isKernelBased) {
  290. createKernelNodeInputs();
  291. }
  292. }
  293. private void createKernelNodeInputs() {
  294. auto impl = getKernel();
  295. if (KernelImpl.Type.Kernel == impl.type) {
  296. final kernel = impl.kernel;
  297. final func = kernel.func;
  298. foreach (param; func.params) {
  299. Stdout.formatln(`Creating a param '{}'`, param.name);
  300. if (param.isInput) {
  301. inputs ~= new ConnectorInfo(param, this);
  302. } else {
  303. outputs ~= new ConnectorInfo(param, this);
  304. }
  305. }
  306. } else {
  307. final graph = cast(GraphDef)impl.graph;
  308. foreach (name, n; graph.nodes) {
  309. if ("input" == n.type) {
  310. foreach (param; n.params) {
  311. inputs ~= new ConnectorInfo(param, this);
  312. }
  313. } else if ("output" == n.type) {
  314. foreach (param; n.params) {
  315. outputs ~= new ConnectorInfo(param, this);
  316. }
  317. }
  318. }
  319. }
  320. }
  321. this (KDefGraphNode cfg) {
  322. //_mem.initialize();
  323. char[] identVal(char[] name) {
  324. return cfg.getVar(name).as!(IdentifierValue).value;
  325. }
  326. this(typeFromString(identVal("type")));
  327. if (auto sp = cfg.getVar("center")) {
  328. this.spawnPosition = vec2.from(sp.as!(Vector2Value).value);
  329. }
  330. // there's also the size, but we'll ignore it for now
  331. if (this.isKernelBased) {
  332. final val = cfg.getVar("kernel");
  333. if (auto kd = cast(KernelDefValue)val) {
  334. _kernelName = "inline";
  335. _isInline = true;
  336. _inlineKernel = kd.kernelDef;
  337. //assert (false, "TODO: inline kernels");
  338. } else if (auto gd = cast(GraphDefValue)val) {
  339. _kernelName = "inline";
  340. _isInline = true;
  341. _inlineGraph = gd.graphDef;
  342. //assert (false, "TODO: inline graphs");
  343. } else {
  344. _kernelName = identVal("kernel").dup;
  345. }
  346. createKernelNodeInputs();
  347. // TODO: ParamValueInfo
  348. } else {
  349. foreach (param; cfg.params) {
  350. this.data.params.add(param);
  351. paramValueInfo ~= ParamValueInfo();
  352. if (Type.Output == this.type) {
  353. inputs ~= new ConnectorInfo(param, this);
  354. } else {
  355. outputs ~= new ConnectorInfo(param, this);
  356. }
  357. }
  358. }
  359. }
  360. // TODO: mem
  361. void addInput(Param p) {
  362. inputs ~= new ConnectorInfo(p, this);
  363. if (!this.isKernelBased) {
  364. this.data.params.add(p).dir = ParamDirection.In;
  365. }
  366. paramValueInfo ~= ParamValueInfo();
  367. }
  368. // TODO: mem
  369. void addOutput(Param p) {
  370. outputs ~= new ConnectorInfo(p, this);
  371. if (!this.isKernelBased) {
  372. this.data.params.add(p).dir = ParamDirection.Out;
  373. }
  374. paramValueInfo ~= ParamValueInfo();
  375. }
  376. uint id() {
  377. return this._id;
  378. }
  379. int iterInputs(int delegate(ref int i, ref ConnectorInfo) dg) {
  380. int i;
  381. foreach (ref x; inputs) {
  382. if (auto r = dg(i, x)) {
  383. return r;
  384. }
  385. ++i;
  386. }
  387. return 0;
  388. }
  389. int iterOutputs(int delegate(ref int i, ref ConnectorInfo) dg) {
  390. int i;
  391. foreach (ref x; outputs) {
  392. if (auto r = dg(i, x)) {
  393. return r;
  394. }
  395. ++i;
  396. }
  397. return 0;
  398. }
  399. /+char[] title() {
  400. return Format("{} ({}) : {}", _funcName == "main" ? _kernelName : _kernelName ~ ":" ~ _funcName, this.id, primLevelStr);
  401. }+/
  402. void getTitle(Cb)(Cb res) {
  403. char[256] buf;
  404. uint bufPtr = 0;
  405. auto sink = (char[] s) {
  406. uint to = bufPtr+s.length;
  407. if (to > buf.length) {
  408. to = buf.length;
  409. }
  410. buf[bufPtr..to] = s;
  411. bufPtr = to;
  412. return bufPtr;
  413. };
  414. char[] label = _kernelName;
  415. switch (type) {
  416. case Type.Data: label = "Data"; break;
  417. case Type.Input: label = "Input"; break;
  418. case Type.Output: label = "Output"; break;
  419. default: break;
  420. }
  421. Format.convert(sink, "{} ({})", label, this.id);
  422. res(buf[0..bufPtr]);
  423. }
  424. /+char[] primLevelStr() {
  425. return CPU ? "cpu" : (primLevel == PrimLevel.Vertex ? "vtx" : (primLevel == PrimLevel.Fragment ? "frag" : "wtf"));
  426. }
  427. void setPrimLevel(char[] str) {
  428. switch (str) {
  429. case "cpu":
  430. CPU = true;
  431. break;
  432. case "vtx":
  433. CPU = false;
  434. primLevel = PrimLevel.Vertex;
  435. break;
  436. case "frag":
  437. CPU = false;
  438. primLevel = PrimLevel.Fragment;
  439. break;
  440. default: assert (false, str);
  441. }
  442. }+/
  443. void dump(KDefGraphNode kdef, IKDefRegistry reg) {
  444. if (this.isKernelBased) {
  445. kdef.kernelImpl = getKernel();
  446. } else {
  447. kdef.params = data.params;
  448. }
  449. }
  450. char[] typeName() {
  451. switch (this.type) {
  452. case Type.Calc: return "kernel";
  453. case Type.Data: return "data";
  454. case Type.Input: return "input";
  455. case Type.Output: return "output";
  456. default: assert (false);
  457. }
  458. }
  459. static Type typeFromString(char[] type) {
  460. switch (type) {
  461. case "kernel": return Type.Calc;
  462. case "data": return Type.Data;
  463. case "input": return Type.Input;
  464. case "output": return Type.Output;
  465. default: assert (false, type);
  466. }
  467. }
  468. bool doGUI() {
  469. auto box = _widget = GraphNodeBox(this.id);
  470. getTitle((char[] t) { box.label = t; });
  471. this.currentCenter = box.globalOffset + box.size * 0.5f;
  472. this.currentSize = box.size;
  473. if (!box.initialized) {
  474. box.parentOffset = spawnPosition;
  475. switch (this.type) {
  476. case Type.Calc:
  477. break;
  478. default:
  479. box.enableStyle(this.typeName);
  480. break;
  481. }
  482. box.addHandler(&clickHandler);
  483. } else {
  484. this.spawnPosition = box.parentOffset;
  485. }
  486. int inputToRemove = -1;
  487. box.open(`inputs`);
  488. foreach (i, ref data; &iterInputs) {
  489. if (Type.Demux == this.type) {
  490. if (i >= inputs.length / 2) {
  491. break;
  492. }
  493. }
  494. HBox(i) [{
  495. DataConnector con;
  496. if (!data.noAutoFlow) {
  497. con = DataConnector();
  498. con.layoutAttribs("vexpand");
  499. }
  500. if (showDataNames) {
  501. final label = Label().text(data.name).fontSize(10).valign(1).layoutAttribs("vexpand vfill");
  502. if (con) {
  503. label.style.color.value = vec4(1, 1, 1, 1);
  504. } else {
  505. label.style.color.value = vec4(1, 1, 1, 0.2);
  506. }
  507. auto brk = ConnectionBreaker();
  508. brk.layoutAttribs("vexpand");
  509. if (brk.clicked) {
  510. inputToRemove = i;
  511. }
  512. }
  513. if (con) {
  514. con.input = true;
  515. con.ci = data;
  516. con.mouseButtonHandler = &_mngr.handleMouseButton;
  517. data.windowPos = con.globalOffset + con.size * 0.5f;
  518. }
  519. }].layoutAttribs = "hexpand hfill";
  520. }
  521. gui.close;
  522. if (showContents && contents !is null) {
  523. box.open(`contents`);
  524. contents.doGUI();
  525. gui.close;
  526. }
  527. int outputToRemove = -1;
  528. box.open(`outputs`);
  529. foreach (i, ref data; &iterOutputs) {
  530. HBox(i) [{
  531. Dummy().layoutAttribs("hexpand hfill");
  532. if (showDataNames) {
  533. auto brk = ConnectionBreaker();
  534. brk.layoutAttribs("vexpand");
  535. if (brk.clicked) {
  536. outputToRemove = i;
  537. }
  538. Label().text(data.name).fontSize(10).valign(1).layoutAttribs("vexpand vfill");
  539. }
  540. auto con = DataConnector();
  541. con.layoutAttribs("vexpand");
  542. con.input = false;
  543. con.ci = data;
  544. con.mouseButtonHandler = &_mngr.handleMouseButton;
  545. data.windowPos = con.globalOffset + con.size * 0.5f;
  546. }].layoutAttribs = "hexpand hfill";
  547. }
  548. gui.close;
  549. if (inputToRemove != -1) {
  550. bool removed = removeIncomingConnectionsTo(inputs[inputToRemove].name);
  551. if (!removed) {
  552. inputs[inputToRemove].noAutoFlow ^= true;
  553. }
  554. }
  555. if (outputToRemove != -1) {
  556. removeOutgoingConnectionsFrom(outputs[outputToRemove].name);
  557. }
  558. /+bool allowGPU = this.type != Type.GPUWrap;
  559. if (allowGPU) {
  560. box.open(`bottom`); {
  561. bool allowCPU = this.type != Type.Demux && this.type != Type.Query;
  562. XorSelector grp;
  563. int cpuIndex = -1;
  564. XCheck cpu;
  565. if (allowCPU) {
  566. cpu = XCheck().text("c").group(grp);
  567. cpuIndex = 0;
  568. }
  569. auto vertex = XCheck().text("v").group(grp);
  570. auto fragment = XCheck().text("f").group(grp);
  571. if (this.CPU) {
  572. assert (cpu !is null);
  573. DefaultOption = cpu;
  574. } else {
  575. if (PrimLevel.Fragment == this.primLevel) {
  576. DefaultOption = fragment;
  577. } else {
  578. DefaultOption = vertex;
  579. }
  580. }
  581. this.CPU = cpuIndex == grp.index;
  582. if (cpuIndex+1 == grp.index) {
  583. this.primLevel = PrimLevel.Vertex;
  584. }
  585. else if (cpuIndex+2 == grp.index) {
  586. this.primLevel = PrimLevel.Fragment;
  587. }
  588. }
  589. gui.close;
  590. } else {
  591. assert (this.CPU);
  592. }+/
  593. bool wasEditingProps = _editingProps;
  594. if (box.doubleClicked) {
  595. _editingProps = true;
  596. }
  597. if (_editingProps) {
  598. auto frame = FloatingWindow(this.id);
  599. frame [{
  600. doEditorGUI(!wasEditingProps, frame.wantsToClose);
  601. }];
  602. //frame.text = this.title;
  603. getTitle((char[] t) { frame.text = t; });
  604. if (frame.wantsToClose) {
  605. _editingProps = false;
  606. }
  607. if (!wasEditingProps) {
  608. frame.parentOffset = box.parentOffset + vec2(5, box.size.y+5);
  609. }
  610. }
  611. return !box.deleteClicked;
  612. }
  613. void addOutgoingConnection(Connection con) {
  614. outgoing ~= con;
  615. }
  616. void addIncomingConnection(Connection con) {
  617. incoming ~= con;
  618. }
  619. bool isKernelBased() {
  620. switch (this.type) {
  621. case Type.Calc:
  622. case Type.GPUWrap:
  623. case Type.Demux:
  624. case Type.Query:
  625. return true;
  626. case Type.Data:
  627. case Type.Input:
  628. case Type.Output:
  629. return false;
  630. default: assert (false);
  631. }
  632. }
  633. KernelImpl getKernel() {
  634. if (_isInline) {
  635. return _inlineGraph
  636. ? KernelImpl(_inlineGraph)
  637. : KernelImpl(_inlineKernel);
  638. } else {
  639. return kdefRegistry.getKernel(kernelName);
  640. }
  641. }
  642. bool _choosingImpl;
  643. //QuarkDef _quarkBeingEdited;
  644. void doEditorGUI(bool justOpened, bool closing) {
  645. if (isKernelBased) {
  646. if (!_inlineGraph) {
  647. doCodeEditorGUI(justOpened, closing);
  648. } else {
  649. // TODO: graph editor
  650. }
  651. } else {
  652. doDataEditorGUI(justOpened, closing);
  653. }
  654. }
  655. char[] safeName(char[] prev, char[] name) {
  656. if (!data.params.get(name)) {
  657. return name;
  658. } else {
  659. if (prev.length > 0) {
  660. return prev;
  661. }
  662. for (int i = 1; i < 10000; ++i) {
  663. auto tmp = Format("{}{}", name, i);
  664. if (!data.params.get(tmp)) {
  665. return tmp;
  666. }
  667. }
  668. }
  669. assert (false);
  670. }
  671. static class QuarkSciEditor : SciEditor {
  672. // in the loaded source
  673. uint firstByte;
  674. uint lastByte;
  675. KDefModule kdefMod;
  676. void editorSaveHandler() {
  677. if (kdefMod is null) {
  678. return;
  679. }
  680. auto sourceVfsFile = _outer.getVfsFile(kdefMod);
  681. char[] text; {
  682. auto sourceFile = sourceVfsFile.input;
  683. scope (exit) sourceFile.close;
  684. text = cast(char[])sourceFile.load();
  685. }
  686. // TODO: check for potential external modifications to the file
  687. try {
  688. if (sourceVfsFile.exists) {
  689. sourceVfsFile.remove;
  690. }
  691. } catch {} // we don't want failz here. better try to write the contents anyway when shit hits the fan
  692. try {
  693. sourceVfsFile.create;
  694. } catch {} // ditto
  695. auto dstFile = sourceVfsFile.output;
  696. scope (exit) dstFile.flush.close;
  697. dstFile.write(text[0..firstByte] ~ this.text ~ text[lastByte..$]);
  698. }
  699. override protected EventHandling handleKey(KeyboardEvent e) {
  700. if (KeySym.s == e.keySym && (e.modifiers & e.modifiers.CTRL) != 0) {
  701. if (e.sinking && e.down) {
  702. this.editorSaveHandler();
  703. }
  704. return EventHandling.Stop;
  705. } else {
  706. return super.handleKey(e);
  707. }
  708. }
  709. GraphNode _outer;
  710. mixin MWidget;
  711. }
  712. VfsFile getVfsFile(KDefModule mod) {
  713. assert (mod !is null);
  714. final vfs = kdefRegistry.kdefFileParser.getVFS();
  715. assert (vfs !is null);
  716. if (auto sourceVfsFile = vfs.file(mod.filePath)) {
  717. log.trace("mod file: {} [ {} ]", sourceVfsFile.name, sourceVfsFile.toString);
  718. return sourceVfsFile;
  719. } else {
  720. log.error("Could not get load the source for module: '{}'.", mod.filePath);
  721. return null;
  722. }
  723. }
  724. void doCodeEditorGUI(bool justOpened, bool closing) {
  725. //assert (quark !is null);
  726. auto sci = QuarkSciEditor();
  727. sci._outer = this;
  728. if (justOpened) {
  729. KernelDef kernel = _isInline
  730. ? _inlineKernel
  731. : kdefRegistry.getKernel(_kernelName).kernel;
  732. if (kernel) {
  733. if (auto func = cast(Function)kernel.func) {
  734. if (func.code._lengthBytes > 0) {
  735. if (auto mod = cast(KDefModule)func.code._module) {
  736. if (auto sourceVfsFile = getVfsFile(mod)) {
  737. auto sourceFile = sourceVfsFile.input;
  738. scope (exit) sourceFile.close;
  739. char[] text = cast(char[])sourceFile.load();
  740. uint first = func.code._firstByte;
  741. uint last = first + func.code._lengthBytes;
  742. // expand the range to include all the spaces and
  743. // tabs preceding the first token in the code
  744. char c;
  745. while (
  746. first > 0 &&
  747. ((c = text[first-1]) == ' ' || c == '\t')
  748. ) --first;
  749. sci.text = text[first..last];
  750. sci.firstByte = first;
  751. sci.lastByte = last;
  752. sci.kdefMod = mod;
  753. } else {
  754. log.warn("Failed to load code for the kernel '{}': unable to load file.", _kernelName);
  755. }
  756. } else {
  757. log.warn("Failed to load code for the kernel '{}': _module is null.", _kernelName);
  758. }
  759. }
  760. } else {
  761. log.info("Can't edit kernel '{}': it is abstract.", _kernelName);
  762. }
  763. } else {
  764. log.warn("Failed to get the kernel '{}' for a code editor.", _kernelName);
  765. }
  766. sci.grabKeyboardFocus();
  767. }
  768. sci.userSize = vec2(300, 80);
  769. }
  770. void doDataEditorGUI(bool justOpened, bool closing) {
  771. auto grid = DynamicGridInput();
  772. struct UserData {
  773. char[][int] semanticsEdited;
  774. }
  775. UserData* userData = justOpened ? null : cast(UserData*)grid.userData;
  776. if (userData is null) {
  777. grid.userData = userData = new UserData;
  778. }
  779. if (justOpened) {
  780. grid.popupMsg = null;
  781. }
  782. DynamicGridInputModel model;
  783. model.onAddRow = {
  784. char[] newName = safeName(null, "noname");
  785. if (Type.Output == this.type) {
  786. auto p = data.params.add(ParamDirection.In, newName);
  787. p.hasPlainSemantic = true;
  788. p.type = "void";
  789. inputs ~= new ConnectorInfo(*p, this);
  790. } else {
  791. auto p = data.params.add(ParamDirection.Out, newName);
  792. p.hasPlainSemantic = true;
  793. p.type = "void";
  794. outputs ~= new ConnectorInfo(*p, this);
  795. }
  796. paramValueInfo ~= ParamValueInfo();
  797. };
  798. model.onRemoveRow = (int i) {
  799. grid.popupMsg = null;
  800. if (i < data.params.length) {
  801. onDeleteParam(data.params[i].name);
  802. }
  803. };
  804. model.onCellChanged = (int row, int column, char[] val) {
  805. Param* p = data.params[row];
  806. grid.popupMsg = null;
  807. bool semanticChanged = false;
  808. // TODO: paramValueInfo
  809. switch (column) {
  810. case 0:
  811. char[] newName = safeName(p.name, val.dup);
  812. onRenameParam(p.name, newName);
  813. p.name = newName;
  814. break;
  815. case 1:
  816. auto str = val.dup;
  817. userData.semanticsEdited[row] = str;
  818. str = TextUtil.trim(str);
  819. if (str.length > 0) {
  820. auto parser = create!(IKDefUtilParser)();
  821. parser.parse_ParamSemantic(str, (Semantic res) {
  822. p.semantic.clearTraits();
  823. // HACK: this is ugly. manage allocators
  824. // in some other way
  825. *p.semantic() = res.dup(&_mem.pushBack);
  826. });
  827. delete parser;
  828. } else {
  829. p.semantic.clearTraits();
  830. }
  831. semanticChanged = true;
  832. break;
  833. default: assert (false);
  834. }
  835. if (semanticChanged) switch (column) {
  836. case 1:
  837. grid.popupCol = 1;
  838. grid.popupRow = row;
  839. grid.popupMsg = p.semantic.toString.dup;
  840. default:
  841. break;
  842. }
  843. };
  844. model.getNumRows = delegate int(){
  845. return data.params.length;
  846. };
  847. model.getNumColumns = {
  848. return 2;
  849. };
  850. model.getCellValue = (int row, int column) {
  851. if (row < data.params.length) {
  852. Param* p = data.params[row];
  853. switch (column) {
  854. case 0:
  855. return p.name;
  856. case 1:
  857. if (auto s = row in userData.semanticsEdited) {
  858. return *s;
  859. } else {
  860. return p.semantic.toString();
  861. }
  862. default: assert (false);
  863. }
  864. } else {
  865. return cast(char[])null;
  866. }
  867. };
  868. grid.doGUI(justOpened, model);
  869. }
  870. void onRenameParam(char[] from, char[] to) {
  871. foreach (con; outgoing) {
  872. foreach (ref fl; con.flow) {
  873. if (fl.from == from) {
  874. fl.from = to;
  875. }
  876. }
  877. }
  878. foreach (con; incoming) {
  879. foreach (ref fl; con.flow) {
  880. if (fl.to == from) {
  881. fl.to = to;
  882. }
  883. }
  884. }
  885. foreach (ref con; inputs) {
  886. if (con.name == from) {
  887. con.name = to;
  888. }
  889. }
  890. foreach (ref con; outputs) {
  891. if (con.name == from) {
  892. con.name = to;
  893. }
  894. }
  895. }
  896. void removeOutgoingConnectionsFrom(char[] name) {
  897. for (int i = 0; i < outgoing.length;) {
  898. auto con = outgoing[i];
  899. for (int j = 0; j < con.flow.length;) {
  900. auto fl = &con.flow[j];
  901. if (fl.from == name) {
  902. *fl = con.flow[$-1];
  903. con.flow = con.flow[0..$-1];
  904. } else {
  905. ++j;
  906. }
  907. }
  908. if (0 == con.flow.length) {
  909. con.unlink;
  910. } else {
  911. ++i;
  912. }
  913. }
  914. }
  915. bool removeIncomingConnectionsTo(char[] name) {
  916. bool res = false;
  917. for (int i = 0; i < incoming.length;) {
  918. auto con = incoming[i];
  919. for (int j = 0; j < con.flow.length;) {
  920. auto fl = &con.flow[j];
  921. if (fl.to == name) {
  922. *fl = con.flow[$-1];
  923. con.flow = con.flow[0..$-1];
  924. res = true;
  925. } else {
  926. ++j;
  927. }
  928. }
  929. if (0 == con.flow.length) {
  930. con.unlink;
  931. res = true;
  932. } else {
  933. ++i;
  934. }
  935. }
  936. return res;
  937. }
  938. void onDeleteParam(char[] name) {
  939. final i = data.params.indexOf(name);
  940. xf.utils.Array.removeKeepOrder(paramValueInfo, i);
  941. data.params.remove(name);
  942. removeOutgoingConnectionsFrom(name);
  943. removeIncomingConnectionsTo(name);
  944. foreach (ref con; inputs) {
  945. if (con.name == name) {
  946. con = inputs[$-1];
  947. inputs = inputs[0..$-1];
  948. break;
  949. }
  950. }
  951. foreach (ref con; outputs) {
  952. if (con.name == name) {
  953. con = outputs[$-1];
  954. outputs = outputs[0..$-1];
  955. break;
  956. }
  957. }
  958. foreach (con; outgoing) {
  959. foreach (fl; con.flow) {
  960. auto src = con.from.outputs.find(fl.from);
  961. assert (src !is null);
  962. }
  963. }
  964. }
  965. void unlink() {
  966. while (incoming.length) {
  967. incoming[0].unlink;
  968. }
  969. while (outgoing.length) {
  970. outgoing[0].unlink;
  971. }
  972. // TODO: other cleanup (connectors)
  973. }
  974. char[] kernelName() {
  975. return _kernelName;
  976. }
  977. class DataCommons {
  978. ParamList params;
  979. }
  980. EventHandling clickHandler(ClickEvent e) {
  981. if (/+MouseButton.Left == e.button && +/e.bubbling && !e.handled) {
  982. _mngr.onNodeSelected(this);
  983. }
  984. return EventHandling.Continue;
  985. }
  986. // returns the first one
  987. Connection hasConnectionToInput(char[] name, char[]* fromOutput = null) {
  988. foreach (input; incoming) {
  989. foreach (fl; input.flow) {
  990. if (fl.to == name) {
  991. if (fromOutput !is null) {
  992. *fromOutput = fl.from;
  993. }
  994. return input;
  995. }
  996. }
  997. }
  998. return null;
  999. }
  1000. public {
  1001. bool showContents = true;
  1002. bool showDataNames = true;
  1003. NodeContents contents;
  1004. DataCommons data;
  1005. ParamValueInfo[] paramValueInfo;
  1006. Connection[] incoming;
  1007. Connection[] outgoing;
  1008. ConnectorInfo[] inputs;
  1009. ConnectorInfo[] outputs;
  1010. vec2 spawnPosition = vec2.zero;
  1011. vec2 currentCenter = vec2.zero;
  1012. vec2 currentSize = vec2.zero;
  1013. bool _isInline;
  1014. // TODO: reload these on kdef refresh
  1015. static assert (false);
  1016. KernelDef _inlineKernel;
  1017. GraphDef _inlineGraph;
  1018. Type type;
  1019. char[] label;
  1020. }
  1021. private {
  1022. uint _id;
  1023. char[] _kernelName;
  1024. bool _editingProps;
  1025. GraphMngr _mngr;
  1026. GraphNodeBox _widget;
  1027. ScratchFIFO _mem;
  1028. static uint g_nextId = 0;
  1029. }
  1030. }
  1031. class DataConnector : CustomWidget {
  1032. //bool _dragHandlerRegistered = false;
  1033. mixin MWidget;
  1034. EventHandling delegate(bool input, ConnectorInfo ci, MouseButtonEvent e)
  1035. mouseButtonHandler;
  1036. ConnectorInfo ci;
  1037. bool input;
  1038. EventHandling handleMouseButton(MouseButtonEvent e) {
  1039. assert (mouseButtonHandler !is null);
  1040. return mouseButtonHandler(input, ci, e);
  1041. }
  1042. this() {
  1043. addHandler(&handleMouseButton);
  1044. }
  1045. }
  1046. class GraphMngr {
  1047. /+this(INucleus core) {
  1048. this._core = core;
  1049. this._vfs = core.root;
  1050. }+/
  1051. void register(Graph graph) {
  1052. _graphs ~= graph;
  1053. }
  1054. private {
  1055. GraphNode _prevClicked;
  1056. }
  1057. GraphNode selected() {
  1058. return _prevClicked;
  1059. }
  1060. void onNodeSelected(GraphNode node) {
  1061. if (_prevClicked) {
  1062. _prevClicked._widget.disableStyle("selected");
  1063. }
  1064. if (node) {
  1065. node._widget.enableStyle("selected");
  1066. }
  1067. _prevClicked = node;
  1068. }
  1069. public EventHandling handleMouseButton(bool input, ConnectorInfo ci, MouseButtonEvent e) {
  1070. if (MouseButton.Left == e.button && e.down && (e.bubbling && !e.handled)) {
  1071. Stdout.formatln("drag start");
  1072. _connecting = true;
  1073. _connectingFrom = ci;
  1074. _connectingFromInput = input;
  1075. gui.addGlobalHandler(&this.globalHandleMouseButton);
  1076. if (e.bubbling) {
  1077. return EventHandling.Stop;
  1078. }
  1079. }
  1080. return EventHandling.Continue;
  1081. }
  1082. protected bool globalHandleMouseButton(MouseButtonEvent e) {
  1083. if (MouseButton.Left == e.button && !e.down) {
  1084. Stdout.formatln("drag end");
  1085. tryCreateConnection();
  1086. _connecting = false;
  1087. return true;
  1088. }
  1089. return false;
  1090. }
  1091. ConnectorInfo findConnector(vec2 pos, bool inputs, bool outputs, bool autoFlow, GraphNode skipNode, float radius = 20.f) {
  1092. if (autoFlow) {
  1093. radius = 300.f;
  1094. }
  1095. float bestDist = float.max;
  1096. ConnectorInfo bestCon;
  1097. float radSq = radius * radius;
  1098. foreach (graph; _graphs) {
  1099. foreach (node; graph.nodes) {
  1100. if (node is skipNode) {
  1101. continue;
  1102. }
  1103. void process(ConnectorInfo con) {
  1104. float distSq = (con.windowPos - pos).sqLength;
  1105. if (distSq < radSq && distSq < bestDist) {
  1106. bestDist = distSq;
  1107. bestCon = con;
  1108. }
  1109. }
  1110. if (inputs) foreach (ref x; node.inputs) {
  1111. if (!autoFlow || x.name == depInputConnectorName) {
  1112. process(x);
  1113. }
  1114. }
  1115. if (outputs) foreach (ref x; node.outputs) {
  1116. if (!autoFlow || x.name == depOutputConnectorName) {
  1117. process(x);
  1118. }
  1119. }
  1120. }
  1121. }
  1122. return bestCon;
  1123. }
  1124. void tryCreateConnection() {
  1125. assert (_connecting);
  1126. bool tryingAutoFlow = (_connectingFromInput && depInputConnectorName == _connectingFrom.name) ||
  1127. (!_connectingFromInput && depOutputConnectorName == _connectingFrom.name);
  1128. auto droppedOn = findConnector(mousePos, !_connectingFromInput, _connectingFromInput, tryingAutoFlow, _connectingFrom.node);
  1129. if (!droppedOn) {
  1130. return;
  1131. }
  1132. if (_connectingFromInput) {
  1133. if ((depInputConnectorName == _connectingFrom.name) != (droppedOn.name == depOutputConnectorName)) {
  1134. return;
  1135. }
  1136. auto flow = DataFlow(droppedOn.name, _connectingFrom.name);
  1137. foreach (con; droppedOn.node.outgoing) {
  1138. if (con.to is _connectingFrom.node) {
  1139. con.flow ~= flow;
  1140. return;
  1141. }
  1142. }
  1143. new Connection(droppedOn.node, _connectingFrom.node, flow);
  1144. } else {
  1145. if ((depOutputConnectorName == _connectingFrom.name) != (droppedOn.name == depInputConnectorName)) {
  1146. return;
  1147. }
  1148. auto flow = DataFlow(_connectingFrom.name, droppedOn.name);
  1149. foreach (con; _connectingFrom.node.outgoing) {
  1150. if (con.to is droppedOn.node) {
  1151. con.flow ~= flow;
  1152. return;
  1153. }
  1154. }
  1155. new Connection(_connectingFrom.node, droppedOn.node, flow);
  1156. }
  1157. }
  1158. bool connecting() {
  1159. return _connecting;
  1160. }
  1161. ConnectorInfo connectingFrom() {
  1162. return _connectingFrom;
  1163. }
  1164. bool connectingFromInput() {
  1165. return _connectingFromInput;
  1166. }
  1167. vec2 mousePos() {
  1168. return gui.mousePos;
  1169. }
  1170. Graph[] graphs() {
  1171. return _graphs;
  1172. }
  1173. VfsFolder vfs() {
  1174. return _vfs;
  1175. }
  1176. private {
  1177. ConnectorInfo _connectingFrom;
  1178. bool _connecting;
  1179. bool _connectingFromInput;
  1180. Graph[] _graphs;
  1181. VfsFolder _vfs;
  1182. //INucleus _core;
  1183. }
  1184. }