From 8dbab931167110e6f74768db1f8ffa2b5751663a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Dani=C5=82o?= Date: Sat, 30 May 2020 22:34:30 +0200 Subject: [PATCH] Wip/wd/dev (https://github.com/enso-org/ide/pull/492) Original commit: https://github.com/enso-org/ide/commit/18971b05f29ea2eec259f6a688dd26098a06239d --- gui/src/js/package-lock.json | 191 ++-- .../ensogl/src/animation/physics/inertia.rs | 147 +-- gui/src/rust/ensogl/src/data/color/data.rs | 10 +- .../rust/ensogl/src/data/color/space/def.rs | 10 +- .../src/display/navigation/navigator.rs | 26 +- .../rust/ensogl/src/display/object/class.rs | 7 + .../display/shape/primitive/def/primitive.rs | 7 +- .../src/display/shape/primitive/def/unit.rs | 16 +- .../src/display/shape/primitive/def/var.rs | 86 ++ .../shape/text/text_field/frp/mouse.rs | 22 +- .../rust/ensogl/src/display/style/sheet.rs | 6 +- .../rust/ensogl/src/display/style/theme.rs | 2 +- gui/src/rust/ensogl/src/gui/component.rs | 13 +- gui/src/rust/ensogl/src/math.rs | 7 +- gui/src/rust/ensogl/src/math/algebra.rs | 226 ++++- gui/src/rust/ensogl/src/math/topology/unit.rs | 17 +- .../ensogl/src/system/gpu/data/buffer/item.rs | 134 +++ .../ensogl/src/system/gpu/data/default.rs | 5 + .../rust/ensogl/src/system/gpu/data/prim.rs | 1 + .../rust/ensogl/src/system/gpu/data/sized.rs | 16 + .../src/system/gpu/data/uniform/upload.rs | 85 ++ .../rust/ensogl/src/system/gpu/shader/glsl.rs | 49 + gui/src/rust/ide/src/view/node_editor.rs | 16 +- gui/src/rust/lib/data/src/hash_map_tree.rs | 14 +- gui/src/rust/lib/debug-scenes/src/shapes.rs | 83 +- gui/src/rust/lib/frp/src/io/keyboard.rs | 6 +- gui/src/rust/lib/frp/src/io/mouse.rs | 24 +- gui/src/rust/lib/frp/src/macros.rs | 46 +- gui/src/rust/lib/frp/src/nodes.rs | 882 ++++++++++------- .../rust/lib/graph-editor/src/component.rs | 8 +- .../graph-editor/src/component/connection.rs | 220 ----- .../lib/graph-editor/src/component/cursor.rs | 315 ++++--- .../lib/graph-editor/src/component/edge.rs | 883 ++++++++++++++++++ .../component/{connection2.rs => edge2.rs} | 0 .../lib/graph-editor/src/component/node.rs | 245 ++--- .../graph-editor/src/component/node/port.rs | 40 +- gui/src/rust/lib/graph-editor/src/lib.rs | 441 +++++---- gui/src/rust/lib/prelude/src/data/monoid.rs | 63 +- .../rust/lib/prelude/src/data/semigroup.rs | 83 +- 39 files changed, 3059 insertions(+), 1393 deletions(-) delete mode 100644 gui/src/rust/lib/graph-editor/src/component/connection.rs create mode 100644 gui/src/rust/lib/graph-editor/src/component/edge.rs rename gui/src/rust/lib/graph-editor/src/component/{connection2.rs => edge2.rs} (100%) diff --git a/gui/src/js/package-lock.json b/gui/src/js/package-lock.json index f636788c22..614e47c22f 100644 --- a/gui/src/js/package-lock.json +++ b/gui/src/js/package-lock.json @@ -10,27 +10,27 @@ "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==" }, "@babel/code-frame": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz", - "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.1.tgz", + "integrity": "sha512-IGhtTmpjGbYzcEDOw7DcQtbQSXcG9ftmAXtWTu9V936vDye4xjjekktFAtgZsWpzTj/X01jocB46mTywm/4SZw==", "dev": true, "requires": { - "@babel/highlight": "^7.8.3" + "@babel/highlight": "^7.10.1" } }, "@babel/helper-validator-identifier": { - "version": "7.9.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz", - "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.1.tgz", + "integrity": "sha512-5vW/JXLALhczRCWP0PnFDMCJAchlBvM7f4uk/jXritBnIa6E1KmqmtrS3yn1LAnxFBypQ3eneLuXjsnfQsgILw==", "dev": true }, "@babel/highlight": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz", - "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.1.tgz", + "integrity": "sha512-8rMof+gVP8mxYZApLF/JgNDAkdKa+aJt3ZYxF8z6+j/hpeXL7iMsKCPHa2jNMHu/qqBwzQF4OHNoYi8dMA/rYg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.9.0", + "@babel/helper-validator-identifier": "^7.10.1", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } @@ -1251,9 +1251,9 @@ } }, "@octokit/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.0.2.tgz", - "integrity": "sha512-+4X6qfhT/fk/5FD66395NrFLxCzD6FsGlpPwfwvnukdyfYbhiZB/FJltiT1XM5Q63rGGBSf9FPaNV3WpNHm54A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-4.1.1.tgz", + "integrity": "sha512-gOuIVmMCfHzSv3QBwLZjGDEDtYC73A5+tYcccEoq+Jd/h9rG/Mfc+h0+GEU+mpGhx86n7eBw6J/0BZ0zAmLkKg==", "dev": true, "requires": { "@types/node": ">= 8" @@ -1289,9 +1289,9 @@ "dev": true }, "@types/fs-extra": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", - "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-B42Sxuaz09MhC3DDeW5kubRcQ5by4iuVQ0cRRWM2lggLzAa/KVom0Aft/208NgMvNQQZ86s5rVcqDdn/SH0/mg==", "requires": { "@types/node": "*" } @@ -1307,6 +1307,11 @@ "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz", + "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -1727,25 +1732,25 @@ "integrity": "sha512-NSjtqZ3x2kYiDp3Qezsgukx/AUzKPr3Xgf9by4cYt05ILWGAptepeeu0Uv+7MO+41o6ujhLixTou8979JGg2Kg==" }, "app-builder-lib": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.6.1.tgz", - "integrity": "sha512-ENL7r+H7IBfDb4faeLASgndsXrAT7AV7m7yJjcpbFDXYma6an7ZWGFIvR0HJrsfiC5TIB8kdLJ/aMSImrrSi/Q==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.7.0.tgz", + "integrity": "sha512-blRKwV8h0ztualXS50ciCTo39tbuDGNS+ldcy8+KLvKXuT6OpYnSJ7M6MSfPT+xWatshMHJV1rJx3Tl+k/Sn/g==", "requires": { "7zip-bin": "~5.0.3", "@develar/schema-utils": "~2.6.5", "async-exit-hook": "^2.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chromium-pickle-js": "^0.2.0", - "debug": "^4.1.1", - "ejs": "^3.1.2", - "electron-publish": "22.6.1", + "debug": "^4.2.0", + "ejs": "^3.1.3", + "electron-publish": "22.7.0", "fs-extra": "^9.0.0", "hosted-git-info": "^3.0.4", "is-ci": "^2.0.0", "isbinaryfile": "^4.0.6", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "lazy-val": "^1.0.4", "minimatch": "^3.0.4", "normalize-package-data": "^2.5.0", @@ -1756,11 +1761,11 @@ }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "fs-extra": { @@ -2512,21 +2517,21 @@ "dev": true }, "builder-util": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.6.1.tgz", - "integrity": "sha512-A9cF+bSHqRTSKIUHEyE92Tl0Uh12N7yZRH9bccIL3gRUwtp6ulF28LsjNIWTSQ1clZo2M895cT5PCrKzjPQFVg==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.7.0.tgz", + "integrity": "sha512-UV3MKL0mwjMq2y9JlBf28Cegpj0CrIXcjGkO0TXn+QZ6Yy9rY6lHOuUvpQ19ct2Qh1o+QSwH3Q1nKUf5viJBBg==", "requires": { "7zip-bin": "~5.0.3", "@types/debug": "^4.1.5", - "@types/fs-extra": "^8.1.0", + "@types/fs-extra": "^9.0.1", "app-builder-bin": "3.5.9", "bluebird-lst": "^1.0.9", - "builder-util-runtime": "8.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", - "debug": "^4.1.1", + "debug": "^4.2.0", "fs-extra": "^9.0.0", "is-ci": "^2.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.3.7" @@ -2564,11 +2569,11 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "fs-extra": { @@ -2626,20 +2631,20 @@ } }, "builder-util-runtime": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.0.tgz", - "integrity": "sha512-G1AqqVM2vYTrSFR982c1NNzwXKrGLQjVjaZaWQdn4O6Z3YKjdMDofw88aD9jpyK9ZXkrCxR0tI3Qe9wNbyTlXg==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.1.tgz", + "integrity": "sha512-uEBH1nAnTvzjcsrh2XI3qOzJ39h0+9kuIuwj+kCc3a07TZNGShfJcai8fFzL3mNgGjEFxoq+XMssR11r+FOFSg==", "requires": { - "debug": "^4.1.1", + "debug": "^4.2.0", "sax": "^1.2.4" }, "dependencies": { "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } } } @@ -3176,6 +3181,17 @@ "webpack-sources": "^1.0.1" }, "dependencies": { + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "cacache": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", @@ -3226,11 +3242,12 @@ } }, "schema-utils": { - "version": "2.6.6", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.6.tgz", - "integrity": "sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "requires": { - "ajv": "^6.12.0", + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", "ajv-keywords": "^3.4.1" } }, @@ -4184,15 +4201,15 @@ } }, "dmg-builder": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.6.1.tgz", - "integrity": "sha512-jUTN0acP15puzevtQASj7QEPgUGpedWSuSnOwR/++JbeYRTwU2oro09h/KZnaeMcxgxjdmT3tYLJeY1XUfPbRg==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.7.0.tgz", + "integrity": "sha512-5Ea2YEz6zSNbyGzZD+O9/MzmaXb6oa15cSKWo4JQ1xP4rorOpte7IOj2jcwYjtc+Los2gu1lvT314OC1OZIWgg==", "requires": { - "app-builder-lib": "22.6.1", - "builder-util": "22.6.1", + "app-builder-lib": "22.7.0", + "builder-util": "22.7.0", "fs-extra": "^9.0.0", "iconv-lite": "^0.5.1", - "js-yaml": "^3.13.1", + "js-yaml": "^3.14.0", "sanitize-filename": "^1.6.3" }, "dependencies": { @@ -4349,17 +4366,17 @@ } }, "electron-builder": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.6.1.tgz", - "integrity": "sha512-3/VNg9GfXKHM53TilFtfF1+bsAR8THK1XHgeqCpsiequa02J9jTPc/DhpCUKQPkrs6/EIGxP7uboop7XYoew0Q==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.7.0.tgz", + "integrity": "sha512-t6E3oMutpST64YWbZCg7HodEwJOsnjUF1vnDIHm2MW6CFZPX8tlCK6efqaV66LU0E0Nkp/JH6TE5bCqQ1+VdPQ==", "requires": { "@types/yargs": "^15.0.5", - "app-builder-lib": "22.6.1", + "app-builder-lib": "22.7.0", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", - "dmg-builder": "22.6.1", + "dmg-builder": "22.7.0", "fs-extra": "^9.0.0", "is-ci": "^2.0.0", "lazy-val": "^1.0.4", @@ -4446,14 +4463,14 @@ "integrity": "sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==" }, "electron-publish": { - "version": "22.6.1", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.6.1.tgz", - "integrity": "sha512-/MkS47ospdSfAFW5Jp52OzYou14HhGJpZ51uAc3GJ5rCfACeqpimC/n1ajRLE3hcXxTWfd3t9MCuClq5jrUO5w==", + "version": "22.7.0", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.7.0.tgz", + "integrity": "sha512-hmU69xlb6vvAV3QfpHYDlkdZMFdBAgDbptoxbLFrnTq5bOkcL8AaDbvxeoZ4+lvqgs29NwqGpkHo2oN+p/hCfg==", "requires": { - "@types/fs-extra": "^8.1.0", + "@types/fs-extra": "^9.0.1", "bluebird-lst": "^1.0.9", - "builder-util": "22.6.1", - "builder-util-runtime": "8.7.0", + "builder-util": "22.7.0", + "builder-util-runtime": "8.7.1", "chalk": "^4.0.0", "fs-extra": "^9.0.0", "lazy-val": "^1.0.4", @@ -4517,9 +4534,9 @@ } }, "mime": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.5.tgz", - "integrity": "sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w==" + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" }, "supports-color": { "version": "7.1.0", @@ -6495,9 +6512,9 @@ } }, "global-agent": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.8.tgz", - "integrity": "sha512-VpBe/rhY6Rw2VDOTszAMNambg+4Qv8j0yiTNDYEXXXxkUNGWLHp8A3ztK4YDBbFNcWF4rgsec6/5gPyryya/+A==", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.9.tgz", + "integrity": "sha512-hylHMbK50BzJbUmQ0LPYK1+AY862Xkvje4DAaonQDfMewGIe7/+XHfG90FORsEsrfw7pskhwV4cFAYgVAPNrdw==", "optional": true, "requires": { "boolean": "^3.0.0", @@ -8255,9 +8272,9 @@ } }, "min-indent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz", - "integrity": "sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, "minimalistic-assert": { @@ -8560,9 +8577,9 @@ "dev": true }, "node-abi": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.17.0.tgz", - "integrity": "sha512-dFRAA0ACk/aBo0TIXQMEWMLUTyWYYT8OBYIzLmEUrQTElGRjxDCvyBZIsDL0QA7QCaj9PrawhOmTEdsuLY4uOQ==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz", + "integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==", "requires": { "semver": "^5.4.1" }, @@ -11635,9 +11652,9 @@ } }, "uglify-js": { - "version": "3.9.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.3.tgz", - "integrity": "sha512-r5ImcL6QyzQGVimQoov3aL2ZScywrOgBXGndbWrdehKoSvGe/RmiE5Jpw/v+GvxODt6l2tpBXwA7n+qZVlHBMA==", + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", + "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", "dev": true, "optional": true, "requires": { diff --git a/gui/src/rust/ensogl/src/animation/physics/inertia.rs b/gui/src/rust/ensogl/src/animation/physics/inertia.rs index 3dd9531525..93e6da35cd 100644 --- a/gui/src/rust/ensogl/src/animation/physics/inertia.rs +++ b/gui/src/rust/ensogl/src/animation/physics/inertia.rs @@ -8,14 +8,15 @@ use crate::animation; -// ================ -// === Position === -// ================ +// ============= +// === Value === +// ============= -/// The type of the position of the simulation. In particular, the Position could be `f32` -/// (1-dimensional simulation), or `Vector` (3-dimensional simulation). -pub trait Position - = 'static + Copy + Default + Debug + Magnitude + Normalize +/// The type of the value of the simulation. In particular, the Value could be `f32` +/// (1-dimensional simulation), or `Vector3` (3-dimensional simulation). +pub trait Value + = 'static + Copy + Default + Debug + Normalize + + Magnitude + Neg< Output=Self> + Sub + Add @@ -93,17 +94,17 @@ impl Thresholds { /// A fixed step physics simulator used to simulate `PhysicsState`. #[derive(Clone,Copy,Debug,Default)] pub struct SimulationData { - position : T, - target_position : T, - velocity : T, - mass : Mass, - spring : Spring, - drag : Drag, - thresholds : Thresholds, - active : bool, + value : T, + target_value : T, + velocity : T, + mass : Mass, + spring : Spring, + drag : Drag, + thresholds : Thresholds, + active : bool, } -impl SimulationData { +impl SimulationData { /// Constructor. pub fn new() -> Self { default() @@ -113,30 +114,30 @@ impl SimulationData { fn step(&mut self, delta_seconds:f32) { if self.active { let velocity = self.velocity.magnitude(); - let distance = (self.position - self.target_position).magnitude(); + let distance = (self.value - self.target_value).magnitude(); let snap_velocity = velocity < self.thresholds.speed; let snap_distance = distance < self.thresholds.distance; let should_snap = snap_velocity && snap_distance; if should_snap { - self.position = self.target_position; + self.value = self.target_value; self.velocity = default(); self.active = false; } else { let force = self.spring_force() + self.drag_force(); let acceleration = force / self.mass.value; self.velocity = self.velocity + acceleration * delta_seconds; - self.position = self.position + self.velocity * delta_seconds; + self.value = self.value + self.velocity * delta_seconds; } } } /// Compute spring force. fn spring_force(&self) -> T { - let position_delta = self.target_position - self.position; - let distance = position_delta.magnitude(); + let value_delta = self.target_value - self.value; + let distance = value_delta.magnitude(); if distance > 0.0 { let coefficient = distance * self.spring.value; - position_delta.normalize() * coefficient + value_delta.normalize() * coefficient } else { default() } @@ -152,44 +153,44 @@ impl SimulationData { // === Getters === #[allow(missing_docs)] -impl SimulationData { - pub fn position (&self) -> T { self.position } - pub fn target_position (&self) -> T { self.target_position } - pub fn velocity (&self) -> T { self.velocity } - pub fn mass (&self) -> Mass { self.mass } - pub fn spring (&self) -> Spring { self.spring } - pub fn drag (&self) -> Drag { self.drag } - pub fn thresholds (&self) -> Thresholds { self.thresholds } - pub fn active (&self) -> bool { self.active } +impl SimulationData { + pub fn value (&self) -> T { self.value } + pub fn target_value (&self) -> T { self.target_value } + pub fn velocity (&self) -> T { self.velocity } + pub fn mass (&self) -> Mass { self.mass } + pub fn spring (&self) -> Spring { self.spring } + pub fn drag (&self) -> Drag { self.drag } + pub fn thresholds (&self) -> Thresholds { self.thresholds } + pub fn active (&self) -> bool { self.active } } // === Setters === #[allow(missing_docs)] -impl SimulationData { +impl SimulationData { pub fn set_velocity (&mut self, velocity:T) { self.velocity = velocity; } pub fn set_mass (&mut self, mass:Mass) { self.mass = mass; } pub fn set_spring (&mut self, spring:Spring) { self.spring = spring; } pub fn set_drag (&mut self, drag:Drag) { self.drag = drag; } pub fn set_thresholds (&mut self, thresholds:Thresholds) { self.thresholds = thresholds; } - pub fn set_position(&mut self, position:T) { + pub fn set_value(&mut self, value:T) { self.active = true; - self.position = position; + self.value = value; } - pub fn set_target_position(&mut self, target_position:T) { + pub fn set_target_value(&mut self, target_value:T) { self.active = true; - self.target_position = target_position; + self.target_value = target_value; } - pub fn update_positionT>(&mut self, f:F) { - self.set_position(f(self.position())); + pub fn update_valueT>(&mut self, f:F) { + self.set_value(f(self.value())); } - pub fn update_target_positionT>(&mut self, f:F) { - self.set_target_position(f(self.target_position())); + pub fn update_target_valueT>(&mut self, f:F) { + self.set_target_value(f(self.target_value())); } pub fn update_velocityT>(&mut self, f:F) { @@ -211,6 +212,12 @@ impl SimulationData { pub fn update_thresholdsThresholds>(&mut self, f:F) { self.set_thresholds(f(self.thresholds())); } + + pub fn skip(&mut self) { + self.active = false; + self.value = self.target_value; + self.velocity = default(); + } } @@ -226,7 +233,7 @@ pub struct Simulation { data : Rc>> } -impl Simulation { +impl Simulation { /// Constructor. pub fn new() -> Self { default() @@ -244,17 +251,17 @@ impl Simulation { // === Getters === #[allow(missing_docs)] -impl Simulation { +impl Simulation { pub fn active(&self) -> bool { self.data.get().active() } - pub fn position(&self) -> T { - self.data.get().position() + pub fn value(&self) -> T { + self.data.get().value() } - pub fn target_position(&self) -> T { - self.data.get().target_position() + pub fn target_value(&self) -> T { + self.data.get().target_value() } } @@ -262,7 +269,7 @@ impl Simulation { // === Setters === #[allow(missing_docs)] -impl Simulation { +impl Simulation { pub fn set_mass(&self, mass:Mass) { self.data.update(|mut sim| {sim.set_mass(mass); sim}); } @@ -279,16 +286,20 @@ impl Simulation { self.data.update(|mut sim| {sim.set_velocity(velocity); sim}); } - pub fn set_position(&self, position:T) { - self.data.update(|mut sim| {sim.set_position(position); sim}); + pub fn set_value(&self, value:T) { + self.data.update(|mut sim| {sim.set_value(value); sim}); } - pub fn set_target_position(&self, target_position:T) { - self.data.update(|mut sim| {sim.set_target_position(target_position); sim}); + pub fn set_target_value(&self, target_value:T) { + self.data.update(|mut sim| {sim.set_target_value(target_value); sim}); } - pub fn update_target_positionT>(&self, f:F) { - self.data.update(|mut sim| {sim.update_target_position(f); sim}); + pub fn update_target_valueT>(&self, f:F) { + self.data.update(|mut sim| {sim.update_target_value(f); sim}); + } + + pub fn skip(&self) { + self.data.update(|mut sim| {sim.skip(); sim}); } } @@ -310,7 +321,7 @@ pub type DynSimulator = Simulator>; #[derive(CloneRef,Derivative,Shrinkwrap)] #[derivative(Clone(bound=""))] #[derivative(Debug(bound=""))] -pub struct Simulator { +pub struct Simulator { #[shrinkwrap(main_field)] simulation : Simulation, animation_loop : Rc>>>, @@ -319,7 +330,7 @@ pub struct Simulator { callback : Rc, } -impl Simulator +impl Simulator where Cb : Callback { /// Constructor. pub fn new(callback:Cb) -> Self { @@ -334,7 +345,7 @@ where Cb : Callback { // === Setters === #[allow(missing_docs)] -impl Simulator +impl Simulator where Cb : Callback { pub fn set_callback(&mut self, callback:Cb) { let callback = Rc::new(callback); @@ -343,26 +354,32 @@ where Cb : Callback { self.start(); } - pub fn set_position(&self, position:T) { - self.simulation.set_position(position); + pub fn set_value(&self, value:T) { + self.simulation.set_value(value); self.start(); } - pub fn set_target_position(&self, target_position:T) { - self.simulation.set_target_position(target_position); + pub fn set_target_value(&self, target_value:T) { + self.simulation.set_target_value(target_value); self.start(); } - pub fn update_target_positionT>(&self, f:F) { - self.simulation.update_target_position(f); + pub fn update_target_valueT>(&self, f:F) { + self.simulation.update_target_value(f); self.start(); } + + pub fn skip(&self) { + self.simulation.skip(); + self.stop(); + (self.callback)(self.simulation.value()); + } } // === Private API === -impl Simulator +impl Simulator where Cb : Callback { fn init(self) -> Self { self.start(); @@ -388,14 +405,14 @@ where Cb : Callback { /// Alias for `FixedFrameRateLoop` with specified step callback. pub type FixedFrameRateAnimationStep = animation::FixedFrameRateLoop>; pub type Step = impl Fn(animation::TimeInfo); -fn step(simulator:&Simulator) -> Step +fn step(simulator:&Simulator) -> Step where Cb : Callback { let this = simulator.clone_ref(); move |time:animation::TimeInfo| { let delta_seconds = time.frame / 1000.0; if this.simulation.active() { this.simulation.step(delta_seconds); - (this.callback)(this.simulation.position()); + (this.callback)(this.simulation.value()); } else { this.stop(); } diff --git a/gui/src/rust/ensogl/src/data/color/data.rs b/gui/src/rust/ensogl/src/data/color/data.rs index 8fd5578cba..3d00366951 100644 --- a/gui/src/rust/ensogl/src/data/color/data.rs +++ b/gui/src/rust/ensogl/src/data/color/data.rs @@ -27,7 +27,7 @@ use nalgebra::Vector4; /// just want it, for example to match the behavior of color mixing in web browsers, which is /// broken for many years already: /// https://stackoverflow.com/questions/60179850/webgl-2-0-canvas-blending-with-html-in-linear-color-space -#[derive(Clone,Copy,Debug,PartialEq)] +#[derive(Clone,Copy,Debug,Default,PartialEq)] pub struct Color { /// The underlying color representation. It is either `Alpha` or a color space instance. pub data : D @@ -225,3 +225,11 @@ impl From for Alpha { Self {alpha,color} } } + +impl Default for Alpha { + fn default() -> Self { + let alpha = 1.0; + let color = default(); + Self {alpha,color} + } +} diff --git a/gui/src/rust/ensogl/src/data/color/space/def.rs b/gui/src/rust/ensogl/src/data/color/space/def.rs index d0add7cb21..b6c7a4739b 100644 --- a/gui/src/rust/ensogl/src/data/color/space/def.rs +++ b/gui/src/rust/ensogl/src/data/color/space/def.rs @@ -18,7 +18,7 @@ macro_rules! define_color_space { pub type $a_name = Color>; $(#[$($meta)*])* - #[derive(Clone,Copy,Debug,PartialEq)] + #[derive(Clone,Copy,Debug,Default,PartialEq)] #[allow(missing_docs)] pub struct $data_name { $(pub $comp : f32),* @@ -26,14 +26,15 @@ macro_rules! define_color_space { impl $data_name { /// Constructor. - pub fn new($($comp:f32),*) -> Self { + pub fn new($($comp:impl Into),*) -> Self { + $(let $comp = $comp.into();)* Self {$($comp),*} } } impl $name { /// Constructor. - pub fn new($($comp:f32),*) -> Self { + pub fn new($($comp:impl Into),*) -> Self { let data = $data_name::new($($comp),*); Self {data} } @@ -41,7 +42,8 @@ macro_rules! define_color_space { impl $a_name { /// Constructor. - pub fn new($($comp:f32),*,alpha:f32) -> Self { + pub fn new($($comp:impl Into),*,alpha:impl Into) -> Self { + let alpha = alpha.into(); let color = $data_name::new($($comp),*); let data = Alpha {alpha,color}; Self {data} diff --git a/gui/src/rust/ensogl/src/display/navigation/navigator.rs b/gui/src/rust/ensogl/src/display/navigation/navigator.rs index 4e93f0ff2d..ee7086fde4 100644 --- a/gui/src/rust/ensogl/src/display/navigation/navigator.rs +++ b/gui/src/rust/ensogl/src/display/navigation/navigator.rs @@ -23,7 +23,7 @@ use events::ZoomEvent; #[derive(Debug)] pub struct Navigator { _events : NavigatorEvents, - simulator : physics::inertia::DynSimulator, + simulator : physics::inertia::DynSimulator, resize_callback : callback::Handle } @@ -39,12 +39,12 @@ impl Navigator { Self {simulator,_events,resize_callback} } - fn create_simulator(camera:&Camera2d) -> physics::inertia::DynSimulator { + fn create_simulator(camera:&Camera2d) -> physics::inertia::DynSimulator { let camera_ref = camera.clone_ref(); - let update = Box::new(move |p:Point3| camera_ref.set_position(p.into())); + let update = Box::new(move |p:V3| camera_ref.set_position(p.into())); let simulator = physics::inertia::DynSimulator::new(update); - simulator.set_position(camera.position().into()); - simulator.set_target_position(camera.position().into()); + simulator.set_value(camera.position().into()); + simulator.set_target_value(camera.position().into()); simulator } @@ -54,7 +54,7 @@ impl Navigator { , min_zoom : f32 , max_zoom : f32 , zoom_speed : f32 - ) -> (physics::inertia::DynSimulator,callback::Handle,NavigatorEvents) { + ) -> (physics::inertia::DynSimulator,callback::Handle,NavigatorEvents) { let simulator = Self::create_simulator(&camera); let panning_callback = enclose!((dom,camera,mut simulator) move |pan: PanEvent| { let fovy_slope = camera.half_fovy_slope(); @@ -64,15 +64,15 @@ impl Navigator { let dx = pan.movement.x * movement_scale_for_distance; let dy = pan.movement.y * movement_scale_for_distance; - let diff = Point3::new(dx,dy,0.0); - simulator.update_target_position(|p| p + diff); + let diff = V3::new(dx,dy,0.0); + simulator.update_target_value(|p| p + diff); }); let resize_callback = camera.add_screen_update_callback( enclose!((mut simulator,camera) move |_:&Vector2| { let position = camera.position().into(); - simulator.set_position(position); - simulator.set_target_position(position); + simulator.set_value(position); + simulator.set_target_value(position); simulator.set_velocity(default()); }) ); @@ -87,8 +87,8 @@ impl Navigator { let x = -normalized.x * camera.screen().aspect(); let y = -normalized.y; let z = half_height / camera.half_fovy_slope(); - let direction = Point3::new(x,y,z).normalize(); - let mut position = simulator.target_position(); + let direction = V3::new(x,y,z).normalize(); + let mut position = simulator.target_value(); let min_zoom = camera.clipping().near + min_zoom; let zoom_amount = zoom.amount * position.z; let direction = direction * zoom_amount; @@ -100,7 +100,7 @@ impl Navigator { else if too_close { min_zoom_limit / direction.z } else { 1.0 }; position += direction * zoom_factor; - simulator.set_target_position(position); + simulator.set_target_value(position); }); (simulator,resize_callback, NavigatorEvents::new(&dom, panning_callback, zoom_callback, zoom_speed)) } diff --git a/gui/src/rust/ensogl/src/display/object/class.rs b/gui/src/rust/ensogl/src/display/object/class.rs index 6182684548..71b420b2fe 100644 --- a/gui/src/rust/ensogl/src/display/object/class.rs +++ b/gui/src/rust/ensogl/src/display/object/class.rs @@ -719,6 +719,13 @@ pub trait ObjectOps : Object { self.display_object().rc.set_position(t); } + fn set_position_xy(&self, t:Vector2) { + self.mod_position(|p| { + p.x = t.x; + p.y = t.y; + }) + } + fn set_scale(&self, t:Vector3) { self.display_object().rc.set_scale(t); } diff --git a/gui/src/rust/ensogl/src/display/shape/primitive/def/primitive.rs b/gui/src/rust/ensogl/src/display/shape/primitive/def/primitive.rs index f6ffda943b..7231163aa3 100644 --- a/gui/src/rust/ensogl/src/display/shape/primitive/def/primitive.rs +++ b/gui/src/rust/ensogl/src/display/shape/primitive/def/primitive.rs @@ -186,7 +186,7 @@ define_sdf_shapes! { PlaneAngle (angle:Angle) { float pi_2 = 2.0 * PI; float angle_norm = value(angle) / pi_2; - angle_norm = abs(mod(angle_norm,2.0)-1.0); + angle_norm = 1.0 - abs(mod(angle_norm,2.0)-1.0); float angle_rad = angle_norm * pi_2; float off = angle_norm - 0.5; // Fixes artifacts with 0 and 360 degrees. float distance = abs(position).x*cos(angle_rad/2.0) - position.y*sin(angle_rad/2.0) - off; @@ -263,8 +263,9 @@ define_sdf_shapes! { // === Triangle === Triangle (width:f32, height:f32) { - vec2 norm = normalize(vec2(height,width/2.0)); - float dist = max(abs(position).x*norm.x + position.y*norm.y - height*norm.y, -position.y); + vec2 norm = normalize(vec2(height,width/2.0)); + float pos_y = -position.y - height/2.0; + float dist = max(abs(position).x*norm.x + position.y*norm.y - height/2.0*norm.y, pos_y); return bound_sdf(dist,bounding_box(width,height/2.0)); } } diff --git a/gui/src/rust/ensogl/src/display/shape/primitive/def/unit.rs b/gui/src/rust/ensogl/src/display/shape/primitive/def/unit.rs index c4948734fa..00df68c13d 100644 --- a/gui/src/rust/ensogl/src/display/shape/primitive/def/unit.rs +++ b/gui/src/rust/ensogl/src/display/shape/primitive/def/unit.rs @@ -18,13 +18,23 @@ pub use crate::math::topology::unit::Degrees; // ===================== /// Provides a `px` method to every unit that can be converted to a pixel distance. +#[allow(missing_docs)] pub trait PixelDistance { + type Output; /// Distance in pixels. - fn px(&self) -> Var>; + fn px(&self) -> Self::Output; } -impl PixelDistance for T { - fn px(&self) -> Var> { +impl PixelDistance for i32 { + type Output = Var>; + fn px(&self) -> Self::Output { + unit::PixelDistance::px(self).into() + } +} + +impl PixelDistance for f32 { + type Output = Var>; + fn px(&self) -> Self::Output { unit::PixelDistance::px(self).into() } } diff --git a/gui/src/rust/ensogl/src/display/shape/primitive/def/var.rs b/gui/src/rust/ensogl/src/display/shape/primitive/def/var.rs index cdf60d0006..c777db79af 100644 --- a/gui/src/rust/ensogl/src/display/shape/primitive/def/var.rs +++ b/gui/src/rust/ensogl/src/display/shape/primitive/def/var.rs @@ -3,6 +3,7 @@ use crate::prelude::*; use crate::data::color; +use crate::display::shape::primitive::def::unit::PixelDistance; use crate::math::algebra::Acos; use crate::math::algebra::Asin; use crate::math::algebra::Cos; @@ -21,6 +22,7 @@ use nalgebra::Scalar; use std::ops::*; + // ====================== // === VarInitializer === // ====================== @@ -55,6 +57,15 @@ impl VarInitializerMarker>> for Unit where impl VarInitializerMarker>> for (S1,S2) where T:Scalar, S1:VarInitializerMarkerNested>, S2:VarInitializerMarkerNested> {} +impl VarInitializerMarker>> for Var> {} +impl VarInitializerMarker>> for Var> {} +impl VarInitializerMarker>> for Var> {} + +impl VarInitializerMarker>> for &Var> {} +impl VarInitializerMarker>> for &Var> {} +impl VarInitializerMarker>> for &Var> {} + + // === Nested === @@ -192,6 +203,81 @@ impl Dim3 for Var> { +impl HasComponents for Var> { + type Component = Var; +} + +impl HasComponents for Var> { + type Component = Var; +} + +impl Dim1 for Var> { + fn x(&self) -> Var { + match self { + Self::Static (t) => Var::Static(t.x), + Self::Dynamic (t) => Var::Dynamic(format!("{}.x",t).into()) + } + } +} + +impl Dim2 for Var> { + fn y(&self) -> Var { + match self { + Self::Static (t) => Var::Static(t.y), + Self::Dynamic (t) => Var::Dynamic(format!("{}.y",t).into()) + } + } +} + +impl Dim1 for Var> { + fn x(&self) -> Var { + match self { + Self::Static (t) => Var::Static(t.x), + Self::Dynamic (t) => Var::Dynamic(format!("{}.x",t).into()) + } + } +} + +impl Dim2 for Var> { + fn y(&self) -> Var { + match self { + Self::Static (t) => Var::Static(t.y), + Self::Dynamic (t) => Var::Dynamic(format!("{}.y",t).into()) + } + } +} + +impl Dim3 for Var> { + fn z(&self) -> Var { + match self { + Self::Static (t) => Var::Static(t.z), + Self::Dynamic (t) => Var::Dynamic(format!("{}.z",t).into()) + } + } +} + +impl PixelDistance for Var> { + type Output = Var>>; + fn px(&self) -> Self::Output { + match self { + Self::Static (t) => Var::Static(V2(Distance::new(t.x),Distance::new(t.y))), + Self::Dynamic (t) => Var::Dynamic(t.clone()) + } + } +} + +impl PixelDistance for Var> { + type Output = Var>>; + fn px(&self) -> Self::Output { + match self { + Self::Static (t) => Var::Static(V3(Distance::new(t.x),Distance::new(t.y),Distance::new(t.z))), + Self::Dynamic (t) => Var::Dynamic(t.clone()) + } + } +} + + + // ================= // === Operators === // ================= diff --git a/gui/src/rust/ensogl/src/display/shape/text/text_field/frp/mouse.rs b/gui/src/rust/ensogl/src/display/shape/text/text_field/frp/mouse.rs index ad3665ce73..ba4f74d6d0 100644 --- a/gui/src/rust/ensogl/src/display/shape/text/text_field/frp/mouse.rs +++ b/gui/src/rust/ensogl/src/display/shape/text/text_field/frp/mouse.rs @@ -45,17 +45,17 @@ impl TextFieldMouseFrp { let set_cursor_action = Self::set_cursor_lambda(text_field_ptr.clone()); let select_action = Self::select_lambda(text_field_ptr); frp::new_network! { text_field - def is_inside = mouse.position.map(is_inside); - def click_in = mouse.press.gate(&is_inside); - def click_in_bool = click_in.constant(true); - def mouse_up_bool = mouse.release.constant(false); - def selecting = click_in_bool.merge(&mouse_up_bool); - def multicursor = keyboard.keyboard.key_mask.map(is_multicursor_mode); - def block_selection = keyboard.keyboard.key_mask.map(is_block_selection); - def click_in_pos = mouse.position.sample(&click_in); - def select_pos = mouse.position.gate(&selecting); - def set_cursor_action = click_in_pos.map2(&multicursor,set_cursor_action); - def select_action = select_pos.map2(&block_selection,select_action); + is_inside <- mouse.position.map(is_inside); + click_in <- mouse.press.gate(&is_inside); + click_in_bool <- click_in.constant(true); + mouse_up_bool <- mouse.release.constant(false); + selecting <- any (click_in_bool,mouse_up_bool); + multicursor <- keyboard.keyboard.key_mask.map(is_multicursor_mode); + block_selection <- keyboard.keyboard.key_mask.map(is_block_selection); + click_in_pos <- mouse.position.sample(&click_in); + select_pos <- mouse.position.gate(&selecting); + set_cursor_action <- click_in_pos.map2(&multicursor,set_cursor_action); + select_action <- select_pos.map2(&block_selection,select_action); } let network = text_field; Self {mouse,network,click_in,selecting,multicursor,set_cursor_action,select_action} diff --git a/gui/src/rust/ensogl/src/display/style/sheet.rs b/gui/src/rust/ensogl/src/display/style/sheet.rs index 6439356c12..97b9f8ec3a 100644 --- a/gui/src/rust/ensogl/src/display/style/sheet.rs +++ b/gui/src/rust/ensogl/src/display/style/sheet.rs @@ -208,12 +208,14 @@ impl From for Value } } -impl Semigroup for Value { +impl PartialSemigroup<&Value> for Value { fn concat_mut(&mut self, other:&Self) { *self = other.clone() } +} - fn concat_mut_take(&mut self, other:Self) { +impl PartialSemigroup for Value { + fn concat_mut(&mut self, other:Self) { *self = other } } diff --git a/gui/src/rust/ensogl/src/display/style/theme.rs b/gui/src/rust/ensogl/src/display/style/theme.rs index ddeb8836ab..4a1472e534 100644 --- a/gui/src/rust/ensogl/src/display/style/theme.rs +++ b/gui/src/rust/ensogl/src/display/style/theme.rs @@ -39,7 +39,7 @@ impl Theme { } } -impl Semigroup for Theme { +impl PartialSemigroup<&Theme> for Theme { fn concat_mut(&mut self, other:&Self) { self.tree.concat_mut(&other.tree); } diff --git a/gui/src/rust/ensogl/src/gui/component.rs b/gui/src/rust/ensogl/src/gui/component.rs index 4ffb412ebf..8c11e3b40c 100644 --- a/gui/src/rust/ensogl/src/gui/component.rs +++ b/gui/src/rust/ensogl/src/gui/component.rs @@ -6,6 +6,7 @@ use crate::prelude::*; +use crate::animation::physics::inertia; use crate::animation::physics::inertia::DynSimulator; use crate::display::object::traits::*; use crate::display::scene::MouseTarget; @@ -42,7 +43,7 @@ impl ShapeViewEvents { mouse_over <- source_(); mouse_out <- source_(); - is_mouse_over <- [mouse_over,mouse_out].toggle(); + is_mouse_over <- any (mouse_over,mouse_out).toggle(); out_on_drop <- on_drop.gate(&is_mouse_over); eval_ out_on_drop (mouse_out.emit(())); } @@ -210,3 +211,13 @@ pub fn animation2(network:&frp::Network) -> (DynSimulator, frp::Stream let source = DynSimulator::::new(Box::new(f!((t) target.emit(t)))); (source,target.into()) } + + +/// Define a new animation FRP network. +pub fn animator(network:&frp::Network) -> (DynSimulator, frp::Stream) { + frp::extend! { network + def target = source::(); + } + let source = DynSimulator::::new(Box::new(f!((t) target.emit(t)))); + (source,target.into()) +} diff --git a/gui/src/rust/ensogl/src/math.rs b/gui/src/rust/ensogl/src/math.rs index 2a218ec945..4d03c752e4 100644 --- a/gui/src/rust/ensogl/src/math.rs +++ b/gui/src/rust/ensogl/src/math.rs @@ -36,7 +36,12 @@ pub mod types { pub use super::algebra::Matrix4x2; pub use super::algebra::Matrix4x3; + pub use super::algebra::V2; + pub use super::algebra::V3; + pub use super::algebra::V4; + pub use super::algebra::Zero; + pub use super::algebra::zero; pub use super::algebra::HasComponents; pub use super::algebra::Dim1; pub use super::algebra::Dim2; @@ -44,6 +49,4 @@ pub mod types { pub use super::algebra::Abs; pub use super::algebra::Magnitude; pub use super::algebra::Normalize; - pub use super::algebra::Point3; - } diff --git a/gui/src/rust/ensogl/src/math/algebra.rs b/gui/src/rust/ensogl/src/math/algebra.rs index 7e793bc15f..090c87b734 100644 --- a/gui/src/rust/ensogl/src/math/algebra.rs +++ b/gui/src/rust/ensogl/src/math/algebra.rs @@ -18,6 +18,13 @@ pub use nalgebra::Matrix4x2; pub use nalgebra::Matrix4x3; use nalgebra; +use nalgebra::Scalar; +use nalgebra::Matrix; +use nalgebra::ComplexField; +use nalgebra::Dim; +use nalgebra::storage::Storage; + +use std::ops::AddAssign; @@ -31,6 +38,11 @@ pub trait Zero { fn zero() -> Self; } +/// Smart constructor for the `Zero` trait. +pub fn zero() -> T { + ::zero() +} + // === Impls === @@ -46,7 +58,7 @@ macro_rules! gen_zero { macro_rules! gen_zero_nalgebra { ([$($ty:ident),*]) => {$( - impl Zero for $ty { + impl Zero for $ty { fn zero() -> Self { nalgebra::zero() } @@ -155,18 +167,28 @@ impl Pow for f32 { /// Types which have magnitude value. #[allow(missing_docs)] pub trait Magnitude { - fn magnitude(&self) -> f32; + type Output; + fn magnitude(&self) -> Self::Output; } // === Impls === impl Magnitude for f32 { - fn magnitude(&self) -> f32 { + type Output = f32; + fn magnitude(&self) -> Self::Output { self.abs() } } +impl> Magnitude for Matrix { + type Output = N::RealField; + fn magnitude(&self) -> Self::Output { + self.norm() + } +} + + // ============== // === Signum === @@ -275,6 +297,7 @@ impl Normalize for f32 { } + // =================== // === Square Root === // =================== @@ -394,61 +417,194 @@ impl Acos for f32 { -// ============= -// === Point === -// ============= -/// A coordinate in space. -#[derive(Clone,Copy,Debug,Neg,Sub,Add,Div,AddAssign,From,Shrinkwrap)] -#[shrinkwrap(mutable)] -pub struct Point3 { - /// Underlying representation - pub matrix : Vector3 +macro_rules! define_vector { + ($name:ident {$($field:ident),*}) => { + /// A coordinate in space. + #[derive(Clone,Copy,Debug,Default)] + #[repr(C)] + pub struct $name { + $( + /// Vector component. + pub $field : T + ),* + } + + /// Smart constructor. + #[allow(non_snake_case)] + pub fn $name($($field:T),*) -> $name { + $name {$($field),*} + } + + impl $name { + /// Constructor. + pub fn new($($field:T),*) -> Self { + Self {$($field),*} + } + + /// Converts the struct to slice. + /// + /// # Safety + /// The code is safe as the struct is implemented as `repr(C)`. + #[allow(unsafe_code)] + #[allow(trivial_casts)] + pub fn as_slice(&self) -> &[T] { + // Safe, because $name is defined as `#[repr(C)]`. + let ptr = self as *const $name as *const T; + unsafe { + std::slice::from_raw_parts(ptr, std::mem::size_of::()) + } + } + } + + impl Magnitude for $name { + type Output = f32; + fn magnitude(&self) -> Self::Output { + $(let $field = self.$field * self.$field;)* + let sum = 0.0 $(+$field)*; + sum.sqrt() + } + } + + impl Normalize for $name { + fn normalize(&self) -> Self { + let magnitude = self.magnitude(); + $(let $field = self.$field / magnitude;)* + Self {$($field),*} + } + } + + impl AddAssign for $name { + fn add_assign(&mut self, rhs:f32) { + $(self.$field += rhs;)* + } + } + + impl AddAssign<$name> for $name + where T:AddAssign { + fn add_assign(&mut self, rhs:$name) { + $(self.$field += rhs.$field;)* + } + } + + impl Add<$name> for $name + where T:Add { + type Output = $name<>::Output>; + fn add(self,rhs:$name) -> Self::Output { + $(let $field = self.$field.add(rhs.$field);)* + $name {$($field),*} + } + } + + impl Sub<$name> for $name + where T:Sub { + type Output = $name<>::Output>; + fn sub(self,rhs:$name) -> Self::Output { + $(let $field = self.$field.sub(rhs.$field);)* + $name {$($field),*} + } + } + + impl Neg for $name + where T:Neg { + type Output = $name<::Output>; + fn neg(self) -> Self::Output { + $(let $field = self.$field.neg();)* + $name {$($field),*} + } + } + + impl Mul for $name { + type Output = $name; + fn mul(self, rhs:f32) -> Self::Output { + $(let $field = self.$field.mul(rhs);)* + Self {$($field),*} + } + } + + impl Div for $name { + type Output = $name; + fn div(self, rhs:f32) -> Self::Output { + $(let $field = self.$field.div(rhs);)* + Self {$($field),*} + } + } + + impl Mul<$name> for f32 { + type Output = $name; + fn mul(self, rhs:$name) -> Self::Output { + $(let $field = self.mul(rhs.$field);)* + $name {$($field),*} + } + } + }; } -impl Point3 { - /// Constructor. - pub fn new(x:f32, y:f32, z:f32) -> Self { - let matrix = Vector3::new(x,y,z); - Self {matrix} +define_vector! {V2 {x,y}} +define_vector! {V3 {x,y,z}} +define_vector! {V4 {x,y,z,w}} + +impl From> for V2 { + fn from(t:Vector2) -> Self { + V2(t.x,t.y) } } -impl Default for Point3 { - fn default() -> Self { - let matrix = nalgebra::zero(); - Self {matrix} +impl Into> for V2 { + fn into(self) -> Vector2 { + Vector2::new(self.x,self.y) } } -impl Magnitude for Point3 { - fn magnitude(&self) -> f32 { - self.matrix.magnitude() +impl Into> for &V2 { + fn into(self) -> Vector2 { + Vector2::new(self.x,self.y) } } -impl Normalize for Point3 { - fn normalize(&self) -> Self { - Self {matrix:self.matrix.normalize()} + + +impl From> for V3 { + fn from(t:Vector3) -> Self { + V3(t.x,t.y,t.z) } } -impl Mul for Point3 { - type Output = Point3; - fn mul(self, rhs:f32) -> Self::Output { - let matrix = self.matrix * rhs; - Self {matrix} +impl Into> for V3 { + fn into(self) -> Vector3 { + Vector3::new(self.x,self.y,self.z) } } -impl Into> for Point3 { - fn into(self) -> Vector3 { - self.matrix +impl Into> for &V3 { + fn into(self) -> Vector3 { + Vector3::new(self.x,self.y,self.z) } } +impl From> for V4 { + fn from(t:Vector4) -> Self { + V4(t.x,t.y,t.z,t.w) + } +} + +impl Into> for V4 { + fn into(self) -> Vector4 { + Vector4::new(self.x,self.y,self.z,self.w) + } +} + +impl Into> for &V4 { + fn into(self) -> Vector4 { + Vector4::new(self.x,self.y,self.z,self.w) + } +} + + + + // ============================ // === Algebraic Structures === // ============================ diff --git a/gui/src/rust/ensogl/src/math/topology/unit.rs b/gui/src/rust/ensogl/src/math/topology/unit.rs index bcf1a952bf..6d142a7ab2 100644 --- a/gui/src/rust/ensogl/src/math/topology/unit.rs +++ b/gui/src/rust/ensogl/src/math/topology/unit.rs @@ -183,23 +183,34 @@ pub type Distance = Unit; pub struct Pixels; /// Provides a `px` method to every unit that can be converted to a pixel distance. +#[allow(missing_docs)] pub trait PixelDistance { + type Output; /// Distance in pixels. - fn px(&self) -> Distance; + fn px(&self) -> Self::Output; } impl PixelDistance for f32 { - fn px(&self) -> Distance { + type Output = Distance; + fn px(&self) -> Self::Output { Distance::new(*self) } } impl PixelDistance for i32 { - fn px(&self) -> Distance { + type Output = Distance; + fn px(&self) -> Self::Output { Distance::new(*self as f32) } } +impl PixelDistance for V2 { + type Output = V2>; + fn px(&self) -> Self::Output { + V2(Distance::new(self.x),Distance::new(self.y)) + } +} + impls! { From + &From > for Glsl { |t| { t.value.into() } }} impls! { From>> for glsl::PrimType { diff --git a/gui/src/rust/ensogl/src/system/gpu/data/buffer/item.rs b/gui/src/rust/ensogl/src/system/gpu/data/buffer/item.rs index de19a6bbe7..e222701f26 100644 --- a/gui/src/rust/ensogl/src/system/gpu/data/buffer/item.rs +++ b/gui/src/rust/ensogl/src/system/gpu/data/buffer/item.rs @@ -180,6 +180,110 @@ impl Storable for f32 { fn slice_to_items_mut (buffer: &mut [Self]) -> &mut [Self::Cell] { buffer } } +impl> Storable for V2 +where Self:GpuDefault + GpuKnownSize + PhantomInto, T:ItemBounds { + type Cell = T; + type Rows = U2; + type Cols = U1; + + #[allow(unsafe_code)] + fn slice_from_items(buffer: &[Self::Cell]) -> &[Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_from_items_mut(buffer: &mut [Self::Cell]) -> &mut [Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items(buffer: &[Self]) -> &[Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items_mut(buffer: &mut [Self]) -> &mut [Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } +} + +impl> Storable for V3 +where Self:GpuDefault + GpuKnownSize + PhantomInto, T:ItemBounds { + type Cell = T; + type Rows = U2; + type Cols = U1; + + #[allow(unsafe_code)] + fn slice_from_items(buffer: &[Self::Cell]) -> &[Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_from_items_mut(buffer: &mut [Self::Cell]) -> &mut [Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items(buffer: &[Self]) -> &[Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items_mut(buffer: &mut [Self]) -> &mut [Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } +} + +impl> Storable for V4 +where Self:GpuDefault + GpuKnownSize + PhantomInto, T:ItemBounds { + type Cell = T; + type Rows = U2; + type Cols = U1; + + #[allow(unsafe_code)] + fn slice_from_items(buffer: &[Self::Cell]) -> &[Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_from_items_mut(buffer: &mut [Self::Cell]) -> &mut [Self] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() / Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items(buffer: &[Self]) -> &[Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts(buffer.as_ptr().cast(), len) } + } + + #[allow(unsafe_code)] + fn slice_to_items_mut(buffer: &mut [Self]) -> &mut [Self::Cell] { + // This code casts slice to vector. It is safe because vector was defined as `#[repr(C)]`. + let len = buffer.len() * Self::item_count(); + unsafe { std::slice::from_raw_parts_mut(buffer.as_mut_ptr().cast(), len) } + } +} impl,R,C> Storable for MatrixMN where T:ItemBounds, Self:MatrixCtx, @@ -292,6 +396,36 @@ impl JsBufferView for [u8] { } } +#[allow(unsafe_code)] +impl JsBufferView for [V2] +where T : Storable + ItemBounds, + V2 : Storable, + [Cell>] : JsBufferView { + unsafe fn js_buffer_view(&self) -> js_sys::Object { + as Storable>::slice_to_items(self).js_buffer_view() + } +} + +#[allow(unsafe_code)] +impl JsBufferView for [V3] +where T : Storable + ItemBounds, + V3 : Storable, + [Cell>] : JsBufferView { + unsafe fn js_buffer_view(&self) -> js_sys::Object { + as Storable>::slice_to_items(self).js_buffer_view() + } +} + +#[allow(unsafe_code)] +impl JsBufferView for [V4] +where T : Storable + ItemBounds, + V4 : Storable, + [Cell>] : JsBufferView { + unsafe fn js_buffer_view(&self) -> js_sys::Object { + as Storable>::slice_to_items(self).js_buffer_view() + } +} + #[allow(unsafe_code)] impl,R,C> JsBufferView for [MatrixMN] where Self : MatrixCtx, diff --git a/gui/src/rust/ensogl/src/system/gpu/data/default.rs b/gui/src/rust/ensogl/src/system/gpu/data/default.rs index 8e0d18f7b7..8ce50cf01f 100644 --- a/gui/src/rust/ensogl/src/system/gpu/data/default.rs +++ b/gui/src/rust/ensogl/src/system/gpu/data/default.rs @@ -1,6 +1,7 @@ //! Defines abstraction for data types that have a default value when used as GPU values. use nalgebra::*; +use crate::math::types::*; @@ -39,6 +40,10 @@ define_gpu_defaults! { f32 = 0.0, bool = false, + V2 = V2::new(0.0,0.0), + V3 = V3::new(0.0,0.0,0.0), + V4 = V4::new(0.0,0.0,0.0,0.0), + Vector2 = Vector2::new(0.0,0.0), Vector3 = Vector3::new(0.0,0.0,0.0), Vector4 = Vector4::new(0.0,0.0,0.0,1.0), diff --git a/gui/src/rust/ensogl/src/system/gpu/data/prim.rs b/gui/src/rust/ensogl/src/system/gpu/data/prim.rs index 6ef359c61a..7a38c583c7 100644 --- a/gui/src/rust/ensogl/src/system/gpu/data/prim.rs +++ b/gui/src/rust/ensogl/src/system/gpu/data/prim.rs @@ -68,6 +68,7 @@ macro_rules! with_all_prim_types { [Matrix2x3 f32] [Matrix2x4 f32] [Matrix3x2 f32] [Matrix3x4 f32] [Matrix4x2 f32] [Matrix4x3 f32] + [V2 f32] [V3 f32] [V4 f32] ] } } diff --git a/gui/src/rust/ensogl/src/system/gpu/data/sized.rs b/gui/src/rust/ensogl/src/system/gpu/data/sized.rs index 229b62f397..ce7053256c 100644 --- a/gui/src/rust/ensogl/src/system/gpu/data/sized.rs +++ b/gui/src/rust/ensogl/src/system/gpu/data/sized.rs @@ -1,6 +1,7 @@ //! This module implements type-level utils for checking the size of values for a given type. use nalgebra::*; +use crate::math::types::*; use crate::system::gpu::data::buffer::item::MatrixCtx; @@ -37,6 +38,21 @@ impl GpuKnownSize for i32 { type GpuByteSize = U4; } impl GpuKnownSize for u32 { type GpuByteSize = U4; } impl GpuKnownSize for f32 { type GpuByteSize = U4; } +impl GpuKnownSize for V2 +where T:GpuKnownSize, U2:DimMul>, Mul>:DimName { + type GpuByteSize = Mul>; +} + +impl GpuKnownSize for V3 +where T:GpuKnownSize, U3:DimMul>, Mul>:DimName { + type GpuByteSize = Mul>; +} + +impl GpuKnownSize for V4 +where T:GpuKnownSize, U4:DimMul>, Mul>:DimName { + type GpuByteSize = Mul>; +} + type Mul = >::Output; impl GpuKnownSize for MatrixMN where Self:MatrixCtx, diff --git a/gui/src/rust/ensogl/src/system/gpu/data/uniform/upload.rs b/gui/src/rust/ensogl/src/system/gpu/data/uniform/upload.rs index 91589844fc..fc582e0a10 100644 --- a/gui/src/rust/ensogl/src/system/gpu/data/uniform/upload.rs +++ b/gui/src/rust/ensogl/src/system/gpu/data/uniform/upload.rs @@ -6,6 +6,7 @@ use web_sys::WebGlUniformLocation; use crate::system::gpu::Context; use crate::system::gpu::data::prim::*; +use crate::math::types::*; @@ -43,6 +44,9 @@ impl UniformUpload for f32 { } } + +// === Vector === + impl UniformUpload for Vector2 { fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { context.uniform2fv_with_f32_array(Some(location),self.data.as_slice()); @@ -118,6 +122,87 @@ impl UniformUpload for Vector4 { } } + +// === V === + +impl UniformUpload for V2 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform2fv_with_f32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V3 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform3fv_with_f32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V4 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform4fv_with_f32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V2 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform2iv_with_i32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V3 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform3iv_with_i32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V4 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform4iv_with_i32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V2 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform2uiv_with_u32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V3 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform3uiv_with_u32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V4 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + context.uniform4uiv_with_u32_array(Some(location),self.as_slice()); + } +} + +impl UniformUpload for V2 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + let v:Vec = self.as_slice().iter().cloned().map(|t| if t {1} else {0}).collect(); + context.uniform2iv_with_i32_array(Some(location),&v); + } +} + +impl UniformUpload for V3 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + let v:Vec = self.as_slice().iter().cloned().map(|t| if t {1} else {0}).collect(); + context.uniform3iv_with_i32_array(Some(location),&v); + } +} + +impl UniformUpload for V4 { + fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { + let v:Vec = self.as_slice().iter().cloned().map(|t| if t {1} else {0}).collect(); + context.uniform4iv_with_i32_array(Some(location),&v); + } +} + + +// === Matrix === + impl UniformUpload for Matrix2 { fn upload_uniform(&self, context:&Context, location:&WebGlUniformLocation) { context.uniform_matrix2fv_with_f32_array(Some(location),false,self.data.as_slice()); diff --git a/gui/src/rust/ensogl/src/system/gpu/shader/glsl.rs b/gui/src/rust/ensogl/src/system/gpu/shader/glsl.rs index 6f91d72e71..e8cb1df095 100644 --- a/gui/src/rust/ensogl/src/system/gpu/shader/glsl.rs +++ b/gui/src/rust/ensogl/src/system/gpu/shader/glsl.rs @@ -105,6 +105,51 @@ where [ T1:Into, T2:Into, T3:Into, T4:Into ] { |t| { }}} +// === From Vectors to Glsl === + +impls! {[T:Into] From > for Glsl { |t| { + let x = t.x.into(); + let y = t.y.into(); + iformat!("vec2({x},{y})").into() +}}} + +impls! {[T:Into] From > for Glsl { |t| { + let x = t.x.into(); + let y = t.y.into(); + let z = t.z.into(); + iformat!("vec2({x},{y},{z})").into() +}}} + +impls! {[T:Into] From > for Glsl { |t| { + let x = t.x.into(); + let y = t.y.into(); + let z = t.z.into(); + let w = t.w.into(); + iformat!("vec2({x},{y},{z},{w})").into() +}}} + +impls! {[T:RefInto] From <&V2> for Glsl { |t| { + let x = t.x.glsl(); + let y = t.y.glsl(); + iformat!("vec2({x},{y})").into() +}}} + +impls! {[T:RefInto] From <&V3> for Glsl { |t| { + let x = t.x.glsl(); + let y = t.y.glsl(); + let z = t.z.glsl(); + iformat!("vec2({x},{y},{z})").into() +}}} + +impls! {[T:RefInto] From <&V4> for Glsl { |t| { + let x = t.x.glsl(); + let y = t.y.glsl(); + let z = t.z.glsl(); + let w = t.w.glsl(); + iformat!("vec2({x},{y},{z},{w})").into() +}}} + + // === From Prim Types to Glsl === impls! { From + &From for Glsl { |t| t.to_string().into() } } @@ -857,6 +902,10 @@ define_glsl_prim_type_conversions! { u32 => UInt, f32 => Float, + V2 => Vec2, + V3 => Vec3, + V4 => Vec4, + Vector2 => Vec2, Vector3 => Vec3, Vector4 => Vec4, diff --git a/gui/src/rust/ide/src/view/node_editor.rs b/gui/src/rust/ide/src/view/node_editor.rs index 1002d8817e..8752c46c71 100644 --- a/gui/src/rust/ide/src/view/node_editor.rs +++ b/gui/src/rust/ide/src/view/node_editor.rs @@ -74,13 +74,13 @@ impl FencedAction { /// Wrap the `action` in `FencedAction`. fn fence(network:&frp::Network, action:impl Fn(&Parameter) + 'static) -> Self { frp::extend! { network - def trigger = source::(); - def triggered = trigger.constant(()); - def switch = gather(); - switch.attach(&triggered); - def performed = trigger.map(move |param| action(param)); - switch.attach(&performed); - def is_running = switch.toggle(); + trigger <- source::(); + triggered <- trigger.constant(()); + switch <- any(...); + switch <+ triggered; + performed <- trigger.map(move |param| action(param)); + switch <+ performed; + is_running <- switch.toggle(); } Self {trigger,is_running} } @@ -158,7 +158,7 @@ impl GraphEditorIntegratedWithController { // Changes in Graph Editor let is_handling_notification = handle_notification.is_running; - def is_hold = is_handling_notification.zip_with(&invalidate.is_running, |l,r| *l || *r); + def is_hold = is_handling_notification.all_with(&invalidate.is_running, |l,r| *l || *r); def _action = editor_outs.node_removed .map2(&is_hold,node_removed); def _action = editor_outs.connection_added .map2(&is_hold,connection_created); def _action = editor_outs.connection_removed.map2(&is_hold,connection_removed); diff --git a/gui/src/rust/lib/data/src/hash_map_tree.rs b/gui/src/rust/lib/data/src/hash_map_tree.rs index 0af67c6019..4bcb1fab7b 100644 --- a/gui/src/rust/lib/data/src/hash_map_tree.rs +++ b/gui/src/rust/lib/data/src/hash_map_tree.rs @@ -246,13 +246,23 @@ where K:Eq+Hash { // === Impls === -impl Semigroup for HashMapTree +impl PartialSemigroup> for HashMapTree + where K : Eq + Hash + Clone, + V : Semigroup, + S : BuildHasher + Clone { + fn concat_mut(&mut self, other:Self) { + self.value.concat_mut(&other.value); + PartialSemigroup::concat_mut(&mut self.branches, other.branches); + } +} + +impl PartialSemigroup<&HashMapTree> for HashMapTree where K : Eq + Hash + Clone, V : Semigroup, S : BuildHasher + Clone { fn concat_mut(&mut self, other:&Self) { self.value.concat_mut(&other.value); - self.branches.concat_mut(&other.branches); + PartialSemigroup::concat_mut(&mut self.branches, &other.branches); } } diff --git a/gui/src/rust/lib/debug-scenes/src/shapes.rs b/gui/src/rust/lib/debug-scenes/src/shapes.rs index 80f8de6a55..7fa2476540 100644 --- a/gui/src/rust/lib/debug-scenes/src/shapes.rs +++ b/gui/src/rust/lib/debug-scenes/src/shapes.rs @@ -9,7 +9,7 @@ use ensogl::prelude::*; use ensogl::display::navigation::navigator::Navigator; use ensogl::system::web; use ensogl::application::Application; -use graph_editor::{GraphEditor, EdgeTarget}; +use graph_editor::GraphEditor; use wasm_bindgen::prelude::*; use ensogl::display::object::ObjectOps; use ensogl_core_msdf_sys::run_once_initialized; @@ -33,13 +33,13 @@ pub fn run_example_shapes() { } -fn fence(network:&frp::Network, trigger:T) -> (frp::Stream,frp::Stream) +fn _fence(network:&frp::Network, trigger:T) -> (frp::Stream,frp::Stream) where T:frp::HasOutput, T:Into>, Out:frp::Data { let trigger = trigger.into(); frp::extend! { network def trigger_ = trigger.constant(()); def runner = source::<()>(); - def switch = gather(); + def switch = any_mut(); switch.attach(&trigger_); def triggered = trigger.map(f_!(runner.emit(()))); switch.attach(&triggered); @@ -49,16 +49,6 @@ where T:frp::HasOutput, T:Into>, Out:frp::Data { (runner,condition) } -//fn fenced_gate(network:&frp::Network, target:&frp::Stream, f:F) -> frp::Stream -//where F:'static+Fn()->T, X:frp::Data { -// let target = target.clone_ref(); -// frp::extend! { network -// let (trigger,runner,condition) = fence(&network); -// def _eval = runner.map(move |_| {f();}); -// def out = target.gate(&condition); -// } -// out -//} fn init(app:&Application) { @@ -67,7 +57,6 @@ fn init(app:&Application) { dark.insert("graph_editor.node.background.color", color::Lcha::new(0.2,0.013,0.18,1.0)); dark.insert("graph_editor.node.selection.color", color::Lcha::new(0.72,0.5,0.22,1.0)); dark.insert("graph_editor.node.selection.size", 7.0); -// dark.insert("graph_editor.node.selection.color", color::Lcha::new(0.7,0.59,0.18,1.0)); dark.insert("animation.duration", 0.5); dark.insert("graph.node.shadow.color", 5.0); dark.insert("graph.node.shadow.size", 5.0); @@ -78,39 +67,7 @@ fn init(app:&Application) { let _bg = app.display.scene().style_sheet.var("application.background.color"); -// println!("{:?}",bg.value()); -// println!("{:?}",app.display.scene().style_sheet.debug_sheet_nodes_count()); -// let t1 : color::Hsla = color::Hsla::new(0.0,0.0,0.03,1.0); -// let t2 : color::Lcha = t1.into(); -// let t4 : color::Rgba = color::Rgba::from(t2); -// println!("{:?}", t2); -// println!("{:?}", color::Rgba::from(t1)); -// println!("{:?}", t4); -// println!("{:?}", color::Hsla::from(color::LinearRgba::new(0.2,0.3,0.4,1.0))); -// -// let x = color::Hsla::from(color::Rgba::new(0.031,0.031,0.031,1.0)); -// let y = color::Rgba::from(x); -// println!("{:?}", y); -// let xyz = color::Xyz::from(color::Rgb::new(0.2,0.4,0.6)); -// let lab = color::Lab::from(color::Rgb::new(0.2,0.4,0.6)); -// let lch = color::Lch::from(color::Rgb::new(0.2,0.4,0.6)); -// let lch = color::Lch::from(color::Rgb::new(1.0,0.0,0.0)); -// println!("{:?}", xyz); -// println!("{:?}", lab); -// println!("{:?}", lch); -// println!("-----------"); -// println!("{:?}", color::Rgb::from(xyz)); -// println!("{:?}", color::Rgb::from(lab)); -// println!("{:?}", color::Rgb::from(lch)); -// println!("{:?}", color::Lab::from(color::Xyz::new(0.1,0.2,0.3))); - -// println!("{:?}", palette::Xyz::from(palette::Srgb::new(0.2,0.4,0.6))); -// println!("{:?}", palette::Lab::from(palette::LinSrgb::new(0.2,0.4,0.6))); -// println!("{:?}", palette::Lab::from(palette::Xyz::new(0.1,0.2,0.3))); - - -// color::test(); let world = &app.display; let scene = world.scene(); @@ -124,27 +81,27 @@ fn init(app:&Application) { let node1_id = graph_editor.add_node(); let node2_id = graph_editor.add_node(); - +// graph_editor.frp.set_node_position.emit((node1_id,Position::new(100.0 , 250.0))); graph_editor.frp.set_node_position.emit((node2_id,Position::new(200.0 , 50.0))); - +// graph_editor.frp.set_node_expression.emit((node1_id,expression_mock())); graph_editor.frp.set_node_expression.emit((node2_id,expression_mock2())); - frp::new_network! { network - def trigger = source::<()>(); - let (runner,condition) = fence(&network,&trigger); - def _eval = runner.map(f_!( { - graph_editor.frp.connect_nodes.emit((EdgeTarget::new(node1_id,default()),EdgeTarget::new(node2_id,vec![1,0,2]))); - })); - def _debug = graph_editor.frp.outputs.edge_added.map2(&condition, |id,cond| { - let owner = if *cond { "GUI" } else { "ME" }; - println!("Edge {:?} added by {}!",id,owner) - }); +// frp::new_network! { network +// def trigger = source::<()>(); +// let (runner,condition) = fence(&network,&trigger); +// def _eval = runner.map(f_!( { +// graph_editor.frp.connect_nodes.emit((EdgeTarget::new(node1_id,default()),EdgeTarget::new(node2_id,vec![1,0,2]))); +// })); +// def _debug = graph_editor.frp.outputs.edge_added.map2(&condition, |id,cond| { +// let owner = if *cond { "GUI" } else { "ME" }; +// println!("Edge {:?} added by {}!",id,owner) +// }); +// +// } - } - - trigger.emit(()); +// trigger.emit(()); let mut was_rendered = false; @@ -152,7 +109,7 @@ fn init(app:&Application) { world.on_frame(move |_| { let _keep_alive = &navigator; let _keep_alive = &graph_editor; - let _keep_alive = &network; +// let _keep_alive = &network; // Temporary code removing the web-loader instance. // To be changed in the future. @@ -181,8 +138,6 @@ use graph_editor::component::node::port::Expression; pub fn expression_mock() -> Expression { - let pattern_crumb = vec![Seq{right:false },Or,Or,Build]; - let _val = ast::crumbs::SegmentMatchCrumb::Body{val:pattern_crumb}; let code = "open \"data.csv\"".into(); let output_span_tree = default(); let input_span_tree = span_tree::builder::TreeBuilder::new(15) diff --git a/gui/src/rust/lib/frp/src/io/keyboard.rs b/gui/src/rust/lib/frp/src/io/keyboard.rs index 7c27791e24..0d39505fe2 100644 --- a/gui/src/rust/lib/frp/src/io/keyboard.rs +++ b/gui/src/rust/lib/frp/src/io/keyboard.rs @@ -153,9 +153,9 @@ impl Default for Keyboard { change_set <- on_pressed . map(KeyMaskChange::on_pressed); change_unset <- on_released . map(KeyMaskChange::on_released); change_clear <- on_defocus . map(|_| KeyMaskChange::on_defocus()); - change_set_unset <- [change_set, change_unset]; - change <- [change_set_unset, change_clear]; - prev_key_mask <- gather::(); + change_set_unset <- any (change_set,change_unset); + change <- any (change_set_unset,change_clear); + prev_key_mask <- any_mut::(); key_mask <- change.map2(&prev_key_mask,KeyMaskChange::updated_mask); prev_key_mask <+ key_mask; previous_key_mask <- key_mask.previous(); diff --git a/gui/src/rust/lib/frp/src/io/mouse.rs b/gui/src/rust/lib/frp/src/io/mouse.rs index d33270797b..70bb67f0bb 100644 --- a/gui/src/rust/lib/frp/src/io/mouse.rs +++ b/gui/src/rust/lib/frp/src/io/mouse.rs @@ -71,18 +71,18 @@ pub struct Mouse { impl Default for Mouse { fn default() -> Self { frp::new_network! { mouse - def release = source_(); - def press = source_(); - def wheel = source_(); - def leave = source_(); - def position = source(); - def down_const = press.constant(true); - def up_const = release.constant(false); - def down = down_const.merge(&up_const); - def up = down.map(|t| !t); - def prev_position = position.previous(); - def translation = position.map2(&prev_position,|t,s| t - s); - def distance = translation.map(|t:&Position| t.length()); + release <- source_(); + press <- source_(); + wheel <- source_(); + leave <- source_(); + position <- source(); + down_const <- press.constant(true); + up_const <- release.constant(false); + down <- any (down_const,up_const); + up <- down.map(|t| !t); + prev_position <- position.previous(); + translation <- position.map2(&prev_position,|t,s| t - s); + distance <- translation.map(|t:&Position| t.length()); }; let network = mouse; Self {network,release,press,leave,wheel,down,up,position,prev_position,translation,distance} diff --git a/gui/src/rust/lib/frp/src/macros.rs b/gui/src/rust/lib/frp/src/macros.rs index 60bc07cb67..6b329a36fa 100644 --- a/gui/src/rust/lib/frp/src/macros.rs +++ b/gui/src/rust/lib/frp/src/macros.rs @@ -71,21 +71,21 @@ /// /// - Stream merge. /// ```compile_fail -/// all_nodes <- [selected_nodes,non_selected_nodes]; +/// all_nodes <- any (selected_nodes,non_selected_nodes); /// ``` /// Desugars to: /// ```compile_fail -/// def all_nodes = merge2(&selected_nodes,non_selected_nodes); +/// def all_nodes = any2 (&selected_nodes,&non_selected_nodes); /// ``` /// /// /// - Stream merge dropping input values. /// ```compile_fail -/// all_nodes <-_ [selected_nodes,non_selected_nodes]; +/// all_nodes <- any_ (selected_nodes,non_selected_nodes); /// ``` /// Desugars to: /// ```compile_fail -/// def all_nodes = merge2_(&selected_nodes,non_selected_nodes); +/// def all_nodes = any2_ (&selected_nodes,&non_selected_nodes); /// ``` /// /// @@ -218,15 +218,37 @@ macro_rules! extend_line2 { ([$($lines:tt)*] $net:ident def $name:ident $(:$ty:ty)? = $tgt1:ident . $tgt2:ident . $tgt3:ident . $tgt4:ident . $base:ident$(::<$param:ty>)?($($arg:tt)*) $($ts:tt)*) => { $crate::extend_line2! { [$($lines)* let $name $(:$ty)? = $net.$base$(::<$param>)?(concat!(stringify!($net),".",stringify!($name)),&$tgt1.$tgt2.$tgt3.$tgt4,$($arg)*) ;] $net def $name = $name $($ts)* } }; ([$($lines:tt)*] $net:ident def $name:ident $(:$ty:ty)? = $tgt1:ident . $tgt2:ident . $tgt3:ident . $tgt4:ident . $tgt5:ident . $base:ident$(::<$param:ty>)?($($arg:tt)*) $($ts:tt)*) => { $crate::extend_line2! { [$($lines)* let $name $(:$ty)? = $net.$base$(::<$param>)?(concat!(stringify!($net),".",stringify!($name)),&$tgt1.$tgt2.$tgt3.$tgt4.$tgt5,$($arg)*) ;] $net def $name = $name $($ts)* } }; - ([] $net:ident $name:ident <- [ $($arg1:ident).+ ] ) => { let $name = $($arg1).+.clone_ref(); }; - ([] $net:ident $name:ident <- [ $($arg1:ident).+ , $($arg2:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge2(&$($arg1).+,&$($arg2).+) $($ts)* } }; - ([] $net:ident $name:ident <- [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge3(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; - ([] $net:ident $name:ident <- [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge4(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; + ([] $net:ident $name:ident <- any (...) $($ts:tt)* ) => {$crate::extend_line2! { [] $net $name <- any_mut() $($ts)* } }; + ([] $net:ident $name:ident <- any ( $($arg1:ident).+ ) ) => { let $name = $($arg1).+.clone_ref(); }; + ([] $net:ident $name:ident <- any ( $($arg1:ident).+ , $($arg2:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any2(&$($arg1).+,&$($arg2).+) $($ts)* } }; + ([] $net:ident $name:ident <- any ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any3(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; + ([] $net:ident $name:ident <- any ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any4(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; + + ([] $net:ident $name:ident <- any_ (...) $($ts:tt)* ) => {$crate::extend_line2! { [] $net $name <- any_mut_() $($ts)* } }; + ([] $net:ident $name:ident <- any_ ( $($arg1:ident).+ ) ) => { let $name = $($arg1).+.constant(()); }; + ([] $net:ident $name:ident <- any_ ( $($arg1:ident).+ , $($arg2:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any2_(&$($arg1).+,&$($arg2).+) $($ts)* } }; + ([] $net:ident $name:ident <- any_ ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any3_(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; + ([] $net:ident $name:ident <- any_ ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = any4_(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; + + + ([] $net:ident $name:ident <- all (...) $($ts:tt)* ) => {$crate::extend_line2! { [] $net $name <- all_mut() $($ts)* } }; + ([] $net:ident $name:ident <- all ( $($arg1:ident).+ ) ) => { let $name = $($arg1).+.clone_ref(); }; + ([] $net:ident $name:ident <- all ( $($arg1:ident).+ , $($arg2:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all2(&$($arg1).+,&$($arg2).+) $($ts)* } }; + ([] $net:ident $name:ident <- all ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all3(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; + ([] $net:ident $name:ident <- all ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all4(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; + + ([] $net:ident $name:ident <- all [...] $($ts:tt)* ) => {$crate::extend_line2! { [] $net $name <- all_mut() $($ts)* } }; + ([] $net:ident $name:ident <- all [ $($arg1:ident).+ ] ) => { let $name = $($arg1).+.clone_ref(); }; + ([] $net:ident $name:ident <- all [ $($arg1:ident).+ , $($arg2:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all_vec2(&$($arg1).+,&$($arg2).+) $($ts)* } }; + ([] $net:ident $name:ident <- all [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all_vec3(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; + ([] $net:ident $name:ident <- all [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all_vec4(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; + + ([] $net:ident $name:ident <- all_ (...) $($ts:tt)* ) => {$crate::extend_line2! { [] $net $name <- all_mut_() $($ts)* } }; + ([] $net:ident $name:ident <- all_ ( $($arg1:ident).+ ) ) => { let $name = $($arg1).+.constant(()); }; + ([] $net:ident $name:ident <- all_ ( $($arg1:ident).+ , $($arg2:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all2_(&$($arg1).+,&$($arg2).+) $($ts)* } }; + ([] $net:ident $name:ident <- all_ ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all3_(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; + ([] $net:ident $name:ident <- all_ ( $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ) $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = all4_(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; - ([] $net:ident $name:ident <-_ [ $($arg1:ident).+ ] ) => { let $name = $($arg1).+.constant(()); }; - ([] $net:ident $name:ident <-_ [ $($arg1:ident).+ , $($arg2:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge2_(&$($arg1).+,&$($arg2).+) $($ts)* } }; - ([] $net:ident $name:ident <-_ [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge3_(&$($arg1).+,&$($arg2).+,&$($arg3).+) $($ts)* } }; - ([] $net:ident $name:ident <-_ [ $($arg1:ident).+ , $($arg2:ident).+ , $($arg3:ident).+ , $($arg4:ident).+ ] $($ts:tt)* ) => {$crate::extend_line2! { [] $net def $name = merge4_(&$($arg1).+,&$($arg2).+,&$($arg3).+,&$($arg4).+) $($ts)* } }; ([] $net:ident $name:ident <= $($toks:tt)*) => {$crate::extend_line2! { [] $net def $name = $($toks)* . iter()} }; ([] $net:ident $name:ident <- $($toks:tt)*) => {$crate::extend_line2! { [] $net def $name = $($toks)* } }; diff --git a/gui/src/rust/lib/frp/src/nodes.rs b/gui/src/rust/lib/frp/src/nodes.rs index 1739566338..ed230b21d1 100644 --- a/gui/src/rust/lib/frp/src/nodes.rs +++ b/gui/src/rust/lib/frp/src/nodes.rs @@ -11,6 +11,7 @@ use crate::data::watch; use crate::network::*; use crate::node::*; use crate::stream::EventOutput; +use crate::stream::ValueProvider; use crate::stream::Stream; use crate::stream::OwnedStream; use crate::stream; @@ -31,46 +32,46 @@ impl Network { self.register_raw(OwnedSource::new(label)) } - /// Begin point in the FRP network. Specialized version of `source`. + /// Begin point in the FRP network. Specialized version of `src`. pub fn source_(&self, label:Label) -> Source { self.register_raw(OwnedSource::new(label)) } /// Remember the last event value and allow sampling it anytime. - pub fn sampler(&self, label:Label, source:&T) -> Sampler + pub fn sampler(&self, label:Label, src:&T) -> Sampler where T:EventOutput, Out:Data { - self.register_raw(OwnedSampler::new(label,source)) + self.register_raw(OwnedSampler::new(label,src)) } /// Print the incoming events to console and pass them to output. - pub fn trace(&self, label:Label, source:&T) -> Stream> { - self.register(OwnedTrace::new(label,source)) + pub fn trace(&self, label:Label, src:&T) -> Stream> { + self.register(OwnedTrace::new(label,src)) } /// Emits `true`, `false`, `true`, `false`, ... on every incoming event. - pub fn toggle(&self, label:Label, source:&T) -> Stream { - self.register(OwnedToggle::new(label,source)) + pub fn toggle(&self, label:Label, src:&T) -> Stream { + self.register(OwnedToggle::new(label,src)) } /// Emits `true`, `false`, `true`, `false`, ... on every incoming event. Initialized with true /// value. - pub fn toggle_true(&self, label:Label, source:&T) -> Stream { - self.register(OwnedToggle::new_with(label,source,true)) + pub fn toggle_true(&self, label:Label, src:&T) -> Stream { + self.register(OwnedToggle::new_with(label,src,true)) } /// Count the incoming events. - pub fn count(&self, label:Label, source:&T) -> Stream { - self.register(OwnedCount::new(label,source)) + pub fn count(&self, label:Label, src:&T) -> Stream { + self.register(OwnedCount::new(label,src)) } /// Replaces the incoming event with the predefined value. - pub fn constant (&self, label:Label, source:&T, value:X) -> Stream { - self.register(OwnedConstant::new(label,source,value)) + pub fn constant (&self, label:Label, src:&T, value:X) -> Stream { + self.register(OwnedConstant::new(label,src,value)) } /// Remembers the value of the input stream and outputs the previously received one. - pub fn previous (&self, label:Label, source:&T) -> Stream> { - self.register(OwnedPrevious::new(label,source)) + pub fn previous (&self, label:Label, src:&T) -> Stream> { + self.register(OwnedPrevious::new(label,src)) } /// Samples the first stream (behavior) on every incoming event of the second stream. The @@ -92,11 +93,21 @@ impl Network { self.register(OwnedGateNot::new(label,event,behavior)) } + pub fn unwrap(&self, label:Label, event:&T) -> Stream + where T:EventOutput>, S:Data { + self.register(OwnedUnwrap::new(label,event)) + } + pub fn iter(&self, label:Label, event:&T1) -> Stream where T1:EventOutput, for<'t> &'t T1::Output:IntoIterator, X:Data { self.register(OwnedIter::new(label,event)) } + pub fn fold(&self, label:Label, event:&T1) -> Stream + where T1:EventOutput, for<'t> &'t T1::Output:IntoIterator, X:Data+Monoid { + self.register(OwnedFold::new(label,event)) + } + pub fn _0(&self, label:Label, event:&T1) -> Stream>> where T1:EventOutput, T1::Output:generics::GetItemAt0, generics::ItemAt0:Data { self.register(OwnedGet0::new(label,event)) @@ -113,108 +124,137 @@ impl Network { } - // === Merge === + // === Any === /// Merges multiple input streams into a single output stream. All input streams have to share - /// the same output data type. Please note that `gather` can be used to create recursive FRP - /// networks by creating an empty merge and using the `attach` method to attach new streams to - /// it. When a recursive network is created, `gather` breaks the cycle. After passing the first + /// the same output data type. Please note that `any_mut` can be used to create recursive FRP + /// networks by creating an empty `any` and using the `attach` method to attach new streams to + /// it. When a recursive network is created, `any_mut` breaks the cycle. After passing the first /// event, no more events will be passed till the end of the current FRP network resolution. - pub fn gather(&self, label:Label) -> Merge { - self.register_raw(OwnedMerge::new(label)) + pub fn any_mut(&self, label:Label) -> Any { + self.register_raw(OwnedAny::new(label)) } /// Merges multiple input streams into a single output stream. All input streams have to share /// the same output data type. - pub fn merge(&self, label:Label, t1:&T1, t2:&T2) -> Stream + pub fn any(&self, label:Label, t1:&T1, t2:&T2) -> Stream where T1:EventOutput, T2:EventOutput { - self.register(OwnedMerge::new2(label,t1,t2)) + self.register(OwnedAny::new2(label,t1,t2)) } - /// Specialized version of `merge`. - pub fn merge2(&self, label:Label, t1:&T1, t2:&T2) -> Stream + /// Specialized version of `any`. + pub fn any2(&self, label:Label, t1:&T1, t2:&T2) -> Stream where T1:EventOutput, T2:EventOutput { - self.register(OwnedMerge::new2(label,t1,t2)) + self.register(OwnedAny::new2(label,t1,t2)) } - /// Specialized version of `merge`. - pub fn merge3(&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream + /// Specialized version of `any`. + pub fn any3(&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream where T1:EventOutput, T2:EventOutput, T3:EventOutput { - self.register(OwnedMerge::new3(label,t1,t2,t3)) + self.register(OwnedAny::new3(label,t1,t2,t3)) } - /// Specialized version of `merge`. - pub fn merge4 + /// Specialized version of `any`. + pub fn any4 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Stream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - self.register(OwnedMerge::new4(label,t1,t2,t3,t4)) + self.register(OwnedAny::new4(label,t1,t2,t3,t4)) } - // === Merge_ === + // === Any_ === - /// Like `gather` but drops the incoming data. You can attach streams of different types. - pub fn gather_(&self, label:Label) -> Merge_ { - self.register_raw(OwnedMerge_::new(label)) + /// Like `any_mut` but drops the incoming data. You can attach streams of different types. + pub fn any_mut_(&self, label:Label) -> Any_ { + self.register_raw(OwnedAny_::new(label)) } - /// Like `merge` but drops the incoming data. You can attach streams of different types. - pub fn merge_(&self, label:Label, t1:&T1, t2:&T2) -> Stream<()> + /// Like `any` but drops the incoming data. You can attach streams of different types. + pub fn any_(&self, label:Label, t1:&T1, t2:&T2) -> Stream<()> where T1:EventOutput, T2:EventOutput { - self.register(OwnedMerge_::new2(label,t1,t2)) + self.register(OwnedAny_::new2(label,t1,t2)) } - /// Specialized version of `merge_`. - pub fn merge2_(&self, label:Label, t1:&T1, t2:&T2) -> Stream<()> + /// Specialized version of `any_`. + pub fn any2_(&self, label:Label, t1:&T1, t2:&T2) -> Stream<()> where T1:EventOutput, T2:EventOutput { - self.register(OwnedMerge_::new2(label,t1,t2)) + self.register(OwnedAny_::new2(label,t1,t2)) } - /// Specialized version of `merge_`. - pub fn merge3_(&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream<()> + /// Specialized version of `any_`. + pub fn any3_(&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream<()> where T1:EventOutput, T2:EventOutput, T3:EventOutput { - self.register(OwnedMerge_::new3(label,t1,t2,t3)) + self.register(OwnedAny_::new3(label,t1,t2,t3)) } - /// Specialized version of `merge_`. - pub fn merge4_ + /// Specialized version of `any_`. + pub fn any4_ (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Stream<()> where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - self.register(OwnedMerge_::new4(label,t1,t2,t3,t4)) + self.register(OwnedAny_::new4(label,t1,t2,t3,t4)) } - // === Zip === + // === All === /// Merges input streams into a stream containing values from all of them. On event from any of /// the input streams, all streams are sampled and the final event is produced. - pub fn zip(&self, label:Label, t1:&T1, t2:&T2) -> Stream<(Output,Output)> - where T1:EventOutput, T2:EventOutput { - self.register(OwnedZip2::new(label,t1,t2)) + pub fn all_mut(&self, label:Label) -> AllMut { + self.register_raw(OwnedAllMut::new(label)) } - /// Specialized version of `zip`. - pub fn zip2(&self, label:Label, t1:&T1, t2:&T2) -> Stream<(Output,Output)> - where T1:EventOutput, T2:EventOutput { - self.register(OwnedZip2::new(label,t1,t2)) + pub fn all_vec2(&self, label:Label, t1:&T1, t2:&T2) -> Stream> + where Out:Data, T1:EventOutput, T2:EventOutput { + self.register(OwnedAllMut::new(label).with(t1).with(t2)) } - /// Specialized version of `zip`. - pub fn zip3 + pub fn all_vec3(&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream> + where Out : Data, + T1 : EventOutput, + T2 : EventOutput, + T3 : EventOutput { + self.register(OwnedAllMut::new(label).with(t1).with(t2).with(t3)) + } + + pub fn all_vec4 + (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Stream> + where Out : Data, + T1 : EventOutput, + T2 : EventOutput, + T3 : EventOutput, + T4 : EventOutput { + self.register(OwnedAllMut::new(label).with(t1).with(t2).with(t3).with(t4)) + } + + /// Merges input streams into a stream containing values from all of them. On event from any of + /// the input streams, all streams are sampled and the final event is produced. + pub fn all(&self, label:Label, t1:&T1, t2:&T2) -> Stream<(Output,Output)> + where T1:EventOutput, T2:EventOutput { + self.register(OwnedAll2::new(label,t1,t2)) + } + + /// Specialized version of `all`. + pub fn all2(&self, label:Label, t1:&T1, t2:&T2) -> Stream<(Output,Output)> + where T1:EventOutput, T2:EventOutput { + self.register(OwnedAll2::new(label,t1,t2)) + } + + /// Specialized version of `all`. + pub fn all3 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> Stream<(Output,Output,Output)> where T1:EventOutput, T2:EventOutput, T3:EventOutput { - self.register(OwnedZip3::new(label,t1,t2,t3)) + self.register(OwnedAll3::new(label,t1,t2,t3)) } - /// Specialized version of `zip`. - pub fn zip4 + /// Specialized version of `all`. + pub fn all4 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Stream<(Output,Output,Output,Output)> where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - self.register(OwnedZip4::new(label,t1,t2,t3,t4)) + self.register(OwnedAll4::new(label,t1,t2,t3,t4)) } @@ -222,10 +262,10 @@ impl Network { /// On every event from the first input stream, sample all other input streams and run the /// provided function on all gathered values. If you want to run the function on event from any - /// input stream, use the `zip_with` function family instead. - pub fn map(&self, label:Label, source:&T, f:F) -> Stream + /// input stream, use the `all_with` function family instead. + pub fn map(&self, label:Label, src:&T, f:F) -> Stream where T:EventOutput, Out:Data, F:'static+Fn(&Output)->Out { - self.register(OwnedMap::new(label,source,f)) + self.register(OwnedMap::new(label,src,f)) } /// Specialized version of `map`. @@ -251,30 +291,30 @@ impl Network { } - // === Apply === + // === AllWith === /// On every input event sample all input streams and run the provided function on all gathered /// values. If you want to run the function only on event on the first input, use the `map` /// function family instead. - pub fn zip_with(&self, label:Label, t1:&T1, t2:&T2, f:F) -> Stream + pub fn all_with(&self, label:Label, t1:&T1, t2:&T2, f:F) -> Stream where T1:EventOutput, T2:EventOutput, T:Data, F:'static+Fn(&Output,&Output)->T { - self.register(OwnedApply2::new(label,t1,t2,f)) + self.register(OwnedAllWith2::new(label,t1,t2,f)) } /// Specialized version `apply`. - pub fn zip_with3 + pub fn all_with3 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, f:F) -> Stream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T:Data, F:'static+Fn(&Output,&Output,&Output)->T { - self.register(OwnedApply3::new(label,t1,t2,t3,f)) + self.register(OwnedAllWith3::new(label,t1,t2,t3,f)) } /// Specialized version `apply`. - pub fn zip_with4 + pub fn all_with4 (&self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, f:F) -> Stream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T:Data, F:'static+Fn(&Output,&Output,&Output,&Output)->T { - self.register(OwnedApply4::new(label,t1,t2,t3,t4,f)) + self.register(OwnedAllWith4::new(label,t1,t2,t3,t4,f)) } } @@ -306,29 +346,29 @@ impl DynamicNetwork { OwnedSource::new(label) } - pub fn sampler(self, label:Label, source:&T) -> OwnedSampler + pub fn sampler(self, label:Label, src:&T) -> OwnedSampler where T:EventOutput, Out:Data { - OwnedSampler::new(label,source) + OwnedSampler::new(label,src) } - pub fn trace(self, label:Label, source:&T) -> OwnedStream> { - OwnedTrace::new(label,source).into() + pub fn trace(self, label:Label, src:&T) -> OwnedStream> { + OwnedTrace::new(label,src).into() } - pub fn toggle(self, label:Label, source:&T) -> OwnedStream { - OwnedToggle::new(label,source).into() + pub fn toggle(self, label:Label, src:&T) -> OwnedStream { + OwnedToggle::new(label,src).into() } - pub fn count(self, label:Label, source:&T) -> OwnedCount { - OwnedCount::new(label,source) + pub fn count(self, label:Label, src:&T) -> OwnedCount { + OwnedCount::new(label,src) } - pub fn constant (self, label:Label, source:&T, value:X) -> OwnedStream { - OwnedConstant::new(label,source,value).into() + pub fn constant (self, label:Label, src:&T, value:X) -> OwnedStream { + OwnedConstant::new(label,src,value).into() } - pub fn previous (self, label:Label, source:&T) -> OwnedStream> { - OwnedPrevious::new(label,source).into() + pub fn previous (self, label:Label, src:&T) -> OwnedStream> { + OwnedPrevious::new(label,src).into() } pub fn sample @@ -351,6 +391,11 @@ impl DynamicNetwork { OwnedIter::new(label,event).into() } + pub fn fold(self, label:Label, event:&T1) -> OwnedStream + where T1:EventOutput, for<'t> &'t T1::Output:IntoIterator, X:Data+Monoid { + OwnedFold::new(label,event).into() + } + pub fn _0(self, label:Label, event:&T1) -> OwnedStream>> where T1:EventOutput, T1::Output:generics::GetItemAt0, generics::ItemAt0:Data { OwnedGet0::new(label,event).into() @@ -367,96 +412,96 @@ impl DynamicNetwork { } - // === Merge === + // === Any === - pub fn gather(self, label:Label) -> OwnedMerge { - OwnedMerge::new(label) + pub fn any_mut(self, label:Label) -> OwnedAny { + OwnedAny::new(label) } - pub fn merge(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream + pub fn any(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream where T1:EventOutput, T2:EventOutput { - OwnedMerge::new2(label,t1,t2).into() + OwnedAny::new2(label,t1,t2).into() } - pub fn merge2(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream + pub fn any2(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream where T1:EventOutput, T2:EventOutput { - OwnedMerge::new2(label,t1,t2).into() + OwnedAny::new2(label,t1,t2).into() } - pub fn merge3(self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> OwnedStream + pub fn any3(self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> OwnedStream where T1:EventOutput, T2:EventOutput, T3:EventOutput { - OwnedMerge::new3(label,t1,t2,t3).into() + OwnedAny::new3(label,t1,t2,t3).into() } - pub fn merge4 + pub fn any4 (self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> OwnedStream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - OwnedMerge::new4(label,t1,t2,t3,t4).into() + OwnedAny::new4(label,t1,t2,t3,t4).into() } - // === Merge_ === + // === Any_ === - pub fn gather_(self, label:Label) -> OwnedMerge_ { - OwnedMerge_::new(label) + pub fn any_mut_(self, label:Label) -> OwnedAny_ { + OwnedAny_::new(label) } - pub fn merge_(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<()> + pub fn any_(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<()> where T1:EventOutput, T2:EventOutput { - OwnedMerge_::new2(label,t1,t2).into() + OwnedAny_::new2(label,t1,t2).into() } - pub fn merge2_(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<()> + pub fn any2_(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<()> where T1:EventOutput, T2:EventOutput { - OwnedMerge_::new2(label,t1,t2).into() + OwnedAny_::new2(label,t1,t2).into() } - pub fn merge3_(self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> OwnedStream<()> + pub fn any3_(self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> OwnedStream<()> where T1:EventOutput, T2:EventOutput, T3:EventOutput { - OwnedMerge_::new3(label,t1,t2,t3).into() + OwnedAny_::new3(label,t1,t2,t3).into() } - pub fn merge4_ + pub fn any4_ (self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> OwnedStream<()> where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - OwnedMerge_::new4(label,t1,t2,t3,t4).into() + OwnedAny_::new4(label,t1,t2,t3,t4).into() } - // === Zip === + // === All === - pub fn zip(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<(Output,Output)> + pub fn all(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<(Output,Output)> where T1:EventOutput, T2:EventOutput { - OwnedZip2::new(label,t1,t2).into() + OwnedAll2::new(label,t1,t2).into() } - pub fn zip2(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<(Output,Output)> + pub fn all2(self, label:Label, t1:&T1, t2:&T2) -> OwnedStream<(Output,Output)> where T1:EventOutput, T2:EventOutput { - OwnedZip2::new(label,t1,t2).into() + OwnedAll2::new(label,t1,t2).into() } - pub fn zip3 + pub fn all3 (self, label:Label, t1:&T1, t2:&T2, t3:&T3) -> OwnedStream<(Output,Output,Output)> where T1:EventOutput, T2:EventOutput, T3:EventOutput { - OwnedZip3::new(label,t1,t2,t3).into() + OwnedAll3::new(label,t1,t2,t3).into() } - pub fn zip4 + pub fn all4 (self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> OwnedStream<(Output,Output,Output,Output)> where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { - OwnedZip4::new(label,t1,t2,t3,t4).into() + OwnedAll4::new(label,t1,t2,t3,t4).into() } // === Map === - pub fn map(self, label:Label, source:&T, f:F) -> OwnedStream + pub fn map(self, label:Label, src:&T, f:F) -> OwnedStream where T:EventOutput, Out:Data, F:'static+Fn(&Output)->Out { - OwnedMap::new(label,source,f).into() + OwnedMap::new(label,src,f).into() } pub fn map2(self, label:Label, t1:&T1, t2:&T2, f:F) -> OwnedStream @@ -479,25 +524,25 @@ impl DynamicNetwork { } - // === Apply === + // === AllWith === pub fn apply2(self, label:Label, t1:&T1, t2:&T2, f:F) -> OwnedStream where T1:EventOutput, T2:EventOutput, T:Data, F:'static+Fn(&Output,&Output)->T { - OwnedApply2::new(label,t1,t2,f).into() + OwnedAllWith2::new(label,t1,t2,f).into() } pub fn apply3 (self, label:Label, t1:&T1, t2:&T2, t3:&T3, f:F) -> OwnedStream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T:Data, F:'static+Fn(&Output,&Output,&Output)->T { - OwnedApply3::new(label,t1,t2,t3,f).into() + OwnedAllWith3::new(label,t1,t2,t3,f).into() } pub fn apply4 (self, label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, f:F) -> OwnedStream where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, T:Data, F:'static+Fn(&Output,&Output,&Output,&Output)->T { - OwnedApply4::new(label,t1,t2,t3,t4,f).into() + OwnedAllWith4::new(label,t1,t2,t3,t4,f).into() } } @@ -557,7 +602,7 @@ impl Source { // =============== #[derive(Debug)] -pub struct SamplerData { source:Box, value:RefCell } +pub struct SamplerData { src:Box, value:RefCell } pub type OwnedSampler = stream::Node >; pub type Sampler = stream::WeakNode >; @@ -567,12 +612,12 @@ impl HasOutput for SamplerData { impl OwnedSampler { /// Constructor. - pub fn new(label:Label, src:&T1) -> Self + pub fn new(label:Label, src1:&T1) -> Self where T1:EventOutput { - let source = Box::new(src.clone_ref()); + let src = Box::new(src1.clone_ref()); let value = default(); - let definition = SamplerData {source,value}; - Self::construct_and_connect(label,src,definition) + let definition = SamplerData {src,value}; + Self::construct_and_connect(label,src1,definition) } } @@ -604,7 +649,7 @@ impl stream::EventConsumer for OwnedSampler { // ============= #[derive(Clone,Debug)] -pub struct TraceData { source:T } +pub struct TraceData { src:T } pub type OwnedTrace = stream::Node >; pub type Trace = stream::WeakNode >; @@ -614,10 +659,10 @@ impl HasOutput for TraceData { impl OwnedTrace { /// Constructor. - pub fn new(label:Label, src:&T) -> Self { - let source = src.clone_ref(); - let def = TraceData {source}; - Self::construct_and_connect(label,src,def) + pub fn new(label:Label, src1:&T) -> Self { + let src = src1.clone_ref(); + let def = TraceData {src}; + Self::construct_and_connect(label,src1,def) } } @@ -635,7 +680,7 @@ impl stream::EventConsumer> for OwnedTrace { // ============== #[derive(Debug)] -pub struct ToggleData { source:T, value:Cell } +pub struct ToggleData { src:T, value:Cell } pub type OwnedToggle = stream::Node >; pub type Toggle = stream::WeakNode >; @@ -645,16 +690,16 @@ impl HasOutput for ToggleData { impl OwnedToggle { /// Constructor. - pub fn new(label:Label, source:&T) -> Self { - Self::new_with(label,source,default()) + pub fn new(label:Label, src:&T) -> Self { + Self::new_with(label,src,default()) } /// Constructor with explicit start value. - pub fn new_with(label:Label, src:&T, init:bool) -> Self { - let source = src.clone_ref(); - let value = Cell::new(init); - let def = ToggleData {source,value}; - Self::construct_and_connect_with_init_value(label,src,def,init) + pub fn new_with(label:Label, src1:&T, init:bool) -> Self { + let src = src1.clone_ref(); + let value = Cell::new(init); + let def = ToggleData {src,value}; + Self::construct_and_connect_with_init_value(label,src1,def,init) } } @@ -673,7 +718,7 @@ impl stream::EventConsumer> for OwnedToggle { // ============= #[derive(Debug)] -pub struct CountData { source:T, value:Cell } +pub struct CountData { src:T, value:Cell } pub type OwnedCount = stream::Node >; pub type Count = stream::WeakNode >; @@ -683,11 +728,11 @@ impl HasOutput for CountData { impl OwnedCount { /// Constructor. - pub fn new(label:Label, src:&T) -> Self { - let source = src.clone_ref(); + pub fn new(label:Label, src1:&T) -> Self { + let src = src1.clone_ref(); let value = default(); - let def = CountData {source,value}; - Self::construct_and_connect(label,src,def) + let def = CountData {src,value}; + Self::construct_and_connect(label,src1,def) } } @@ -706,7 +751,7 @@ impl stream::EventConsumer> for OwnedCount { // ================ #[derive(Debug)] -pub struct ConstantData { source:T, value:Out } +pub struct ConstantData { src:T, value:Out } pub type OwnedConstant = stream::Node >; pub type Constant = stream::WeakNode >; @@ -716,10 +761,10 @@ impl HasOutput for ConstantData { impl OwnedConstant { /// Constructor. - pub fn new(label:Label, src:&T, value:Out) -> Self { - let source = src.clone_ref(); - let def = ConstantData {source,value}; - Self::construct_and_connect(label,src,def) + pub fn new(label:Label, src1:&T, value:Out) -> Self { + let src = src1.clone_ref(); + let def = ConstantData {src,value}; + Self::construct_and_connect(label,src1,def) } } @@ -736,7 +781,7 @@ impl stream::EventConsumer> for OwnedConstant< // ================ #[derive(Debug)] -pub struct PreviousData { source:T, previous:RefCell> } +pub struct PreviousData { src:T, previous:RefCell> } pub type OwnedPrevious = stream::Node >; pub type Previous = stream::WeakNode >; @@ -746,11 +791,11 @@ impl HasOutput for PreviousData { impl OwnedPrevious { /// Constructor. - pub fn new(label:Label, src:&T) -> Self { - let source = src.clone_ref(); + pub fn new(label:Label, src1:&T) -> Self { + let src = src1.clone_ref(); let previous = default(); - let def = PreviousData {source,previous}; - Self::construct_and_connect(label,src,def) + let def = PreviousData {src,previous}; + Self::construct_and_connect(label,src1,def) } } @@ -884,33 +929,68 @@ impl stream::InputBehaviors for GateNotData -// ============= -// === Merge === -// ============= +// ============== +// === Unwrap === +// ============== #[derive(Debug)] -pub struct MergeData { sources:Rc>>>, phantom:PhantomData } -pub type OwnedMerge = stream::Node >; -pub type Merge = stream::WeakNode >; +pub struct UnwrapData { src:T } +pub type OwnedUnwrap = stream::Node >; +pub type Unwrap = stream::WeakNode >; -impl HasOutput for MergeData { +impl HasOutput for UnwrapData +where T:EventOutput>, S:Data { + type Output = S; +} + +impl OwnedUnwrap +where T:EventOutput>, S:Data { + /// Constructor. + pub fn new(label:Label, src1:&T) -> Self { + let src = src1.clone_ref(); + let def = UnwrapData {src}; + Self::construct_and_connect(label,src1,def) + } +} + +impl stream::EventConsumer> for OwnedUnwrap +where T:EventOutput>, S:Data { + fn on_event(&self, event:&Output) { + if let Some(t) = event { + self.emit_event(t) + } + } +} + + + +// =========== +// === Any === +// =========== + +#[derive(Debug)] +pub struct AnyData { srcs:Rc>>>, phantom:PhantomData } +pub type OwnedAny = stream::Node >; +pub type Any = stream::WeakNode >; + +impl HasOutput for AnyData { type Output = Out; } -impl OwnedMerge { +impl OwnedAny { /// Constructor. pub fn new(label:Label) -> Self { - let sources = default(); + let srcs = default(); let phantom = default(); - let def = MergeData {sources,phantom}; + let def = AnyData {srcs,phantom}; Self::construct(label,def) } /// Takes ownership of self and returns it with a new stream attached. - pub fn with(self, source:&T) -> Self + pub fn with(self, src:&T) -> Self where T:EventOutput { - source.register_target(self.downgrade().into()); - self.sources.borrow_mut().push(Box::new(source.clone_ref())); + src.register_target(self.downgrade().into()); + self.srcs.borrow_mut().push(Box::new(src.clone_ref())); self } @@ -945,24 +1025,24 @@ impl OwnedMerge { } } -impl Merge { +impl Any { /// Takes ownership of self and returns it with a new stream attached. - pub fn with(self, source:&T1) -> Self + pub fn with(self, src:&T1) -> Self where T1:EventOutput { - source.register_target(self.clone_ref().into()); - self.upgrade().for_each(|t| t.sources.borrow_mut().push(Box::new(source.clone_ref()))); + src.register_target(self.clone_ref().into()); + self.upgrade().for_each(|t| t.srcs.borrow_mut().push(Box::new(src.clone_ref()))); self } - /// Attach new source to this node. - pub fn attach(&self, source:&T1) + /// Attach new src to this node. + pub fn attach(&self, src:&T1) where T1:EventOutput { - source.register_target(self.into()); - self.upgrade().for_each(|t| t.sources.borrow_mut().push(Box::new(source.clone_ref()))); + src.register_target(self.into()); + self.upgrade().for_each(|t| t.srcs.borrow_mut().push(Box::new(src.clone_ref()))); } } -impl stream::EventConsumer for OwnedMerge { +impl stream::EventConsumer for OwnedAny { fn on_event(&self, event:&Out) { self.emit_event(event); } @@ -970,32 +1050,32 @@ impl stream::EventConsumer for OwnedMerge { -// ============= -// === Merge === -// ============= +// ============ +// === Any_ === +// ============ #[derive(Debug)] -pub struct MergeData_ { sources:Rc>>> } -pub type OwnedMerge_ = stream::Node ; -pub type Merge_ = stream::WeakNode ; +pub struct AnyData_ { srcs:Rc>>> } +pub type OwnedAny_ = stream::Node ; +pub type Any_ = stream::WeakNode ; -impl HasOutput for MergeData_ { +impl HasOutput for AnyData_ { type Output = (); } -impl OwnedMerge_ { +impl OwnedAny_ { /// Constructor. pub fn new(label:Label) -> Self { - let sources = default(); - let def = MergeData_ {sources}; + let srcs = default(); + let def = AnyData_ {srcs}; Self::construct(label,def) } /// Takes ownership of self and returns it with a new stream attached. - pub fn with(self, source:&T) -> Self + pub fn with(self, src:&T) -> Self where T:EventOutput { - source.register_target(self.downgrade().into()); - self.sources.borrow_mut().push(Box::new(source.clone_ref())); + src.register_target(self.downgrade().into()); + self.srcs.borrow_mut().push(Box::new(src.clone_ref())); self } @@ -1024,24 +1104,24 @@ impl OwnedMerge_ { } } -impl Merge_ { +impl Any_ { /// Takes ownership of self and returns it with a new stream attached. - pub fn with(self, source:&T1) -> Self + pub fn with(self, src:&T1) -> Self where T1:EventOutput { - source.register_target(self.clone_ref().into()); - self.upgrade().for_each(|t| t.sources.borrow_mut().push(Box::new(source.clone_ref()))); + src.register_target(self.clone_ref().into()); + self.upgrade().for_each(|t| t.srcs.borrow_mut().push(Box::new(src.clone_ref()))); self } - /// Attach new source to this node. - pub fn attach(&self, source:&T1) + /// Attach new src to this node. + pub fn attach(&self, src:&T1) where T1:EventOutput { - source.register_target(self.into()); - self.upgrade().for_each(|t| t.sources.borrow_mut().push(Box::new(source.clone_ref()))); + src.register_target(self.into()); + self.upgrade().for_each(|t| t.srcs.borrow_mut().push(Box::new(src.clone_ref()))); } } -impl stream::EventConsumer for OwnedMerge_ { +impl stream::EventConsumer for OwnedAny_ { fn on_event(&self, _:&T) { self.emit_event(&()); } @@ -1126,6 +1206,7 @@ impl stream::InputBehaviors for Get1Data { } + // ============ // === Get2 === // ============ @@ -1207,26 +1288,165 @@ impl stream::InputBehaviors for IterData { // ============ -// === Zip2 === +// === Fold === // ============ #[derive(Debug)] -pub struct Zip2Data { source1:watch::Ref, source2:watch::Ref } -pub type OwnedZip2 = stream::Node >; -pub type Zip2 = stream::WeakNode >; +pub struct FoldData { event:T1 } +pub type OwnedFold = stream::Node >; +pub type Fold = stream::WeakNode >; -impl HasOutput for Zip2Data +impl HasOutput for FoldData + where T1:EventOutput, X:Data, for<'t> &'t T1::Output:IntoIterator { + type Output = X; +} + +impl OwnedFold + where T1:EventOutput, X:Data+Monoid, for<'t> &'t T1::Output:IntoIterator { + /// Constructor. + pub fn new(label:Label, src:&T1) -> Self { + let event = src.clone_ref(); + let definition = FoldData {event}; + Self::construct_and_connect(label,src,definition) + } +} + +impl stream::EventConsumer> for OwnedFold + where T1:EventOutput, X:Data+Monoid, for<'t> &'t T1::Output:IntoIterator { + fn on_event(&self, event:&Output) { + self.emit_event(&event.into_iter().fold(default(),|t,s| t.concat(s))) + } +} + +impl stream::InputBehaviors for FoldData { + fn input_behaviors(&self) -> Vec { + vec![] + } +} + + + +// ============== +// === AllMut === +// ============== + +pub struct AllMutData { + srcs : Rc>>>>, + watches : Rc>>>, + phantom : PhantomData } +pub type OwnedAllMut = stream::Node >; +pub type AllMut = stream::WeakNode >; + +impl Debug for AllMutData { + fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result { + write!(f,"AllMutData") + } +} + +impl HasOutput for AllMutData { + type Output = Vec; +} + +impl OwnedAllMut { + /// Constructor. + pub fn new(label:Label) -> Self { + let srcs = default(); + let watches = default(); + let phantom = default(); + let def = AllMutData {srcs,watches,phantom}; + Self::construct(label,def) + } + + /// Takes ownership of self and returns it with a new stream attached. + pub fn with(self, src:&T) -> Self + where T:EventOutput { + src.register_target(self.downgrade().into()); + let watch = watch_stream(src); + self.watches.borrow_mut().push(Box::new(watch)); + self.srcs.borrow_mut().push(Box::new(src.clone_ref())); + self + } + + /// Constructor for 1 input stream. + pub fn new1(label:Label, t1:&T1) -> Self + where T1:EventOutput { + Self::new(label).with(t1) + } + + /// Constructor for 2 input streams. + pub fn new2(label:Label, t1:&T1, t2:&T2) -> Self + where T1:EventOutput, + T2:EventOutput { + Self::new(label).with(t1).with(t2) + } + + /// Constructor for 3 input streams. + pub fn new3(label:Label, t1:&T1, t2:&T2, t3:&T3) -> Self + where T1:EventOutput, + T2:EventOutput, + T3:EventOutput { + Self::new(label).with(t1).with(t2).with(t3) + } + + /// Constructor for 4 input streams. + pub fn new4(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Self + where T1:EventOutput, + T2:EventOutput, + T3:EventOutput, + T4:EventOutput { + Self::new(label).with(t1).with(t2).with(t3).with(t4) + } +} + +impl AllMut { + /// Attach new src to this node. + pub fn attach(&self, src:&T1) + where T1:EventOutput { + src.register_target(self.into()); + let watch = watch_stream(src); + self.upgrade().for_each(|t| { + t.watches.borrow_mut().push(Box::new(watch)); + t.srcs.borrow_mut().push(Box::new(src.clone_ref())) + }); + } + + pub fn with(self, src:&T1) -> Self + where T1:EventOutput { + self.attach(src); + self + } +} + +impl stream::EventConsumer for OwnedAllMut { + fn on_event(&self, _event:&Out) { + let values = self.srcs.borrow().iter().map(|src| src.value()).collect(); + self.emit_event(&values); + } +} + + + +// ============ +// === All2 === +// ============ + +#[derive(Debug)] +pub struct All2Data { src1:watch::Ref, src2:watch::Ref } +pub type OwnedAll2 = stream::Node >; +pub type All2 = stream::WeakNode >; + +impl HasOutput for All2Data where T1:EventOutput, T2:EventOutput { type Output = (Output,Output); } -impl OwnedZip2 +impl OwnedAll2 where T1:EventOutput, T2:EventOutput { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let def = Zip2Data {source1,source2}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let def = All2Data {src1,src2}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1235,47 +1455,47 @@ where T1:EventOutput, T2:EventOutput { } } -impl stream::EventConsumer for OwnedZip2 +impl stream::EventConsumer for OwnedAll2 where T1:EventOutput, T2:EventOutput { fn on_event(&self, _:&Out) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); self.emit_event(&(value1,value2)); } } -impl stream::InputBehaviors for Zip2Data +impl stream::InputBehaviors for All2Data where T1:EventOutput, T2:EventOutput { fn input_behaviors(&self) -> Vec { - vec![Link::mixed(&self.source1), Link::mixed(&self.source2)] + vec![Link::mixed(&self.src1), Link::mixed(&self.src2)] } } // ============ -// === Zip3 === +// === All3 === // ============ #[derive(Debug)] -pub struct Zip3Data - { source1:watch::Ref, source2:watch::Ref, source3:watch::Ref } -pub type OwnedZip3 = stream::Node >; -pub type Zip3 = stream::WeakNode >; +pub struct All3Data + { src1:watch::Ref, src2:watch::Ref, src3:watch::Ref } +pub type OwnedAll3 = stream::Node >; +pub type All3 = stream::WeakNode >; -impl HasOutput for Zip3Data +impl HasOutput for All3Data where T1:EventOutput, T2:EventOutput, T3:EventOutput { type Output = (Output,Output,Output); } -impl OwnedZip3 +impl OwnedAll3 where T1:EventOutput, T2:EventOutput, T3:EventOutput { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let def = Zip3Data {source1,source2,source3}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let def = All3Data {src1,src2,src3}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1285,49 +1505,49 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput { } } -impl stream::EventConsumer for OwnedZip3 +impl stream::EventConsumer for OwnedAll3 where T1:EventOutput, T2:EventOutput, T3:EventOutput { fn on_event(&self, _:&Out) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); - let value3 = self.source3.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); self.emit_event(&(value1,value2,value3)); } } -impl stream::InputBehaviors for Zip3Data +impl stream::InputBehaviors for All3Data where T1:EventOutput, T2:EventOutput, T3:EventOutput { fn input_behaviors(&self) -> Vec { - vec![Link::mixed(&self.source1), Link::mixed(&self.source2), Link::mixed(&self.source3)] + vec![Link::mixed(&self.src1), Link::mixed(&self.src2), Link::mixed(&self.src3)] } } // ============ -// === Zip4 === +// === All4 === // ============ #[derive(Debug)] -pub struct Zip4Data - {source1:watch::Ref, source2:watch::Ref, source3:watch::Ref, source4:watch::Ref} -pub type OwnedZip4 = stream::Node >; -pub type WeakZip4 = stream::WeakNode >; +pub struct All4Data + {src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, src4:watch::Ref} +pub type OwnedAll4 = stream::Node >; +pub type WeakAll4 = stream::WeakNode >; -impl HasOutput for Zip4Data +impl HasOutput for All4Data where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { type Output = (Output,Output,Output,Output); } -impl OwnedZip4 +impl OwnedAll4 where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let source4 = watch_stream(t4); - let def = Zip4Data {source1,source2,source3,source4}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let src4 = watch_stream(t4); + let def = All4Data {src1,src2,src3,src4}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1338,24 +1558,24 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { } } -impl stream::EventConsumer for OwnedZip4 +impl stream::EventConsumer for OwnedAll4 where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { fn on_event(&self, _:&Out) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); - let value3 = self.source3.value(); - let value4 = self.source4.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); + let value4 = self.src4.value(); self.emit_event(&(value1,value2,value3,value4)); } } -impl stream::InputBehaviors for Zip4Data +impl stream::InputBehaviors for All4Data where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { fn input_behaviors(&self) -> Vec { - vec![ Link::mixed(&self.source1) - , Link::mixed(&self.source2) - , Link::mixed(&self.source3) - , Link::mixed(&self.source4) + vec![ Link::mixed(&self.src1) + , Link::mixed(&self.src2) + , Link::mixed(&self.src3) + , Link::mixed(&self.src4) ] } } @@ -1366,7 +1586,7 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { // === Map === // =========== -pub struct MapData { _source:T, function:F } +pub struct MapData { _src:T, function:F } pub type OwnedMap = stream::Node >; pub type Map = stream::WeakNode >; @@ -1379,8 +1599,8 @@ impl OwnedMap where T:EventOutput, Out:Data, F:'static+Fn(&Output)->Out { /// Constructor. pub fn new(label:Label, src:&T, function:F) -> Self { - let _source = src.clone_ref(); - let definition = MapData {_source,function}; + let _src = src.clone_ref(); + let definition = MapData {_src,function}; Self::construct_and_connect(label,src,definition) } } @@ -1405,7 +1625,7 @@ impl Debug for MapData { // === Map2 === // ============ -pub struct Map2Data { _source1:T1, source2:watch::Ref, function:F } +pub struct Map2Data { _src1:T1, src2:watch::Ref, function:F } pub type OwnedMap2 = stream::Node >; pub type Map2 = stream::WeakNode >; @@ -1418,9 +1638,9 @@ impl OwnedMap2 where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, function:F) -> Self { - let _source1 = t1.clone_ref(); - let source2 = watch_stream(t2); - let def = Map2Data {_source1,source2,function}; + let _src1 = t1.clone_ref(); + let src2 = watch_stream(t2); + let def = Map2Data {_src1,src2,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.into()); @@ -1431,7 +1651,7 @@ where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output impl stream::EventConsumer> for OwnedMap2 where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output)->Out { fn on_event(&self, value1:&Output) { - let value2 = self.source2.value(); + let value2 = self.src2.value(); let out = (self.function)(&value1,&value2); self.emit_event(&out); } @@ -1446,7 +1666,7 @@ impl Debug for Map2Data { impl stream::InputBehaviors for Map2Data where T1:EventOutput, T2:EventOutput { fn input_behaviors(&self) -> Vec { - vec![Link::behavior(&self.source2)] + vec![Link::behavior(&self.src2)] } } @@ -1457,7 +1677,7 @@ where T1:EventOutput, T2:EventOutput { // ============ pub struct Map3Data - { _source1:T1, source2:watch::Ref, source3:watch::Ref, function:F } + { _src1:T1, src2:watch::Ref, src3:watch::Ref, function:F } pub type OwnedMap3 = stream::Node >; pub type Map3 = stream::WeakNode >; @@ -1472,10 +1692,10 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, function:F) -> Self { - let _source1 = t1.clone_ref(); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let def = Map3Data {_source1,source2,source3,function}; + let _src1 = t1.clone_ref(); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let def = Map3Data {_src1,src2,src3,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.into()); @@ -1487,8 +1707,8 @@ impl stream::EventConsumer> for OwnedMap3 where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output)->Out { fn on_event(&self, value1:&Output) { - let value2 = self.source2.value(); - let value3 = self.source3.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); let out = (self.function)(&value1,&value2,&value3); self.emit_event(&out); } @@ -1503,7 +1723,7 @@ impl Debug for Map3Data { impl stream::InputBehaviors for Map3Data where T1:EventOutput, T2:EventOutput, T3:EventOutput { fn input_behaviors(&self) -> Vec { - vec![Link::behavior(&self.source2), Link::behavior(&self.source3)] + vec![Link::behavior(&self.src2), Link::behavior(&self.src3)] } } @@ -1514,8 +1734,8 @@ impl stream::InputBehaviors for Map3Data // ============ pub struct Map4Data - { _source1:T1 - , source2:watch::Ref, source3:watch::Ref, source4:watch::Ref, function:F } + { _src1:T1 + , src2:watch::Ref, src3:watch::Ref, src4:watch::Ref, function:F } pub type OwnedMap4 = stream::Node >; pub type Map4 = stream::WeakNode >; @@ -1530,11 +1750,11 @@ impl OwnedMap4 F:'static+Fn(&Output,&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, function:F) -> Self { - let _source1 = t1.clone_ref(); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let source4 = watch_stream(t4); - let def = Map4Data {_source1,source2,source3,source4,function}; + let _src1 = t1.clone_ref(); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let src4 = watch_stream(t4); + let def = Map4Data {_src1,src2,src3,src4,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.into()); @@ -1546,9 +1766,9 @@ impl stream::EventConsumer> for OwnedMap4,&Output,&Output,&Output)->Out { fn on_event(&self, value1:&Output) { - let value2 = self.source2.value(); - let value3 = self.source3.value(); - let value4 = self.source4.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); + let value4 = self.src4.value(); let out = (self.function)(&value1,&value2,&value3,&value4); self.emit_event(&out); } @@ -1557,9 +1777,9 @@ impl stream::EventConsumer> for OwnedMap4 stream::InputBehaviors for Map4Data where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput { fn input_behaviors(&self) -> Vec { - vec![ Link::behavior(&self.source2) - , Link::behavior(&self.source3) - , Link::behavior(&self.source4) + vec![ Link::behavior(&self.src2) + , Link::behavior(&self.src3) + , Link::behavior(&self.src4) ] } } @@ -1573,25 +1793,25 @@ impl Debug for Map4Data { // ============== -// === Apply2 === +// === AllWith2 === // ============== -pub struct Apply2Data { source1:watch::Ref, source2:watch::Ref, function:F } -pub type OwnedApply2 = stream::Node >; -pub type Apply2 = stream::WeakNode >; +pub struct AllWith2Data { src1:watch::Ref, src2:watch::Ref, function:F } +pub type OwnedAllWith2 = stream::Node >; +pub type AllWith2 = stream::WeakNode >; -impl HasOutput for Apply2Data +impl HasOutput for AllWith2Data where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output)->Out { type Output = Out; } -impl OwnedApply2 +impl OwnedAllWith2 where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, function:F) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let def = Apply2Data {source1,source2,function}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let def = AllWith2Data {src1,src2,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1600,48 +1820,48 @@ where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output } } -impl stream::EventConsumer for OwnedApply2 +impl stream::EventConsumer for OwnedAllWith2 where T1:EventOutput, T2:EventOutput, Out:Data, F:'static+Fn(&Output,&Output)->Out { fn on_event(&self, _:&T) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); let out = (self.function)(&value1,&value2); self.emit_event(&out); } } -impl Debug for Apply2Data { +impl Debug for AllWith2Data { fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f,"Apply2Data") + write!(f,"AllWith2Data") } } // ============== -// === Apply3 === +// === AllWith3 === // ============== -pub struct Apply3Data - { source1:watch::Ref, source2:watch::Ref, source3:watch::Ref, function:F } -pub type OwnedApply3 = stream::Node >; -pub type Apply3 = stream::WeakNode >; +pub struct AllWith3Data + { src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, function:F } +pub type OwnedAllWith3 = stream::Node >; +pub type AllWith3 = stream::WeakNode >; -impl HasOutput for Apply3Data +impl HasOutput for AllWith3Data where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output)->Out { type Output = Out; } -impl OwnedApply3 +impl OwnedAllWith3 where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, function:F) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let def = Apply3Data {source1,source2,source3,function}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let def = AllWith3Data {src1,src2,src3,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1651,52 +1871,52 @@ where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, } } -impl stream::EventConsumer for OwnedApply3 +impl stream::EventConsumer for OwnedAllWith3 where T1:EventOutput, T2:EventOutput, T3:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output)->Out { fn on_event(&self, _:&T) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); - let value3 = self.source3.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); let out = (self.function)(&value1,&value2,&value3); self.emit_event(&out); } } -impl Debug for Apply3Data { +impl Debug for AllWith3Data { fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f,"Apply3Data") + write!(f,"AllWith3Data") } } // ============== -// === Apply4 === +// === AllWith4 === // ============== -pub struct Apply4Data - { source1:watch::Ref, source2:watch::Ref, source3:watch::Ref, source4:watch::Ref +pub struct AllWith4Data + { src1:watch::Ref, src2:watch::Ref, src3:watch::Ref, src4:watch::Ref , function:F } -pub type OwnedApply4 = stream::Node >; -pub type Apply4 = stream::WeakNode >; +pub type OwnedAllWith4 = stream::Node >; +pub type AllWith4 = stream::WeakNode >; -impl HasOutput for Apply4Data +impl HasOutput for AllWith4Data where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output,&Output)->Out { type Output = Out; } -impl OwnedApply4 +impl OwnedAllWith4 where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output,&Output)->Out { /// Constructor. pub fn new(label:Label, t1:&T1, t2:&T2, t3:&T3, t4:&T4, function:F) -> Self { - let source1 = watch_stream(t1); - let source2 = watch_stream(t2); - let source3 = watch_stream(t3); - let source4 = watch_stream(t4); - let def = Apply4Data {source1,source2,source3,source4,function}; + let src1 = watch_stream(t1); + let src2 = watch_stream(t2); + let src3 = watch_stream(t3); + let src4 = watch_stream(t4); + let def = AllWith4Data {src1,src2,src3,src4,function}; let this = Self::construct(label,def); let weak = this.downgrade(); t1.register_target(weak.clone_ref().into()); @@ -1707,21 +1927,21 @@ impl OwnedApply4 } } -impl stream::EventConsumer for OwnedApply4 +impl stream::EventConsumer for OwnedAllWith4 where T1:EventOutput, T2:EventOutput, T3:EventOutput, T4:EventOutput, Out:Data, F:'static+Fn(&Output,&Output,&Output,&Output)->Out { fn on_event(&self, _:&T) { - let value1 = self.source1.value(); - let value2 = self.source2.value(); - let value3 = self.source3.value(); - let value4 = self.source4.value(); + let value1 = self.src1.value(); + let value2 = self.src2.value(); + let value3 = self.src3.value(); + let value4 = self.src4.value(); let out = (self.function)(&value1,&value2,&value3,&value4); self.emit_event(&out); } } -impl Debug for Apply4Data { +impl Debug for AllWith4Data { fn fmt(&self, f:&mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f,"Apply4Data") + write!(f,"AllWith4Data") } } diff --git a/gui/src/rust/lib/graph-editor/src/component.rs b/gui/src/rust/lib/graph-editor/src/component.rs index fd094dc301..e48f94e2b5 100644 --- a/gui/src/rust/lib/graph-editor/src/component.rs +++ b/gui/src/rust/lib/graph-editor/src/component.rs @@ -1,7 +1,11 @@ //! Root module for graph component definitions. -pub mod connection; -pub mod connection2; +pub mod edge; +pub mod edge2; pub mod cursor; pub mod node; pub mod visualization; + +pub use cursor::Cursor; +pub use edge::Edge; +pub use node::Node; diff --git a/gui/src/rust/lib/graph-editor/src/component/connection.rs b/gui/src/rust/lib/graph-editor/src/component/connection.rs deleted file mode 100644 index 0bc0c8635a..0000000000 --- a/gui/src/rust/lib/graph-editor/src/component/connection.rs +++ /dev/null @@ -1,220 +0,0 @@ -//! Definition of the Connection component. - -#![allow(missing_docs)] -// WARNING! UNDER HEAVY DEVELOPMENT. EXPECT DRASTIC CHANGES. - -use crate::prelude::*; - -use enso_frp; -use enso_frp as frp; -use ensogl::data::color; -use ensogl::display::Attribute; -use ensogl::display::Buffer; -use ensogl::display::Sprite; -use ensogl::display::scene::Scene; -use ensogl::display::shape::*; -use ensogl::display::traits::*; -use ensogl::display; -use ensogl::gui::component; - - - -// ================== -// === Connection === -// ================== - -/// Canvas node shape definition. -pub mod shape { - use super::*; - - ensogl::define_shape_system! { - (radius:f32, start_angle:f32, angle:f32) { - let radius = 1.px() * radius; - let width = LINE_WIDTH.px(); - let width2 = width / 2.0; - let ring = Circle(&radius + &width2) - Circle(radius-width2); - let right : Var = (std::f32::consts::PI/2.0).into(); - let rot = right - &angle/2.0; - let mask = Plane().cut_angle_fast(angle).rotate(rot); - let shape = ring * mask; - let shape = shape.fill(color::Rgba::from(color::Lcha::new(0.6,0.5,0.76,1.0))); - shape.into() - } - } -} - - -/// Canvas node shape definition. -pub mod line { - use super::*; - - ensogl::define_shape_system! { - () { - let width = LINE_WIDTH.px(); - let height : Var> = "input_size.y".into(); - let shape = Rect((width,height)); - let shape = shape.fill(color::Rgba::from(color::Lcha::new(0.6,0.5,0.76,1.0))); - shape.into() - } - } -} - - -/// Canvas node shape definition. -pub mod helper { - use super::*; - - ensogl::define_shape_system! { - () { - let shape = Circle(2.px()); - let shape = shape.fill(color::Rgba::new(1.0,0.0,0.0,1.0)); - shape.into() - } - } -} - - -const LINE_WIDTH : f32 = 4.0; -const PADDING : f32 = 5.0; - - - -// ================== -// === Connection === -// ================== - -/// Connection definition. -#[derive(AsRef,Clone,CloneRef,Debug,Deref)] -pub struct Connection { - data : Rc, -} - -impl AsRef for Connection { - fn as_ref(&self) -> &Self { - self - } -} - - -#[derive(Clone,CloneRef,Debug)] -pub struct InputEvents { - pub network : frp::Network, - pub source_width : frp::Source, - pub target_position : frp::Source, -} - -impl InputEvents { - pub fn new() -> Self { - frp::new_network! { network - def source_width = source(); - def target_position = source(); - } - Self {network,source_width,target_position} - } -} - -impl Default for InputEvents { - fn default() -> Self { - Self::new() - } -} - - -/// Internal data of `Connection` -#[derive(Debug)] -#[allow(missing_docs)] -pub struct ConnectionData { - pub object : display::object::Instance, - pub logger : Logger, - pub events : InputEvents, - pub corner : component::ShapeView, - pub side_line : component::ShapeView, - pub main_line : component::ShapeView, - pub source_width : Rc>, - pub target_position : Rc>, -} - -impl Connection { - /// Constructor. - pub fn new(scene:&Scene) -> Self { - let logger = Logger::new("edge"); - let object = display::object::Instance::new(&logger); - - let corner = component::ShapeView::::new(&logger.sub("corner"),scene); - let side_line = component::ShapeView::::new(&logger.sub("side_line"),scene); - let main_line = component::ShapeView::::new(&logger.sub("main_line"),scene); - object.add_child(&corner); - object.add_child(&side_line); - object.add_child(&main_line); - side_line.mod_rotation(|r| r.z = std::f32::consts::PI/2.0); - - let input = InputEvents::new(); - let network = &input.network; - - let source_width : Rc> = default(); - let target_position = Rc::new(Cell::new(frp::Position::default())); - source_width.set(100.0); - - frp::extend! { network - eval input.target_position ((t) target_position.set(*t)); - eval input.source_width ((t) source_width.set(*t)); - on_change <-_ [input.source_width,input.target_position]; - eval_ on_change ([source_width,target_position,object,side_line,main_line,corner] { - let target = target_position.get(); - let target = Vector2::new(target.x - object.position().x, target.y - object.position().y); - let radius = 14.0; - let width = source_width.get() / 2.0; - - let side_circle_x = width - radius; - let side = target.x.signum(); - let target = Vector2::new(target.x.abs(),target.y); - - let corner_grow = ((target.x - width) * 0.6).max(0.0); - let corner_radius = 20.0 + corner_grow; - let corner_radius = corner_radius.min(target.y.abs()); - let corner_x = target.x - corner_radius; - - - let x = (corner_x - side_circle_x).clamp(-corner_radius,radius); - let y = (radius*radius + corner_radius*corner_radius - x*x).sqrt(); - - - let angle1 = f32::atan2(y,x); - let angle2 = f32::atan2(radius,corner_radius); - let corner_angle = std::f32::consts::PI - angle1 - angle2; - let angle_overlap = if corner_x > width { 0.0 } else { 0.1 }; - - corner.shape.angle.set((corner_angle + angle_overlap) * side); - - - let corner_y = - y; - let corner_side = (corner_radius + PADDING) * 2.0; - corner.shape.sprite.size().set(Vector2::new(corner_side,corner_side)); - corner.shape.radius.set(corner_radius); - corner.mod_position(|t| t.x = corner_x * side); - corner.mod_position(|t| t.y = corner_y); - - let line_overlap = 2.0; - side_line.shape.sprite.size().set(Vector2::new(10.0,corner_x - width + line_overlap)); - side_line.mod_position(|p| p.x = side*(width + corner_x)/2.0); - - main_line.shape.sprite.size().set(Vector2::new(10.0,corner_y - target.y + line_overlap)); - main_line.mod_position(|p| { - p.x = side * target.x; - p.y = (target.y + corner_y) / 2.0; - }); - }); - } - - let events = input; - let data = Rc::new(ConnectionData {object,logger,events,corner,side_line,main_line - ,source_width,target_position}); - Self {data} - } -} - -impl display::Object for Connection { - fn display_object(&self) -> &display::object::Instance { - &self.object - } -} diff --git a/gui/src/rust/lib/graph-editor/src/component/cursor.rs b/gui/src/rust/lib/graph-editor/src/component/cursor.rs index 58594f4550..5b02bfe04c 100644 --- a/gui/src/rust/lib/graph-editor/src/component/cursor.rs +++ b/gui/src/rust/lib/graph-editor/src/component/cursor.rs @@ -16,32 +16,101 @@ use ensogl::display::{Sprite, Attribute}; use ensogl::display; use ensogl::gui::component::animation; use ensogl::gui::component::animation2; +use ensogl::gui::component::animator; use ensogl::gui::component; use ensogl::system::web; + #[derive(Debug,Clone)] -pub enum Mode { - Normal, - Cursor, - Highlight { - host : display::object::Instance, - position : Vector2, - size : Vector2, - } +pub struct StyleParam { + pub value : T, + pub animate : bool, } -impl Mode { - pub fn highlight(host:H, position:Vector2, size:Vector2) -> Self - where H:display::Object { - let host = host.display_object().clone_ref(); - Self::Highlight {host,position,size} - } -} - -impl Default for Mode { +impl Default for StyleParam { fn default() -> Self { - Self::Normal + let value = default(); + let animate = true; + Self {value,animate} + } +} + +impl StyleParam { + pub fn new(value:T) -> Self { + let animate = true; + Self {value,animate} + } + + pub fn new_no_animation(value:T) -> Self { + let animate = false; + Self {value,animate} + } +} + + +#[derive(Debug,Clone,Default)] +pub struct Style { + host : Option, + size : Option>>, + offset : Option>>, + color : Option>, + radius : Option, + press : Option, +} + +impl Style { + pub fn highlight + (host:H, size:Vector2, color:Option) -> Self + where H:display::Object { + let host = Some(host.display_object().clone_ref()); + let size = Some(StyleParam::new(size)); + let color = color.map(StyleParam::new); + Self {host,size,color,..default()} + } + + pub fn color(color:color::Lcha) -> Self { + let color = Some(StyleParam::new(color)); + Self {color,..default()} + } + + pub fn color_no_animation(color:color::Lcha) -> Self { + let color = Some(StyleParam::new_no_animation(color)); + Self {color,..default()} + } + + pub fn selection(size:Vector2) -> Self { + let offset = Some(StyleParam::new_no_animation(-size / 2.0)); + let size = Some(StyleParam::new_no_animation(size.abs() + Vector2::new(16.0,16.0))); + Self {size,offset,..default()} + } + + pub fn pressed() -> Self { + let press = Some(1.0); + Self {press,..default()} + } + + pub fn press(mut self) -> Self { + self.press = Some(1.0); + self + } +} + +impl PartialSemigroup<&Style> for Style { + #[allow(clippy::clone_on_copy)] + fn concat_mut(&mut self, other:&Self) { + if self.host . is_none() { self.host = other.host . clone() } + if self.size . is_none() { self.size = other.size . clone() } + if self.offset . is_none() { self.offset = other.offset . clone() } + if self.color . is_none() { self.color = other.color . clone() } + if self.radius . is_none() { self.radius = other.radius . clone() } + if self.press . is_none() { self.press = other.press . clone() } + } +} + +impl PartialSemigroup