diff --git a/.gitignore b/.gitignore index be82bc7d5..6a2245c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ app/profile.json app/_cache app/_build app/resources/locale/**/*.json +demo/*.v diff --git a/.npmrc b/.npmrc index 1b2e19ef3..f142fc0bd 100644 --- a/.npmrc +++ b/.npmrc @@ -1,2 +1 @@ loglevel="error" -nwjs_build_type="normal" diff --git a/README.md b/README.md index 99fd33c85..38f932ff8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ [![License](http://img.shields.io/:license-gpl-blue.svg)](http://opensource.org/licenses/GPL-2.0) -[![Documentation Status](https://readthedocs.org/projects/icestudio/badge/?version=stable)](http://icestudio.readthedocs.io/en/stable/) +[![Documentation Status](https://readthedocs.org/projects/icestudio/badge/?version=latest)](http://icestudio.readthedocs.io/en/latest) +[![Documentation Status](https://readthedocs.org/projects/icestudio/badge/?version=stable)](http://icestudio.readthedocs.io/en/stable) **Experimental** graphic editor for open FPGAs. Built on top of the [icestorm project](http://www.clifford.at/icestorm/). @@ -17,25 +18,31 @@ Supported boards: * [icoBOARD 1.0](http://icoboard.org/about-icoboard.html) * [Kéfir I](http://fpgalibre.sourceforge.net/Kefir/) -## Version 0.2.3 +Supported operating systems: + +* GNU/Linux +* Windows +* Mac OS X + +## Version 0.3.0-beta2 (latest) ### Installation 1. Install [Python 2.7](https://www.python.org) -2. Download the [release](https://github.com/FPGAwars/icestudio/releases), unzip and execute **icestudio** +2. Download the [release](https://github.com/FPGAwars/icestudio/releases/tag/0.3.0-beta2), unzip and execute **icestudio** -**Documentation: http://icestudio.readthedocs.io** +Documentation: http://icestudio.readthedocs.io/en/latest -Supported on Linux, Windows and Mac OSX. +NOTE: if you want to add blocks or examples, please contribute to [icestudio-blocks](https://github.com/FPGAwars/icestudio-blocks) or [icestudio-examples](https://github.com/FPGAwars/icestudio-examples). - + ## Development -Install [Python 2.7](https://www.python.org/downloads/release/python-2711/) +Install [Python 2.7](https://www.python.org/downloads/release/python-2711/) and [nodejs](https://github.com/nodejs/node). -Install [nodejs](https://github.com/nodejs/node) +Using [Atom](https://atom.io/) editor with [linter-jshint](https://atom.io/packages/linter-jshint). ##### Ubuntu @@ -77,9 +84,9 @@ NOTE: in Mac OS X this command also generates a **dmg** package. |:----------:|:------------------------------------------:| | English | ![Progress](http://progressed.io/bar/100) | | Spanish | ![Progress](http://progressed.io/bar/100) | -| French | ![Progress](http://progressed.io/bar/84) | -| Basque | ![Progress](http://progressed.io/bar/69) | -| Galician | ![Progress](http://progressed.io/bar/67) | +| Basque | ![Progress](http://progressed.io/bar/88) | +| French | ![Progress](http://progressed.io/bar/72) | +| Galician | ![Progress](http://progressed.io/bar/47) | **Contribute**: add or update the [translations](https://github.com/FPGAwars/icestudio/tree/develop/app/resources/locale) by following the [next instructions](https://angular-gettext.rocketeer.be/dev-guide/translate/#poedit). @@ -93,6 +100,17 @@ There is a [Wishlist](https://github.com/FPGAwars/icestudio/wiki/Wishlist:-propo We use the GitHub issues to schedule our new features and improvements. +## Version 0.2.3 (stable) + +### Installation + +1. Install [Python 2.7](https://www.python.org) + +2. Download the [release](https://github.com/FPGAwars/icestudio/releases/tag/0.2.3), unzip and execute **icestudio** + +Documentation: http://icestudio.readthedocs.io/en/stable + + ## Version 0.1 @@ -121,6 +139,11 @@ There is a [Wishlist](https://github.com/FPGAwars/icestudio/wiki/Wishlist:-propo ## Contributors +* v0.3 + * [Martoni](https://github.com/Martoni) + * [Carlos Díaz](https://github.com/C47D) + * [Lorea-Aldabaldetreku](https://github.com/Lorea-Aldabaldetreku) + * v0.2 * [Tomás Calvo](https://github.com/tocalvo) * [Juan González (Obijuan)](https://github.com/Obijuan) @@ -129,12 +152,13 @@ There is a [Wishlist](https://github.com/FPGAwars/icestudio/wiki/Wishlist:-propo * [Salvador E. Tropea](https://github.com/set-soft) * [Democrito](https://github.com/Democrito) * [Martoni](https://github.com/Martoni) + * [Pascal Cotret](https://github.com/pcotret) * v0.1 * [Miguel Sánchez de León Peque](https://github.com/Peque) ## Credits -* v0.2: using [JointJS](https://github.com/clientIO/joint) +* v0.3, v0.2: using [JointJS](https://github.com/clientIO/joint) and [AlertifyJS](https://github.com/MohammadYounes/AlertifyJS) * v0.1: using [AngularJS-Flowchart](https://github.com/codecapers/AngularJS-FlowChart) * Sponsored by [BQ](https://www.bq.com) diff --git a/app/.jshintrc b/app/.jshintrc new file mode 100644 index 000000000..173f232e2 --- /dev/null +++ b/app/.jshintrc @@ -0,0 +1,39 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": false, + "newcap": true, + "noarg": true, + "quotmark": "single", + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "multistr": true, + "-W064": true, + "-W069": true, + "-W084": true, + "globals": { + "$": false, + "angular": false, + "console": false, + "alertify": false, + "joint": false, + "_": false, + "svgPanZoom": false, + "Backbone": false, + "async": false, + "gettext": false, + "ace": false, + "g": false, + "V": false + } +} diff --git a/app/bower.json b/app/bower.json index a5d073a3b..5d85acf9e 100644 --- a/app/bower.json +++ b/app/bower.json @@ -21,9 +21,7 @@ "tests" ], "dependencies": { - "angular": "^1.5.5", - "angular-translate": "^2.11.0", - "angular-translate-loader-static-files": "^2.11.0", + "angular": "^1.6.0", "angular-route": "^1.5.5", "jquery": "^2.0.3", "backbone": "^1.2.1", diff --git a/app/index.html b/app/index.html index 611823b6a..1587487d7 100644 --- a/app/index.html +++ b/app/index.html @@ -2,74 +2,74 @@ - Icestudio - - - - - - - - - - - - - - - + Icestudio + + + + + + + + + + + + + + + -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/package.json b/app/package.json index 0f1242a9e..db4d53c43 100644 --- a/app/package.json +++ b/app/package.json @@ -1,14 +1,15 @@ { "name": "icestudio", - "version": "0.2.3", + "version": "0.3.0-beta2", "description": "Experimental graphic editor for open FPGAs", "author": "Jesús Arroyo Torrens ", "repository": "https://github.com/FPGAwars/icestudio", "license": "GPL-2.0", "main": "index.html", + "single-instance": false, "window": { "width": 900, - "height": 600, + "height": 620, "min_width": 800, "min_height": 200, "toolbar": false, @@ -36,7 +37,9 @@ "sha1": "^1.1.1", "ssh-exec": "^2.0.0", "sudo-prompt": "^6.2.0", - "tarball-extract": "0.0.3" + "svgo": "^0.7.1", + "tarball-extract": "0.0.3", + "unzip": "^0.1.11" }, "readme": "../README.md", "keywords": [ diff --git a/app/resources/blocks/bit/0.ice b/app/resources/blocks/bit/0.ice new file mode 100644 index 000000000..e8fa3794f --- /dev/null +++ b/app/resources/blocks/bit/0.ice @@ -0,0 +1,76 @@ +{ + "version": "1.1", + "package": { + "name": "Bit 0", + "version": "1.0.0", + "description": "Assign 0 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.37%22%20y=%22315.373%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.37%22%20y=%22315.373%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E0%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 0\n\nassign v = 1'b0;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 + } + }, + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 608, + "y": 192 + } + } + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/bit/0.iceb b/app/resources/blocks/bit/0.iceb deleted file mode 100644 index f223d7ffe..000000000 --- a/app/resources/blocks/bit/0.iceb +++ /dev/null @@ -1,55 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 0\n\nassign v = 1'b0;", - "ports": { - "in": [], - "out": [ - "v" - ] - } - }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 608, - "y": 192 - } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/0.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/blocks/bit/1.ice b/app/resources/blocks/bit/1.ice new file mode 100644 index 000000000..91ec7a7da --- /dev/null +++ b/app/resources/blocks/bit/1.ice @@ -0,0 +1,76 @@ +{ + "version": "1.1", + "package": { + "name": "Bit 1", + "version": "1.0.0", + "description": "Assign 1 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.218%22%20y=%22315.455%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.218%22%20y=%22315.455%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E1%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 1\n\nassign v = 1'b1;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 + } + }, + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 608, + "y": 192 + } + } + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/bit/1.iceb b/app/resources/blocks/bit/1.iceb deleted file mode 100644 index a8048566b..000000000 --- a/app/resources/blocks/bit/1.iceb +++ /dev/null @@ -1,55 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 1\n\nassign v = 1'b1;", - "ports": { - "in": [], - "out": [ - "v" - ] - } - }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 608, - "y": 192 - } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/1.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/blocks/config/pull_up.ice b/app/resources/blocks/config/pull_up.ice new file mode 100644 index 000000000..9a9ce030f --- /dev/null +++ b/app/resources/blocks/config/pull_up.ice @@ -0,0 +1,111 @@ +{ + "version": "1.1", + "package": { + "name": "Pull up", + "version": "1.0.0", + "description": "FPGA internal pull up configuration on the connected input port", + "author": "Juan González", + "image": "%3Csvg%20id=%22svg2%22%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-265%20401.5%2063.5%2038.4%22%3E%3Cstyle%3E.st0%7Bdisplay:none%7D.st1%7Bfill:none;stroke:#000;stroke-width:.75;stroke-linejoin:round;stroke-miterlimit:10%7D.st2%7Bfill:#010002%7D%3C/style%3E%3Cpath%20class=%22st0%22%20d=%22M-242.5%20411.8v11.8h-5.4v-11.8h5.4m1-1h-7.4v13.8h7.4v-13.8z%22/%3E%3Cpath%20d=%22M-212%20425.6l-15.4-8.7v8.5h-17.4v-2.7c0-.2-.1-.4-.3-.4l-2.3-1.2%205.6-2.9c.2-.1.3-.3.3-.5s-.1-.4-.3-.4l-5.7-2.7%202.4-1.6c.1-.1.2-.2.2-.4v-2.7h3.1l-3.5-6.1-3.5%206.1h3v2.5l-2.9%202c-.1.1-.2.3-.2.5s.1.3.3.4l5.6%202.6-5.6%202.9c-.2.1-.3.3-.3.4s.1.4.3.4l2.9%201.5V425.5H-265v1.2h37.6v8.5l15.4-8.7h10.5v-.8H-212zm-33.3-20.4l2.2%203.9h-4.5l2.3-3.9zm19.2%2027.7v-13.8l12.3%206.9-12.3%206.9z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "config": "true", + "pullup": "true", + "graph": { + "blocks": [ + { + "id": "2b245a71-2d80-466b-955f-e3d61839fe25", + "type": "basic.code", + "data": { + "code": "// Pull up\n\nwire din, dout, outen;\n\nassign o = din;\n\nSB_IO #(\n .PIN_TYPE(6'b 1010_01),\n .PULLUP(1'b 1)\n) io_pin (\n .PACKAGE_PIN(i),\n .OUTPUT_ENABLE(outen),\n .D_OUT_0(dout),\n .D_IN_0(din)\n);", + "params": [], + "ports": { + "in": [ + { + "name": "i" + } + ], + "out": [ + { + "name": "o" + } + ] + } + }, + "position": { + "x": 256, + "y": 104 + } + }, + { + "id": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 200 + } + }, + { + "id": "a139fa0d-9b45-4480-a251-f4a66b49aa23", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 200 + } + } + ], + "wires": [ + { + "source": { + "block": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", + "port": "out" + }, + "target": { + "block": "2b245a71-2d80-466b-955f-e3d61839fe25", + "port": "i" + } + }, + { + "source": { + "block": "2b245a71-2d80-466b-955f-e3d61839fe25", + "port": "o" + }, + "target": { + "block": "a139fa0d-9b45-4480-a251-f4a66b49aa23", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} diff --git a/app/resources/blocks/config/pull_up.iceb b/app/resources/blocks/config/pull_up.iceb deleted file mode 100644 index 06e5ec841..000000000 --- a/app/resources/blocks/config/pull_up.iceb +++ /dev/null @@ -1,78 +0,0 @@ -{ - "image": "resources/images/pull_up.svg", - "state": { - "pan": { - "x": -23, - "y": 8 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "2b245a71-2d80-466b-955f-e3d61839fe25", - "type": "basic.code", - "data": { - "code": "// Pull up\n\nwire din, dout, outen;\n\nassign o = din;\n\nSB_IO #(\n .PIN_TYPE(6'b 1010_01),\n .PULLUP(1'b 1)\n) io_pin (\n .PACKAGE_PIN(i),\n .OUTPUT_ENABLE(outen),\n .D_OUT_0(dout),\n .D_IN_0(din)\n);", - "ports": { - "in": [ - "i" - ], - "out": [ - "o" - ] - } - }, - "position": { - "x": 256, - "y": 104 - } - }, - { - "id": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 200 - } - }, - { - "id": "a139fa0d-9b45-4480-a251-f4a66b49aa23", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 760, - "y": 200 - } - } - ], - "wires": [ - { - "source": { - "block": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", - "port": "out" - }, - "target": { - "block": "2b245a71-2d80-466b-955f-e3d61839fe25", - "port": "i" - } - }, - { - "source": { - "block": "2b245a71-2d80-466b-955f-e3d61839fe25", - "port": "o" - }, - "target": { - "block": "a139fa0d-9b45-4480-a251-f4a66b49aa23", - "port": "in" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/config/pull_up_inv.ice b/app/resources/blocks/config/pull_up_inv.ice new file mode 100644 index 000000000..1871d6862 --- /dev/null +++ b/app/resources/blocks/config/pull_up_inv.ice @@ -0,0 +1,111 @@ +{ + "version": "1.1", + "package": { + "name": "Pull up inv", + "version": "1.0.0", + "description": "FPGA internal pull up configuration on the connected input port plus a logic inverter", + "author": "Juan González", + "image": "%3Csvg%20id=%22svg2%22%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-265%20401.5%2063.5%2038.4%22%3E%3Cstyle%3E.st0%7Bdisplay:none%7D.st1%7Bfill:none;stroke:#000;stroke-width:.75;stroke-linejoin:round;stroke-miterlimit:10%7D.st2%7Bfill:#010002%7D%3C/style%3E%3Cpath%20class=%22st0%22%20d=%22M-242.5%20411.8v11.8h-5.4v-11.8h5.4m1-1h-7.4v13.8h7.4v-13.8z%22/%3E%3Cpath%20d=%22M-207.6%20425.4c-.3-.9-1.1-1.6-2.1-1.6-1.1%200-2%20.8-2.2%201.8l-15.4-8.7v8.5h-17.4v-2.7c0-.2-.1-.4-.3-.4l-2.3-1.2%205.6-2.9c.2-.1.3-.3.3-.5s-.1-.4-.3-.4l-5.7-2.7%202.4-1.6c.1-.1.2-.2.2-.4v-2.7h3.1l-3.5-6.1-3.5%206.1h3v2.5l-2.9%202c-.1.1-.2.3-.2.5s.1.3.3.4l5.6%202.6-5.6%202.9c-.2.1-.3.3-.3.4s.1.4.3.4l2.9%201.5V425.5H-265v1.2h37.6v8.5l15.4-8.7c.2%201%201.1%201.8%202.2%201.8%201%200%201.9-.7%202.1-1.6h6.1v-1.2h-6zm-37.7-20.2l2.2%203.9h-4.5l2.3-3.9zm19.2%2027.7v-13.8l12.3%206.9-12.3%206.9zm16.3-5.5c-.8%200-1.4-.6-1.4-1.4%200-.8.6-1.4%201.4-1.4s1.4.6%201.4%201.4c0%20.8-.6%201.4-1.4%201.4z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "config": "true", + "pullup": "true", + "graph": { + "blocks": [ + { + "id": "2b245a71-2d80-466b-955f-e3d61839fe25", + "type": "basic.code", + "data": { + "code": "// Pull up inv\n\nwire din, dout, outen;\n\nassign o = ~din;\n\nSB_IO #(\n .PIN_TYPE(6'b 1010_01),\n .PULLUP(1'b 1)\n) io_pin (\n .PACKAGE_PIN(i),\n .OUTPUT_ENABLE(outen),\n .D_OUT_0(dout),\n .D_IN_0(din)\n);", + "params": [], + "ports": { + "in": [ + { + "name": "i" + } + ], + "out": [ + { + "name": "o" + } + ] + } + }, + "position": { + "x": 256, + "y": 104 + } + }, + { + "id": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 200 + } + }, + { + "id": "a139fa0d-9b45-4480-a251-f4a66b49aa23", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 200 + } + } + ], + "wires": [ + { + "source": { + "block": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", + "port": "out" + }, + "target": { + "block": "2b245a71-2d80-466b-955f-e3d61839fe25", + "port": "i" + } + }, + { + "source": { + "block": "2b245a71-2d80-466b-955f-e3d61839fe25", + "port": "o" + }, + "target": { + "block": "a139fa0d-9b45-4480-a251-f4a66b49aa23", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} diff --git a/app/resources/blocks/config/pull_up_inv.iceb b/app/resources/blocks/config/pull_up_inv.iceb deleted file mode 100644 index b2089d065..000000000 --- a/app/resources/blocks/config/pull_up_inv.iceb +++ /dev/null @@ -1,78 +0,0 @@ -{ - "image": "resources/images/pull_up_inv.svg", - "state": { - "pan": { - "x": -23, - "y": 8 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "2b245a71-2d80-466b-955f-e3d61839fe25", - "type": "basic.code", - "data": { - "code": "// Pull up inv\n\nwire din, dout, outen;\n\nassign o = ~din;\n\nSB_IO #(\n .PIN_TYPE(6'b 1010_01),\n .PULLUP(1'b 1)\n) io_pin (\n .PACKAGE_PIN(i),\n .OUTPUT_ENABLE(outen),\n .D_OUT_0(dout),\n .D_IN_0(din)\n);", - "ports": { - "in": [ - "i" - ], - "out": [ - "o" - ] - } - }, - "position": { - "x": 256, - "y": 104 - } - }, - { - "id": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 200 - } - }, - { - "id": "a139fa0d-9b45-4480-a251-f4a66b49aa23", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 760, - "y": 200 - } - } - ], - "wires": [ - { - "source": { - "block": "bb4a1ca9-1b30-471e-92ca-ca7ff2fc1150", - "port": "out" - }, - "target": { - "block": "2b245a71-2d80-466b-955f-e3d61839fe25", - "port": "i" - } - }, - { - "source": { - "block": "2b245a71-2d80-466b-955f-e3d61839fe25", - "port": "o" - }, - "target": { - "block": "a139fa0d-9b45-4480-a251-f4a66b49aa23", - "port": "in" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/config/tri_state.ice b/app/resources/blocks/config/tri_state.ice new file mode 100644 index 000000000..337e9381e --- /dev/null +++ b/app/resources/blocks/config/tri_state.ice @@ -0,0 +1,174 @@ +{ + "version": "1.1", + "package": { + "name": "Tri state", + "version": "1.0.0", + "description": "Tri-state logic block", + "author": "Salvador E. Tropea", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-265%20401.5%2063.5%2038.4%22%20id=%22svg2%22%3E%3Cstyle%20id=%22style3%22/%3E%3Cpath%20d=%22M-9.78%203.538l-4.214%2024.984-19.53-16.141z%22%20transform=%22matrix(.62422%20-.11476%20.1058%20.67701%20-219.33%20413.046)%22%20id=%22path3008%22%20fill=%22none%22%20stroke=%22#0b0b0b%22%20stroke-width=%221.885%22/%3E%3Cpath%20d=%22M-9.78%203.538l-4.214%2024.984-19.53-16.141z%22%20transform=%22matrix(-.62422%20-.11476%20-.1058%20.67701%20-244.991%20400.53)%22%20id=%22path3008-6%22%20fill=%22none%22%20stroke=%22#0b0b0b%22%20stroke-width=%221.885%22/%3E%3Cpath%20d=%22M40.154%2011.247H63.74%22%20transform=%22translate(-265%20401.5)%22%20id=%22path3800%22%20fill=%22none%22%20stroke=%22#000%22/%3E%3Cpath%20d=%22M25.945%2023.73l-7.364.058V11.305h7.076%22%20transform=%22translate(-265%20401.5)%22%20id=%22path3802%22%20fill=%22none%22%20stroke=%22#000%22/%3E%3Cpath%20d=%22M-265.029%20412.747l18.582.058%22%20id=%22path3804%22%20fill=%22none%22%20stroke=%22#000%22/%3E%3Cpath%20d=%22M.081%2023.919h12.936v7.566h19.037V27.58%22%20transform=%22translate(-265%20401.5)%22%20id=%22path3806%22%20fill=%22none%22%20stroke=%22#000%22/%3E%3Cpath%20d=%22M0%2035.96h49.302V24.162h-9.356%22%20transform=%22translate(-265%20401.5)%22%20id=%22path3812%22%20fill=%22none%22%20stroke=%22#000%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "config": "true", + "graph": { + "blocks": [ + { + "id": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", + "type": "basic.code", + "data": { + "code": " SB_IO #(\n .PIN_TYPE(6'b1010_01),\n .PULLUP(1'b0)\n ) triState (\n .PACKAGE_PIN(pin),\n .OUTPUT_ENABLE(oe),\n .D_OUT_0(din),\n .D_IN_0(dout)\n );", + "params": [], + "ports": { + "in": [ + { + "name": "pin" + }, + { + "name": "oe" + }, + { + "name": "din" + } + ], + "out": [ + { + "name": "dout" + } + ] + } + }, + "position": { + "x": 248, + "y": 32 + } + }, + { + "id": "076fd025-aa42-4f23-ae97-b65aec2298ce", + "type": "basic.input", + "data": { + "name": "pin", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 32, + "y": 40 + } + }, + { + "id": "f96a1baf-fc8b-4c25-b132-12552605743f", + "type": "basic.input", + "data": { + "name": "oe", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 32, + "y": 128 + } + }, + { + "id": "0b2a85b3-b6ac-4e8a-8b16-dd5a195fb058", + "type": "basic.output", + "data": { + "name": "dout", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 128 + } + }, + { + "id": "04fdb7a7-2740-4ff1-ad26-56407ef5b958", + "type": "basic.input", + "data": { + "name": "din", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 32, + "y": 216 + } + } + ], + "wires": [ + { + "source": { + "block": "076fd025-aa42-4f23-ae97-b65aec2298ce", + "port": "out" + }, + "target": { + "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", + "port": "pin" + } + }, + { + "source": { + "block": "f96a1baf-fc8b-4c25-b132-12552605743f", + "port": "out" + }, + "target": { + "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", + "port": "oe" + } + }, + { + "source": { + "block": "04fdb7a7-2740-4ff1-ad26-56407ef5b958", + "port": "out" + }, + "target": { + "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", + "port": "din" + } + }, + { + "source": { + "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", + "port": "dout" + }, + "target": { + "block": "0b2a85b3-b6ac-4e8a-8b16-dd5a195fb058", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} diff --git a/app/resources/blocks/config/tri_state.iceb b/app/resources/blocks/config/tri_state.iceb deleted file mode 100644 index 5e8d9f473..000000000 --- a/app/resources/blocks/config/tri_state.iceb +++ /dev/null @@ -1,122 +0,0 @@ -{ - "image": "resources/images/tri_state.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", - "type": "basic.code", - "data": { - "code": " SB_IO #(\n .PIN_TYPE(6'b1010_01),\n .PULLUP(1'b0)\n ) triState (\n .PACKAGE_PIN(pin),\n .OUTPUT_ENABLE(oe),\n .D_OUT_0(din),\n .D_IN_0(dout)\n );", - "ports": { - "in": [ - "pin", - "oe", - "din" - ], - "out": [ - "dout" - ] - } - }, - "position": { - "x": 248, - "y": 32 - } - }, - { - "id": "076fd025-aa42-4f23-ae97-b65aec2298ce", - "type": "basic.input", - "data": { - "label": "pin" - }, - "position": { - "x": 32, - "y": 40 - } - }, - { - "id": "f96a1baf-fc8b-4c25-b132-12552605743f", - "type": "basic.input", - "data": { - "label": "oe" - }, - "position": { - "x": 32, - "y": 128 - } - }, - { - "id": "04fdb7a7-2740-4ff1-ad26-56407ef5b958", - "type": "basic.input", - "data": { - "label": "din" - }, - "position": { - "x": 32, - "y": 216 - } - }, - { - "id": "0b2a85b3-b6ac-4e8a-8b16-dd5a195fb058", - "type": "basic.output", - "data": { - "label": "dout" - }, - "position": { - "x": 760, - "y": 128 - } - } - ], - "wires": [ - { - "source": { - "block": "076fd025-aa42-4f23-ae97-b65aec2298ce", - "port": "out" - }, - "target": { - "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", - "port": "pin" - } - }, - { - "source": { - "block": "f96a1baf-fc8b-4c25-b132-12552605743f", - "port": "out" - }, - "target": { - "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", - "port": "oe" - } - }, - { - "source": { - "block": "04fdb7a7-2740-4ff1-ad26-56407ef5b958", - "port": "out" - }, - "target": { - "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", - "port": "din" - } - }, - { - "source": { - "block": "5c8e9a35-33e7-46ef-a0cc-cc27edcc99c0", - "port": "dout" - }, - "target": { - "block": "0b2a85b3-b6ac-4e8a-8b16-dd5a195fb058", - "port": "in" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/labels.js b/app/resources/blocks/labels.js index f7209d3f2..f45415c3d 100644 --- a/app/resources/blocks/labels.js +++ b/app/resources/blocks/labels.js @@ -1,56 +1,58 @@ // In this file the blocks labels are annotated for translation /// Bit -gettext('bit') +gettext('bit'); /// Config -gettext('config') +gettext('config'); /// Pull up -gettext('pull_up') +gettext('pull_up'); /// Pull up inv -gettext('pull_up_inv') +gettext('pull_up_inv'); /// Tri-state -gettext('tri_state') +gettext('tri_state'); /// Logic -gettext('logic') +gettext('logic'); /// Combinational -gettext('combinational') +gettext('combinational'); /// Demux 1:2 -gettext('demux_1_2') +gettext('demux_1_2'); /// Demux 1:4 -gettext('demux_1_4') +gettext('demux_1_4'); /// Demux 1:8 -gettext('demux_1_8') +gettext('demux_1_8'); /// Hex 7 Segment CC -gettext('hex_7seg_cc') +gettext('hex_7seg_cc'); /// Hex 7 Segment CA -gettext('hex_7seg_ca') +gettext('hex_7seg_ca'); /// Mux 2:1 -gettext('mux_2_1') +gettext('mux_2_1'); /// Mux 4:1 -gettext('mux_4_1') +gettext('mux_4_1'); /// Gate -gettext('gate') +gettext('gate'); /// And -gettext('and') +gettext('and'); /// Nand -gettext('nand') +gettext('nand'); /// Nor -gettext('nor') +gettext('nor'); /// Not -gettext('not') +gettext('not'); /// Or -gettext('or') +gettext('or'); /// Xnor -gettext('xnor') +gettext('xnor'); /// Xor -gettext('xor') +gettext('xor'); /// Sequential -gettext('sequential') +gettext('sequential'); /// D flip-flop async -gettext('dff_ar') +gettext('dff_ar'); /// D flip-flop async -gettext('dff_sr') +gettext('dff_sr'); /// T flip-flop async -gettext('tff_ar') +gettext('tff_ar'); /// T flip-flop -gettext('tff_sr') +gettext('tff_sr'); +/// Debouncer +gettext('debouncer'); diff --git a/app/resources/blocks/logic/combinational/demux_1_2.ice b/app/resources/blocks/logic/combinational/demux_1_2.ice new file mode 100644 index 000000000..bf21af960 --- /dev/null +++ b/app/resources/blocks/logic/combinational/demux_1_2.ice @@ -0,0 +1,173 @@ +{ + "version": "1.1", + "package": { + "name": "Demux 1:2", + "version": "1.0.0", + "description": "Demultiplexer 1:2", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20421.9h24v7.3l41%2011.7v-9h25v-2h-25v-18h25v-2h-25v-9l-41%2011.8v7.2h-24v2zm26%205.7v-13.5l37-10.8v35l-37-10.7z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "c8fdb023-d458-4657-899c-5749a256be09", + "type": "basic.code", + "data": { + "code": "assign {out1,out0} = in0 << sel0;", + "params": [], + "ports": { + "in": [ + { + "name": "in0" + }, + { + "name": "sel0" + } + ], + "out": [ + { + "name": "out0" + }, + { + "name": "out1" + } + ] + } + }, + "position": { + "x": 248, + "y": 88 + } + }, + { + "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "type": "basic.input", + "data": { + "name": "i", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 120 + } + }, + { + "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "type": "basic.output", + "data": { + "name": "o0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 120 + } + }, + { + "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "type": "basic.input", + "data": { + "name": "sel", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 248 + } + }, + { + "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "type": "basic.output", + "data": { + "name": "o1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 248 + } + } + ], + "wires": [ + { + "source": { + "block": "c8fdb023-d458-4657-899c-5749a256be09", + "port": "out1" + }, + "target": { + "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "port": "in" + } + }, + { + "source": { + "block": "c8fdb023-d458-4657-899c-5749a256be09", + "port": "out0" + }, + "target": { + "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "port": "in" + } + }, + { + "source": { + "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "port": "out" + }, + "target": { + "block": "c8fdb023-d458-4657-899c-5749a256be09", + "port": "in0" + } + }, + { + "source": { + "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "port": "out" + }, + "target": { + "block": "c8fdb023-d458-4657-899c-5749a256be09", + "port": "sel0" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/demux_1_2.iceb b/app/resources/blocks/logic/combinational/demux_1_2.iceb deleted file mode 100644 index f963ac483..000000000 --- a/app/resources/blocks/logic/combinational/demux_1_2.iceb +++ /dev/null @@ -1,122 +0,0 @@ -{ - "image": "resources/images/demux.svg", - "state": { - "pan": { - "x": 104.8444188797269, - "y": 152.1580250587398 - }, - "zoom": 0.8586960434913635 - }, - "graph": { - "blocks": [ - { - "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "type": "basic.output", - "data": { - "label": "o0" - }, - "position": { - "x": 720, - "y": 96 - } - }, - { - "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "type": "basic.output", - "data": { - "label": "o1" - }, - "position": { - "x": 720, - "y": 224 - } - }, - { - "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "type": "basic.input", - "data": { - "label": "i" - }, - "position": { - "x": 0, - "y": 96 - } - }, - { - "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "type": "basic.input", - "data": { - "label": "sel" - }, - "position": { - "x": 0, - "y": 224 - } - }, - { - "id": "c8fdb023-d458-4657-899c-5749a256be09", - "type": "basic.code", - "data": { - "code": "assign {out1,out0} = in0 << sel0;", - "ports": { - "in": [ - "in0", - "sel0" - ], - "out": [ - "out0", - "out1" - ] - } - }, - "position": { - "x": 208, - "y": 64 - } - } - ], - "wires": [ - { - "source": { - "block": "c8fdb023-d458-4657-899c-5749a256be09", - "port": "out1" - }, - "target": { - "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "port": "in" - } - }, - { - "source": { - "block": "c8fdb023-d458-4657-899c-5749a256be09", - "port": "out0" - }, - "target": { - "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "port": "in" - } - }, - { - "source": { - "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "port": "out" - }, - "target": { - "block": "c8fdb023-d458-4657-899c-5749a256be09", - "port": "in0" - } - }, - { - "source": { - "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "port": "out" - }, - "target": { - "block": "c8fdb023-d458-4657-899c-5749a256be09", - "port": "sel0" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/demux_1_4.ice b/app/resources/blocks/logic/combinational/demux_1_4.ice new file mode 100644 index 000000000..48ced9775 --- /dev/null +++ b/app/resources/blocks/logic/combinational/demux_1_4.ice @@ -0,0 +1,269 @@ +{ + "version": "1.1", + "package": { + "name": "Demux 1:4", + "version": "1.0.0", + "description": "Demultiplexer 1:4", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20421.9h24v7.3l41%2011.7v-9h25v-2h-25v-18h25v-2h-25v-9l-41%2011.8v7.2h-24v2zm26%205.7v-13.5l37-10.8v35l-37-10.7z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "type": "basic.output", + "data": { + "name": "o0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 800, + "y": 64 + } + }, + { + "id": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "type": "basic.code", + "data": { + "code": "assign {out3,out2,out1,out0} = in0 << {sel1,sel0};", + "params": [], + "ports": { + "in": [ + { + "name": "in0" + }, + { + "name": "sel0" + }, + { + "name": "sel1" + } + ], + "out": [ + { + "name": "out0" + }, + { + "name": "out1" + }, + { + "name": "out2" + }, + { + "name": "out3" + } + ] + } + }, + "position": { + "x": 248, + "y": 88 + } + }, + { + "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "type": "basic.input", + "data": { + "name": "i", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 56, + "y": 96 + } + }, + { + "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "type": "basic.output", + "data": { + "name": "o1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 800, + "y": 144 + } + }, + { + "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "type": "basic.input", + "data": { + "name": "sel0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 56, + "y": 184 + } + }, + { + "id": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", + "type": "basic.output", + "data": { + "name": "o2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 800, + "y": 224 + } + }, + { + "id": "657dab9e-6580-4f02-b54f-66477863f26a", + "type": "basic.input", + "data": { + "name": "sel1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 56, + "y": 272 + } + }, + { + "id": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", + "type": "basic.output", + "data": { + "name": "o3", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 800, + "y": 304 + } + } + ], + "wires": [ + { + "source": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "out0" + }, + "target": { + "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "port": "in" + } + }, + { + "source": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "out1" + }, + "target": { + "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "port": "in" + } + }, + { + "source": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "out2" + }, + "target": { + "block": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", + "port": "in" + } + }, + { + "source": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "out3" + }, + "target": { + "block": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", + "port": "in" + } + }, + { + "source": { + "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "port": "out" + }, + "target": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "in0" + } + }, + { + "source": { + "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "port": "out" + }, + "target": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "sel0" + } + }, + { + "source": { + "block": "657dab9e-6580-4f02-b54f-66477863f26a", + "port": "out" + }, + "target": { + "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", + "port": "sel1" + } + } + ] + }, + "state": { + "pan": { + "x": 11.1761, + "y": 3.2151 + }, + "zoom": 0.9235 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/demux_1_4.iceb b/app/resources/blocks/logic/combinational/demux_1_4.iceb deleted file mode 100644 index 47aab7607..000000000 --- a/app/resources/blocks/logic/combinational/demux_1_4.iceb +++ /dev/null @@ -1,188 +0,0 @@ -{ - "image": "resources/images/demux.svg", - "state": { - "pan": { - "x": 75.84442855228853, - "y": 63.15803102316195 - }, - "zoom": 0.8586960434913635 - }, - "graph": { - "blocks": [ - { - "id": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "type": "basic.code", - "data": { - "code": "assign {out3,out2,out1,out0} = in0 << {sel1,sel0};", - "ports": { - "in": [ - "in0", - "sel0", - "sel1" - ], - "out": [ - "out0", - "out1", - "out2", - "out3" - ] - } - }, - "position": { - "x": 208, - "y": 64 - } - }, - { - "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "type": "basic.output", - "data": { - "label": "o0" - }, - "position": { - "x": 760, - "y": 40 - } - }, - { - "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "type": "basic.output", - "data": { - "label": "o1" - }, - "position": { - "x": 760, - "y": 120 - } - }, - { - "id": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", - "type": "basic.output", - "data": { - "label": "o2" - }, - "position": { - "x": 760, - "y": 200 - } - }, - { - "id": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", - "type": "basic.output", - "data": { - "label": "o3" - }, - "position": { - "x": 760, - "y": 280 - } - }, - { - "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "type": "basic.input", - "data": { - "label": "i" - }, - "position": { - "x": 16, - "y": 72 - } - }, - { - "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "type": "basic.input", - "data": { - "label": "sel0" - }, - "position": { - "x": 16, - "y": 160 - } - }, - { - "id": "657dab9e-6580-4f02-b54f-66477863f26a", - "type": "basic.input", - "data": { - "label": "sel1" - }, - "position": { - "x": 16, - "y": 248 - } - } - ], - "wires": [ - { - "source": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "out0" - }, - "target": { - "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "port": "in" - } - }, - { - "source": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "out1" - }, - "target": { - "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "port": "in" - } - }, - { - "source": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "out2" - }, - "target": { - "block": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", - "port": "in" - } - }, - { - "source": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "out3" - }, - "target": { - "block": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", - "port": "in" - } - }, - { - "source": { - "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "port": "out" - }, - "target": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "in0" - } - }, - { - "source": { - "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "port": "out" - }, - "target": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "sel0" - } - }, - { - "source": { - "block": "657dab9e-6580-4f02-b54f-66477863f26a", - "port": "out" - }, - "target": { - "block": "8a50b4e9-884d-49bb-98c3-3cd1e6cb3f4f", - "port": "sel1" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/demux_1_8.ice b/app/resources/blocks/logic/combinational/demux_1_8.ice new file mode 100644 index 000000000..f281e1dc6 --- /dev/null +++ b/app/resources/blocks/logic/combinational/demux_1_8.ice @@ -0,0 +1,483 @@ +{ + "version": "1.1", + "package": { + "name": "Demux 1:8", + "version": "1.0.0", + "description": "Demultiplexer 1:8", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20421.9h24v7.3l41%2011.7v-9h25v-2h-25v-18h25v-2h-25v-9l-41%2011.8v7.2h-24v2zm26%205.7v-13.5l37-10.8v35l-37-10.7z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "type": "basic.output", + "data": { + "name": "o0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": -120 + } + }, + { + "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "type": "basic.output", + "data": { + "name": "o1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": -40 + } + }, + { + "id": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", + "type": "basic.output", + "data": { + "name": "o2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 40 + } + }, + { + "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "type": "basic.input", + "data": { + "name": "i", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": -8, + "y": 48 + } + }, + { + "id": "1ea41d18-7010-42c0-932f-99d135efdb73", + "type": "basic.code", + "data": { + "code": "assign {out7,out6,out5,out4,out3,out2,out1,out0} = in0 << {sel2,sel1,sel0};", + "params": [], + "ports": { + "in": [ + { + "name": "in0" + }, + { + "name": "sel0" + }, + { + "name": "sel1" + }, + { + "name": "sel2" + } + ], + "out": [ + { + "name": "out0" + }, + { + "name": "out1" + }, + { + "name": "out2" + }, + { + "name": "out3" + }, + { + "name": "out4" + }, + { + "name": "out5" + }, + { + "name": "out6" + }, + { + "name": "out7" + } + ] + } + }, + "position": { + "x": 184, + "y": 72 + } + }, + { + "id": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", + "type": "basic.output", + "data": { + "name": "o3", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 120 + } + }, + { + "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "type": "basic.input", + "data": { + "name": "sel0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": -8, + "y": 128 + } + }, + { + "id": "657dab9e-6580-4f02-b54f-66477863f26a", + "type": "basic.input", + "data": { + "name": "sel1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": -8, + "y": 208 + } + }, + { + "id": "1b8510ac-d723-4226-bf28-c7329d0f73fb", + "type": "basic.output", + "data": { + "name": "o4", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 216 + } + }, + { + "id": "e1a156c8-5813-46f6-a4d4-c672857f3396", + "type": "basic.input", + "data": { + "name": "sel2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": -8, + "y": 288 + } + }, + { + "id": "65f31fca-d607-4d5c-82cc-878a93b8e580", + "type": "basic.output", + "data": { + "name": "o5", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 312 + } + }, + { + "id": "c8fadd68-77e1-47be-a262-b076e878e6fd", + "type": "basic.output", + "data": { + "name": "o6", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 392 + } + }, + { + "id": "99ca2a23-7e0d-4c34-9ab1-988c6bf69633", + "type": "basic.output", + "data": { + "name": "o7", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 760, + "y": 472 + } + } + ], + "wires": [ + { + "source": { + "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", + "port": "out" + }, + "target": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "in0" + } + }, + { + "source": { + "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", + "port": "out" + }, + "target": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "sel0" + } + }, + { + "source": { + "block": "657dab9e-6580-4f02-b54f-66477863f26a", + "port": "out" + }, + "target": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "sel1" + } + }, + { + "source": { + "block": "e1a156c8-5813-46f6-a4d4-c672857f3396", + "port": "out" + }, + "target": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "sel2" + } + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out0" + }, + "target": { + "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", + "port": "in" + }, + "vertices": [ + { + "x": 640, + "y": -16 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out7" + }, + "target": { + "block": "99ca2a23-7e0d-4c34-9ab1-988c6bf69633", + "port": "in" + }, + "vertices": [ + { + "x": 640, + "y": 424 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out1" + }, + "target": { + "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", + "port": "in" + }, + "vertices": [ + { + "x": 656, + "y": 40 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out2" + }, + "target": { + "block": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", + "port": "in" + }, + "vertices": [ + { + "x": 672, + "y": 120 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out3" + }, + "target": { + "block": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", + "port": "in" + }, + "vertices": [ + { + "x": 688, + "y": 184 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out4" + }, + "target": { + "block": "1b8510ac-d723-4226-bf28-c7329d0f73fb", + "port": "in" + } + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out5" + }, + "target": { + "block": "65f31fca-d607-4d5c-82cc-878a93b8e580", + "port": "in" + }, + "vertices": [ + { + "x": 672, + "y": 296 + } + ] + }, + { + "source": { + "block": "1ea41d18-7010-42c0-932f-99d135efdb73", + "port": "out6" + }, + "target": { + "block": "c8fadd68-77e1-47be-a262-b076e878e6fd", + "port": "in" + }, + "vertices": [ + { + "x": 656, + "y": 328 + }, + { + "x": 656, + "y": 368 + }, + { + "x": 656, + "y": 384 + }, + { + "x": 664, + "y": 424 + } + ] + } + ] + }, + "state": { + "pan": { + "x": 143.764, + "y": 110.7556 + }, + "zoom": 0.7272 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/demux_1_8.iceb b/app/resources/blocks/logic/combinational/demux_1_8.iceb deleted file mode 100644 index c8a9c43bc..000000000 --- a/app/resources/blocks/logic/combinational/demux_1_8.iceb +++ /dev/null @@ -1,352 +0,0 @@ -{ - "image": "resources/images/demux.svg", - "state": { - "pan": { - "x": 75.69774669071234, - "y": 148.91048230054443 - }, - "zoom": 0.63316672636209 - }, - "graph": { - "blocks": [ - { - "id": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "type": "basic.output", - "data": { - "label": "o0" - }, - "position": { - "x": 784, - "y": -128 - } - }, - { - "id": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "type": "basic.output", - "data": { - "label": "o1" - }, - "position": { - "x": 784, - "y": -48 - } - }, - { - "id": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", - "type": "basic.output", - "data": { - "label": "o2" - }, - "position": { - "x": 784, - "y": 32 - } - }, - { - "id": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", - "type": "basic.output", - "data": { - "label": "o3" - }, - "position": { - "x": 784, - "y": 112 - } - }, - { - "id": "1b8510ac-d723-4226-bf28-c7329d0f73fb", - "type": "basic.output", - "data": { - "label": "o4" - }, - "position": { - "x": 784, - "y": 208 - } - }, - { - "id": "65f31fca-d607-4d5c-82cc-878a93b8e580", - "type": "basic.output", - "data": { - "label": "o5" - }, - "position": { - "x": 784, - "y": 304 - } - }, - { - "id": "c8fadd68-77e1-47be-a262-b076e878e6fd", - "type": "basic.output", - "data": { - "label": "o6" - }, - "position": { - "x": 784, - "y": 384 - } - }, - { - "id": "99ca2a23-7e0d-4c34-9ab1-988c6bf69633", - "type": "basic.output", - "data": { - "label": "o7" - }, - "position": { - "x": 784, - "y": 464 - } - }, - { - "id": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "type": "basic.input", - "data": { - "label": "i" - }, - "position": { - "x": 16, - "y": 40 - } - }, - { - "id": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "type": "basic.input", - "data": { - "label": "sel0" - }, - "position": { - "x": 16, - "y": 120 - } - }, - { - "id": "657dab9e-6580-4f02-b54f-66477863f26a", - "type": "basic.input", - "data": { - "label": "sel1" - }, - "position": { - "x": 16, - "y": 200 - } - }, - { - "id": "e1a156c8-5813-46f6-a4d4-c672857f3396", - "type": "basic.input", - "data": { - "label": "sel2" - }, - "position": { - "x": 16, - "y": 280 - } - }, - { - "id": "1ea41d18-7010-42c0-932f-99d135efdb73", - "type": "basic.code", - "data": { - "code": "assign {out7,out6,out5,out4,out3,out2,out1,out0} = in0 << {sel2,sel1,sel0};", - "ports": { - "in": [ - "in0", - "sel0", - "sel1", - "sel2" - ], - "out": [ - "out0", - "out1", - "out2", - "out3", - "out4", - "out5", - "out6", - "out7" - ] - } - }, - "position": { - "x": 208, - "y": 64 - } - } - ], - "wires": [ - { - "source": { - "block": "5fc9a8e9-d463-4c1f-b6a3-185d5cabb406", - "port": "out" - }, - "target": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "in0" - } - }, - { - "source": { - "block": "75cafe5a-1968-49ed-9e05-70d1bc3fbd0f", - "port": "out" - }, - "target": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "sel0" - } - }, - { - "source": { - "block": "657dab9e-6580-4f02-b54f-66477863f26a", - "port": "out" - }, - "target": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "sel1" - } - }, - { - "source": { - "block": "e1a156c8-5813-46f6-a4d4-c672857f3396", - "port": "out" - }, - "target": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "sel2" - } - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out0" - }, - "target": { - "block": "91e2ff2d-2430-41e5-9d21-bc9ec4082aaa", - "port": "in" - }, - "vertices": [ - { - "x": 664, - "y": -24 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out7" - }, - "target": { - "block": "99ca2a23-7e0d-4c34-9ab1-988c6bf69633", - "port": "in" - }, - "vertices": [ - { - "x": 664, - "y": 416 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out1" - }, - "target": { - "block": "c6dc7002-dfc0-45fd-88e2-b5e5a75231f2", - "port": "in" - }, - "vertices": [ - { - "x": 680, - "y": 32 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out2" - }, - "target": { - "block": "5e246f93-51ad-4d6f-83f1-4fcce69c5ae3", - "port": "in" - }, - "vertices": [ - { - "x": 696, - "y": 112 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out3" - }, - "target": { - "block": "b9d764ea-538a-420f-a8d3-45af7a8e30a2", - "port": "in" - }, - "vertices": [ - { - "x": 712, - "y": 176 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out4" - }, - "target": { - "block": "1b8510ac-d723-4226-bf28-c7329d0f73fb", - "port": "in" - } - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out5" - }, - "target": { - "block": "65f31fca-d607-4d5c-82cc-878a93b8e580", - "port": "in" - }, - "vertices": [ - { - "x": 696, - "y": 288 - } - ] - }, - { - "source": { - "block": "1ea41d18-7010-42c0-932f-99d135efdb73", - "port": "out6" - }, - "target": { - "block": "c8fadd68-77e1-47be-a262-b076e878e6fd", - "port": "in" - }, - "vertices": [ - { - "x": 680, - "y": 320 - }, - { - "x": 680, - "y": 360 - }, - { - "x": 680, - "y": 376 - }, - { - "x": 688, - "y": 416 - } - ] - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/hex_7seg_ca.ice b/app/resources/blocks/logic/combinational/hex_7seg_ca.ice new file mode 100644 index 000000000..7576429a8 --- /dev/null +++ b/app/resources/blocks/logic/combinational/hex_7seg_ca.ice @@ -0,0 +1,427 @@ +{ + "version": "1.1", + "package": { + "name": "Hex 7seg CA", + "version": "1.0.0", + "description": "Display de 7 segmentos. Ánodo común", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20id=%22Capa_1%22%20viewBox=%220%200%2035.530029%2051.500018%22%20width=%2235.53%22%20height=%2251.5%22%3E%3Cstyle%20id=%22style4204%22%3E.st0%7Bfill:red%7D.st1%7Bfont-family:'FranklinGothic-DemiCond'%7D.st2%7Bfont-size:9.5149px%7D%3C/style%3E%3Cg%20id=%22g4206%22%20transform=%22matrix(.67676%200%200%20.67676%20-11.031%20-3.52)%22%3E%3Cpath%20class=%22st0%22%20id=%22polygon4208%22%20fill=%22red%22%20d=%22M27.7%2020v.1h25.7V20l3-3.2-2.5-2.4H28.2v.1-.1l-3.1%203.3%202.6%202.3z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4210%22%20fill=%22red%22%20d=%22M25.1%2050.4v.1h25.7v-.1l3-3.2-2.6-2.3v-.1H25.5v.1-.1l-3%203.3%202.5%202.3z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4212%22%20fill=%22red%22%20d=%22M48.9%2080.8v.1H23.2v-.1l-3-3.2%202.5-2.3v-.1h25.7v.1l3.1%203.2-2.6%202.4z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4214%22%20fill=%22red%22%20d=%22M19%2044.6l2.3%202.3%203.1-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4216%22%20fill=%22red%22%20d=%22M52.7%2043.9l2.3%202.4%203.1-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4218%22%20fill=%22red%22%20d=%22M16.3%2075.2l2.2%202.4%203.2-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4220%22%20fill=%22red%22%20d=%22M49.9%2074.6l2.3%202.4%203.2-3.2%202-22.8-2.3-2.3-3.4%203.1z%22/%3E%3Ccircle%20class=%22st0%22%20cx=%2265.1%22%20cy=%2277.6%22%20r=%223.7%22%20id=%22circle4222%22%20fill=%22red%22/%3E%3C/g%3E%3Ctext%20class=%22st0%20st1%20st2%22%20id=%22text4224%22%20x=%223.502%22%20y=%223.377%22%20font-size=%223.642%22%20font-family=%22FranklinGothic-DemiCond%22%20fill=%22red%22%3E%3Ctspan%20style=%22-inkscape-font-specification:sans-serif%22%20id=%22tspan4204%22%20font-family=%22sans-serif%22%20font-weight=%22400%22%20font-size=%223.75%22%3EANODO%20COM%C3%9AN%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "8b73e273-3603-443a-b952-0ab9ad826a96", + "type": "basic.output", + "data": { + "name": "a", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 368 + } + }, + { + "id": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", + "type": "basic.output", + "data": { + "name": "b", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 448 + } + }, + { + "id": "16e44a6a-853a-4264-9e9d-2269827ed136", + "type": "basic.input", + "data": { + "name": "h0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 488 + } + }, + { + "id": "1d9b0829-1b10-4495-ae33-08792225f68e", + "type": "basic.code", + "data": { + "code": "// Ánodo común\n// gfe_dcba\nlocalparam BCD_0 = 7'b011_1111,\n BCD_1 = 7'b000_0110,\n BCD_2 = 7'b101_1011,\n BCD_3 = 7'b100_1111,\n BCD_4 = 7'b110_0110,\n BCD_5 = 7'b110_1101,\n BCD_6 = 7'b111_1101,\n BCD_7 = 7'b000_0111,\n BCD_8 = 7'b111_1111,\n BCD_9 = 7'b110_1111,\n BCD_A = 7'b111_0111,\n BCD_B = 7'b111_1100,\n BCD_C = 7'b011_1001,\n BCD_D = 7'b101_1110,\n BCD_E = 7'b111_1001,\n BCD_F = 7'b111_0001;\n\nreg [6:0] _o;\n\nalways @(*)\nbegin\n\n case({h3, h2, h1, h0})\n 4'h0: _o <= BCD_0;\n 4'h1: _o <= BCD_1;\n 4'h2: _o <= BCD_2;\n 4'h3: _o <= BCD_3;\n 4'h4: _o <= BCD_4;\n 4'h5: _o <= BCD_5;\n 4'h6: _o <= BCD_6;\n 4'h7: _o <= BCD_7;\n 4'h8: _o <= BCD_8;\n 4'h9: _o <= BCD_9;\n 4'hA: _o <= BCD_A;\n 4'hB: _o <= BCD_B;\n 4'hC: _o <= BCD_C;\n 4'hD: _o <= BCD_D;\n 4'hE: _o <= BCD_E;\n 4'hF: _o <= BCD_F;\n default: _o <= 0;\n endcase\nend\n\nassign {g, f, e, d, c, b, a} = ~_o;", + "params": [], + "ports": { + "in": [ + { + "name": "h0" + }, + { + "name": "h1" + }, + { + "name": "h2" + }, + { + "name": "h3" + } + ], + "out": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + }, + { + "name": "d" + }, + { + "name": "e" + }, + { + "name": "f" + }, + { + "name": "g" + } + ] + } + }, + "position": { + "x": 496, + "y": 512 + } + }, + { + "id": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", + "type": "basic.output", + "data": { + "name": "c", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 528 + } + }, + { + "id": "9cdbdf9f-f086-4427-9719-e13470658d97", + "type": "basic.input", + "data": { + "name": "h1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 568 + } + }, + { + "id": "4687e984-3f19-44d7-baee-ca89513f8f1a", + "type": "basic.output", + "data": { + "name": "d", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 608 + } + }, + { + "id": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", + "type": "basic.input", + "data": { + "name": "h2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 648 + } + }, + { + "id": "1691b072-9102-4986-a900-fefd1a5a7b9e", + "type": "basic.output", + "data": { + "name": "e", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 688 + } + }, + { + "id": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", + "type": "basic.input", + "data": { + "name": "h3", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 728 + } + }, + { + "id": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", + "type": "basic.output", + "data": { + "name": "f", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 768 + } + }, + { + "id": "2565c42b-00b0-4b1d-92a4-66c715834b33", + "type": "basic.output", + "data": { + "name": "g", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 840 + } + } + ], + "wires": [ + { + "source": { + "block": "16e44a6a-853a-4264-9e9d-2269827ed136", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h0" + } + }, + { + "source": { + "block": "9cdbdf9f-f086-4427-9719-e13470658d97", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h1" + } + }, + { + "source": { + "block": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h2" + } + }, + { + "source": { + "block": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h3" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "d" + }, + "target": { + "block": "4687e984-3f19-44d7-baee-ca89513f8f1a", + "port": "in" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "c" + }, + "target": { + "block": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", + "port": "in" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "b" + }, + "target": { + "block": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", + "port": "in" + }, + "vertices": [ + { + "x": 952, + "y": 504 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "a" + }, + "target": { + "block": "8b73e273-3603-443a-b952-0ab9ad826a96", + "port": "in" + }, + "vertices": [ + { + "x": 928, + "y": 440 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "e" + }, + "target": { + "block": "1691b072-9102-4986-a900-fefd1a5a7b9e", + "port": "in" + }, + "vertices": [ + { + "x": 976, + "y": 704 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "f" + }, + "target": { + "block": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", + "port": "in" + }, + "vertices": [ + { + "x": 952, + "y": 752 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "g" + }, + "target": { + "block": "2565c42b-00b0-4b1d-92a4-66c715834b33", + "port": "in" + }, + "vertices": [ + { + "x": 928, + "y": 824 + } + ] + } + ] + }, + "state": { + "pan": { + "x": -152.0732, + "y": -209.2108 + }, + "zoom": 0.7374 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/hex_7seg_ca.iceb b/app/resources/blocks/logic/combinational/hex_7seg_ca.iceb deleted file mode 100644 index ea53c99c8..000000000 --- a/app/resources/blocks/logic/combinational/hex_7seg_ca.iceb +++ /dev/null @@ -1,276 +0,0 @@ -{ - "image": "resources/images/7segmentos_ANODO.svg", - "state": { - "pan": { - "x": -152.07320110504, - "y": -209.21075900090992 - }, - "zoom": 0.7373584520604582 - }, - "graph": { - "blocks": [ - { - "id": "8b73e273-3603-443a-b952-0ab9ad826a96", - "type": "basic.output", - "data": { - "label": "a" - }, - "position": { - "x": 1016, - "y": 368 - } - }, - { - "id": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", - "type": "basic.output", - "data": { - "label": "b" - }, - "position": { - "x": 1016, - "y": 448 - } - }, - { - "id": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", - "type": "basic.output", - "data": { - "label": "c" - }, - "position": { - "x": 1016, - "y": 528 - } - }, - { - "id": "4687e984-3f19-44d7-baee-ca89513f8f1a", - "type": "basic.output", - "data": { - "label": "d" - }, - "position": { - "x": 1016, - "y": 608 - } - }, - { - "id": "1691b072-9102-4986-a900-fefd1a5a7b9e", - "type": "basic.output", - "data": { - "label": "e" - }, - "position": { - "x": 1016, - "y": 688 - } - }, - { - "id": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", - "type": "basic.output", - "data": { - "label": "f" - }, - "position": { - "x": 1016, - "y": 768 - } - }, - { - "id": "2565c42b-00b0-4b1d-92a4-66c715834b33", - "type": "basic.output", - "data": { - "label": "g" - }, - "position": { - "x": 1016, - "y": 840 - } - }, - { - "id": "16e44a6a-853a-4264-9e9d-2269827ed136", - "type": "basic.input", - "data": { - "label": "h0" - }, - "position": { - "x": 312, - "y": 488 - } - }, - { - "id": "9cdbdf9f-f086-4427-9719-e13470658d97", - "type": "basic.input", - "data": { - "label": "h1" - }, - "position": { - "x": 312, - "y": 568 - } - }, - { - "id": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", - "type": "basic.input", - "data": { - "label": "h2" - }, - "position": { - "x": 312, - "y": 648 - } - }, - { - "id": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", - "type": "basic.input", - "data": { - "label": "h3" - }, - "position": { - "x": 312, - "y": 728 - } - }, - { - "id": "1d9b0829-1b10-4495-ae33-08792225f68e", - "type": "basic.code", - "data": { - "code": "// Catodo común\n// gfe_dcba\nlocalparam BCD_0 = 7'b011_1111,\n BCD_1 = 7'b000_0110,\n BCD_2 = 7'b101_1011,\n BCD_3 = 7'b100_1111,\n BCD_4 = 7'b110_0110,\n BCD_5 = 7'b110_1101,\n BCD_6 = 7'b111_1101,\n BCD_7 = 7'b000_0111,\n BCD_8 = 7'b111_1111,\n BCD_9 = 7'b110_1111,\n BCD_A = 7'b111_0111,\n BCD_B = 7'b111_1100,\n BCD_C = 7'b011_1001,\n BCD_D = 7'b101_1110,\n BCD_E = 7'b111_1001,\n BCD_F = 7'b111_0001;\n\nreg [6:0] _o;\n\nalways @(*)\nbegin\n\n case({h3, h2, h1, h0})\n 4'h0: _o <= BCD_0;\n 4'h1: _o <= BCD_1;\n 4'h2: _o <= BCD_2;\n 4'h3: _o <= BCD_3;\n 4'h4: _o <= BCD_4;\n 4'h5: _o <= BCD_5;\n 4'h6: _o <= BCD_6;\n 4'h7: _o <= BCD_7;\n 4'h8: _o <= BCD_8;\n 4'h9: _o <= BCD_9;\n 4'hA: _o <= BCD_A;\n 4'hB: _o <= BCD_B;\n 4'hC: _o <= BCD_C;\n 4'hD: _o <= BCD_D;\n 4'hE: _o <= BCD_E;\n 4'hF: _o <= BCD_F;\n default: _o <= 0;\n endcase\nend\n\nassign {g, f, e, d, c, b, a} = ~_o;", - "ports": { - "in": [ - "h0", - "h1", - "h2", - "h3" - ], - "out": [ - "a", - "b", - "c", - "d", - "e", - "f", - "g" - ] - } - }, - "position": { - "x": 496, - "y": 512 - } - } - ], - "wires": [ - { - "source": { - "block": "16e44a6a-853a-4264-9e9d-2269827ed136", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h0" - } - }, - { - "source": { - "block": "9cdbdf9f-f086-4427-9719-e13470658d97", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h1" - } - }, - { - "source": { - "block": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h2" - } - }, - { - "source": { - "block": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h3" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "d" - }, - "target": { - "block": "4687e984-3f19-44d7-baee-ca89513f8f1a", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "c" - }, - "target": { - "block": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "b" - }, - "target": { - "block": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "a" - }, - "target": { - "block": "8b73e273-3603-443a-b952-0ab9ad826a96", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "e" - }, - "target": { - "block": "1691b072-9102-4986-a900-fefd1a5a7b9e", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "f" - }, - "target": { - "block": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "g" - }, - "target": { - "block": "2565c42b-00b0-4b1d-92a4-66c715834b33", - "port": "in" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/hex_7seg_cc.ice b/app/resources/blocks/logic/combinational/hex_7seg_cc.ice new file mode 100644 index 000000000..fb9b3d09f --- /dev/null +++ b/app/resources/blocks/logic/combinational/hex_7seg_cc.ice @@ -0,0 +1,421 @@ +{ + "version": "1.1", + "package": { + "name": "Hex 7seg CC", + "version": "1.0.0", + "description": "Display de 7 segmentos. Cátodo común", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20id=%22Capa_1%22%20viewBox=%220%200%2035.530029%2051.500018%22%20width=%2235.53%22%20height=%2251.5%22%3E%3Cstyle%20id=%22style4204%22%3E.st0%7Bfill:red%7D.st1%7Bfont-family:'FranklinGothic-DemiCond'%7D.st2%7Bfont-size:9.5149px%7D%3C/style%3E%3Cg%20id=%22g4206%22%20transform=%22matrix(.67676%200%200%20.67676%20-11.031%20-3.52)%22%3E%3Cpath%20class=%22st0%22%20id=%22polygon4208%22%20fill=%22red%22%20d=%22M27.7%2020v.1h25.7V20l3-3.2-2.5-2.4H28.2v.1-.1l-3.1%203.3%202.6%202.3z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4210%22%20fill=%22red%22%20d=%22M25.1%2050.4v.1h25.7v-.1l3-3.2-2.6-2.3v-.1H25.5v.1-.1l-3%203.3%202.5%202.3z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4212%22%20fill=%22red%22%20d=%22M48.9%2080.8v.1H23.2v-.1l-3-3.2%202.5-2.3v-.1h25.7v.1l3.1%203.2-2.6%202.4z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4214%22%20fill=%22red%22%20d=%22M19%2044.6l2.3%202.3%203.1-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4216%22%20fill=%22red%22%20d=%22M52.7%2043.9l2.3%202.4%203.1-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4218%22%20fill=%22red%22%20d=%22M16.3%2075.2l2.2%202.4%203.2-3.2%202-22.8-2.3-2.3-3.3%203.1z%22/%3E%3Cpath%20class=%22st0%22%20id=%22polygon4220%22%20fill=%22red%22%20d=%22M49.9%2074.6l2.3%202.4%203.2-3.2%202-22.8-2.3-2.3-3.4%203.1z%22/%3E%3Ccircle%20class=%22st0%22%20cx=%2265.1%22%20cy=%2277.6%22%20r=%223.7%22%20id=%22circle4222%22%20fill=%22red%22/%3E%3C/g%3E%3Ctext%20class=%22st0%20st1%20st2%22%20id=%22text4224%22%20x=%222.532%22%20y=%223.377%22%20style=%22-inkscape-font-specification:sans-serif%22%20font-size=%223.642%22%20font-family=%22sans-serif%22%20fill=%22red%22%20font-weight=%22400%22%3E%3Ctspan%20id=%22tspan4814%22%20font-size=%223.75%22%3ECATODO%20COM%C3%9AN%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "8b73e273-3603-443a-b952-0ab9ad826a96", + "type": "basic.output", + "data": { + "name": "a", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 368 + } + }, + { + "id": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", + "type": "basic.output", + "data": { + "name": "b", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 448 + } + }, + { + "id": "16e44a6a-853a-4264-9e9d-2269827ed136", + "type": "basic.input", + "data": { + "name": "h0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 488 + } + }, + { + "id": "1d9b0829-1b10-4495-ae33-08792225f68e", + "type": "basic.code", + "data": { + "code": "// Catodo común\n// gfe_dcba\nlocalparam BCD_0 = 7'b011_1111,\n BCD_1 = 7'b000_0110,\n BCD_2 = 7'b101_1011,\n BCD_3 = 7'b100_1111,\n BCD_4 = 7'b110_0110,\n BCD_5 = 7'b110_1101,\n BCD_6 = 7'b111_1101,\n BCD_7 = 7'b000_0111,\n BCD_8 = 7'b111_1111,\n BCD_9 = 7'b110_1111,\n BCD_A = 7'b111_0111,\n BCD_B = 7'b111_1100,\n BCD_C = 7'b011_1001,\n BCD_D = 7'b101_1110,\n BCD_E = 7'b111_1001,\n BCD_F = 7'b111_0001;\n\nreg [6:0] _o;\n\nalways @(*)\nbegin\n\n case({h3, h2, h1, h0})\n 4'h0: _o <= BCD_0;\n 4'h1: _o <= BCD_1;\n 4'h2: _o <= BCD_2;\n 4'h3: _o <= BCD_3;\n 4'h4: _o <= BCD_4;\n 4'h5: _o <= BCD_5;\n 4'h6: _o <= BCD_6;\n 4'h7: _o <= BCD_7;\n 4'h8: _o <= BCD_8;\n 4'h9: _o <= BCD_9;\n 4'hA: _o <= BCD_A;\n 4'hB: _o <= BCD_B;\n 4'hC: _o <= BCD_C;\n 4'hD: _o <= BCD_D;\n 4'hE: _o <= BCD_E;\n 4'hF: _o <= BCD_F;\n default: _o <= 0;\n endcase\nend\n\nassign {g, f, e, d, c, b, a} = _o;", + "params": [], + "ports": { + "in": [ + { + "name": "h0" + }, + { + "name": "h1" + }, + { + "name": "h2" + }, + { + "name": "h3" + } + ], + "out": [ + { + "name": "a" + }, + { + "name": "b" + }, + { + "name": "c" + }, + { + "name": "d" + }, + { + "name": "e" + }, + { + "name": "f" + }, + { + "name": "g" + } + ] + } + }, + "position": { + "x": 496, + "y": 512 + } + }, + { + "id": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", + "type": "basic.output", + "data": { + "name": "c", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 528 + } + }, + { + "id": "9cdbdf9f-f086-4427-9719-e13470658d97", + "type": "basic.input", + "data": { + "name": "h1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 568 + } + }, + { + "id": "4687e984-3f19-44d7-baee-ca89513f8f1a", + "type": "basic.output", + "data": { + "name": "d", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 608 + } + }, + { + "id": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", + "type": "basic.input", + "data": { + "name": "h2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 648 + } + }, + { + "id": "1691b072-9102-4986-a900-fefd1a5a7b9e", + "type": "basic.output", + "data": { + "name": "e", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 688 + } + }, + { + "id": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", + "type": "basic.input", + "data": { + "name": "h3", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 312, + "y": 728 + } + }, + { + "id": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", + "type": "basic.output", + "data": { + "name": "f", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 768 + } + }, + { + "id": "2565c42b-00b0-4b1d-92a4-66c715834b33", + "type": "basic.output", + "data": { + "name": "g", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 1016, + "y": 840 + } + } + ], + "wires": [ + { + "source": { + "block": "16e44a6a-853a-4264-9e9d-2269827ed136", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h0" + } + }, + { + "source": { + "block": "9cdbdf9f-f086-4427-9719-e13470658d97", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h1" + } + }, + { + "source": { + "block": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h2" + } + }, + { + "source": { + "block": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", + "port": "out" + }, + "target": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "h3" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "d" + }, + "target": { + "block": "4687e984-3f19-44d7-baee-ca89513f8f1a", + "port": "in" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "c" + }, + "target": { + "block": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", + "port": "in" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "b" + }, + "target": { + "block": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", + "port": "in" + }, + "vertices": [ + { + "x": 952, + "y": 528 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "a" + }, + "target": { + "block": "8b73e273-3603-443a-b952-0ab9ad826a96", + "port": "in" + }, + "vertices": [ + { + "x": 928, + "y": 448 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "e" + }, + "target": { + "block": "1691b072-9102-4986-a900-fefd1a5a7b9e", + "port": "in" + } + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "f" + }, + "target": { + "block": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", + "port": "in" + }, + "vertices": [ + { + "x": 952, + "y": 776 + } + ] + }, + { + "source": { + "block": "1d9b0829-1b10-4495-ae33-08792225f68e", + "port": "g" + }, + "target": { + "block": "2565c42b-00b0-4b1d-92a4-66c715834b33", + "port": "in" + }, + "vertices": [ + { + "x": 928, + "y": 824 + } + ] + } + ] + }, + "state": { + "pan": { + "x": -152.0732, + "y": -209.2108 + }, + "zoom": 0.7374 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/hex_7seg_cc.iceb b/app/resources/blocks/logic/combinational/hex_7seg_cc.iceb deleted file mode 100644 index 33f6b7c7f..000000000 --- a/app/resources/blocks/logic/combinational/hex_7seg_cc.iceb +++ /dev/null @@ -1,276 +0,0 @@ -{ - "image": "resources/images/7segmentos_CATODO.svg", - "state": { - "pan": { - "x": -152.07320110504, - "y": -209.21075900090992 - }, - "zoom": 0.7373584520604582 - }, - "graph": { - "blocks": [ - { - "id": "8b73e273-3603-443a-b952-0ab9ad826a96", - "type": "basic.output", - "data": { - "label": "a" - }, - "position": { - "x": 1016, - "y": 368 - } - }, - { - "id": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", - "type": "basic.output", - "data": { - "label": "b" - }, - "position": { - "x": 1016, - "y": 448 - } - }, - { - "id": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", - "type": "basic.output", - "data": { - "label": "c" - }, - "position": { - "x": 1016, - "y": 528 - } - }, - { - "id": "4687e984-3f19-44d7-baee-ca89513f8f1a", - "type": "basic.output", - "data": { - "label": "d" - }, - "position": { - "x": 1016, - "y": 608 - } - }, - { - "id": "1691b072-9102-4986-a900-fefd1a5a7b9e", - "type": "basic.output", - "data": { - "label": "e" - }, - "position": { - "x": 1016, - "y": 688 - } - }, - { - "id": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", - "type": "basic.output", - "data": { - "label": "f" - }, - "position": { - "x": 1016, - "y": 768 - } - }, - { - "id": "2565c42b-00b0-4b1d-92a4-66c715834b33", - "type": "basic.output", - "data": { - "label": "g" - }, - "position": { - "x": 1016, - "y": 840 - } - }, - { - "id": "16e44a6a-853a-4264-9e9d-2269827ed136", - "type": "basic.input", - "data": { - "label": "h0" - }, - "position": { - "x": 312, - "y": 488 - } - }, - { - "id": "9cdbdf9f-f086-4427-9719-e13470658d97", - "type": "basic.input", - "data": { - "label": "h1" - }, - "position": { - "x": 312, - "y": 568 - } - }, - { - "id": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", - "type": "basic.input", - "data": { - "label": "h2" - }, - "position": { - "x": 312, - "y": 648 - } - }, - { - "id": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", - "type": "basic.input", - "data": { - "label": "h3" - }, - "position": { - "x": 312, - "y": 728 - } - }, - { - "id": "1d9b0829-1b10-4495-ae33-08792225f68e", - "type": "basic.code", - "data": { - "code": "// Catodo común\n// gfe_dcba\nlocalparam BCD_0 = 7'b011_1111,\n BCD_1 = 7'b000_0110,\n BCD_2 = 7'b101_1011,\n BCD_3 = 7'b100_1111,\n BCD_4 = 7'b110_0110,\n BCD_5 = 7'b110_1101,\n BCD_6 = 7'b111_1101,\n BCD_7 = 7'b000_0111,\n BCD_8 = 7'b111_1111,\n BCD_9 = 7'b110_1111,\n BCD_A = 7'b111_0111,\n BCD_B = 7'b111_1100,\n BCD_C = 7'b011_1001,\n BCD_D = 7'b101_1110,\n BCD_E = 7'b111_1001,\n BCD_F = 7'b111_0001;\n\nreg [6:0] _o;\n\nalways @(*)\nbegin\n\n case({h3, h2, h1, h0})\n 4'h0: _o <= BCD_0;\n 4'h1: _o <= BCD_1;\n 4'h2: _o <= BCD_2;\n 4'h3: _o <= BCD_3;\n 4'h4: _o <= BCD_4;\n 4'h5: _o <= BCD_5;\n 4'h6: _o <= BCD_6;\n 4'h7: _o <= BCD_7;\n 4'h8: _o <= BCD_8;\n 4'h9: _o <= BCD_9;\n 4'hA: _o <= BCD_A;\n 4'hB: _o <= BCD_B;\n 4'hC: _o <= BCD_C;\n 4'hD: _o <= BCD_D;\n 4'hE: _o <= BCD_E;\n 4'hF: _o <= BCD_F;\n default: _o <= 0;\n endcase\nend\n\nassign {g, f, e, d, c, b, a} = _o;", - "ports": { - "in": [ - "h0", - "h1", - "h2", - "h3" - ], - "out": [ - "a", - "b", - "c", - "d", - "e", - "f", - "g" - ] - } - }, - "position": { - "x": 496, - "y": 512 - } - } - ], - "wires": [ - { - "source": { - "block": "16e44a6a-853a-4264-9e9d-2269827ed136", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h0" - } - }, - { - "source": { - "block": "9cdbdf9f-f086-4427-9719-e13470658d97", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h1" - } - }, - { - "source": { - "block": "f40ab7a8-10e5-4e7f-94f9-cefd697d5d40", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h2" - } - }, - { - "source": { - "block": "2d774807-3ec8-492c-98e2-f1c9da8d68ff", - "port": "out" - }, - "target": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "h3" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "d" - }, - "target": { - "block": "4687e984-3f19-44d7-baee-ca89513f8f1a", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "c" - }, - "target": { - "block": "bf0ea22e-3ac2-4756-87d5-020a6ea6a1a8", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "b" - }, - "target": { - "block": "f2fce5fa-be07-46fe-bee1-bb2a497fe747", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "a" - }, - "target": { - "block": "8b73e273-3603-443a-b952-0ab9ad826a96", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "e" - }, - "target": { - "block": "1691b072-9102-4986-a900-fefd1a5a7b9e", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "f" - }, - "target": { - "block": "7c14afe7-1ac0-4394-b38e-fa8a00ffa21c", - "port": "in" - } - }, - { - "source": { - "block": "1d9b0829-1b10-4495-ae33-08792225f68e", - "port": "g" - }, - "target": { - "block": "2565c42b-00b0-4b1d-92a4-66c715834b33", - "port": "in" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/mux_2_1.ice b/app/resources/blocks/logic/combinational/mux_2_1.ice new file mode 100644 index 000000000..aa5bc7ae2 --- /dev/null +++ b/app/resources/blocks/logic/combinational/mux_2_1.ice @@ -0,0 +1,173 @@ +{ + "version": "1.1", + "package": { + "name": "Mux 2:1", + "version": "1.0.0", + "description": "Multiplexer 2:1", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-162%20419.9h-24v-7.2l-41-11.8v9h-25v2h25v18h-25v2h25v9l41-11.7v-7.4h24v-1.9zm-63%2018.5v-35l37%2010.8v13.5l-37%2010.7z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "ba573190-2ead-411a-a323-1b15a22d46db", + "type": "basic.code", + "data": { + "code": "reg _o;\n\nalways @(*) begin\n case(sel0)\n 0: _o = in0;\n 1: _o = in1;\n default: _o = in0;\n endcase\nend\n\nassign o = _o;", + "params": [], + "ports": { + "in": [ + { + "name": "in0" + }, + { + "name": "in1" + }, + { + "name": "sel0" + } + ], + "out": [ + { + "name": "o" + } + ] + } + }, + "position": { + "x": 312, + "y": 112 + } + }, + { + "id": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", + "type": "basic.input", + "data": { + "name": "i0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 80, + "y": 120 + } + }, + { + "id": "5fb29465-2ee7-45bb-afa4-9a3de895c774", + "type": "basic.input", + "data": { + "name": "i1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 80, + "y": 208 + } + }, + { + "id": "061aa997-2f30-4591-8841-fb6abf5c3b2e", + "type": "basic.output", + "data": { + "name": "o", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 792, + "y": 208 + } + }, + { + "id": "67ed5e09-486d-4f97-929f-aefea9c43951", + "type": "basic.input", + "data": { + "name": "sel", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 80, + "y": 296 + } + } + ], + "wires": [ + { + "source": { + "block": "ba573190-2ead-411a-a323-1b15a22d46db", + "port": "o" + }, + "target": { + "block": "061aa997-2f30-4591-8841-fb6abf5c3b2e", + "port": "in" + } + }, + { + "source": { + "block": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", + "port": "out" + }, + "target": { + "block": "ba573190-2ead-411a-a323-1b15a22d46db", + "port": "in0" + } + }, + { + "source": { + "block": "5fb29465-2ee7-45bb-afa4-9a3de895c774", + "port": "out" + }, + "target": { + "block": "ba573190-2ead-411a-a323-1b15a22d46db", + "port": "in1" + } + }, + { + "source": { + "block": "67ed5e09-486d-4f97-929f-aefea9c43951", + "port": "out" + }, + "target": { + "block": "ba573190-2ead-411a-a323-1b15a22d46db", + "port": "sel0" + } + } + ] + }, + "state": { + "pan": { + "x": -21.0375, + "y": 29.4792 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/mux_2_1.iceb b/app/resources/blocks/logic/combinational/mux_2_1.iceb deleted file mode 100644 index eb1a4cc0d..000000000 --- a/app/resources/blocks/logic/combinational/mux_2_1.iceb +++ /dev/null @@ -1,122 +0,0 @@ -{ - "image": "resources/images/mux.svg", - "state": { - "pan": { - "x": -21.03752160981206, - "y": 29.479234822175684 - }, - "zoom": 1.000000683370386 - }, - "graph": { - "blocks": [ - { - "id": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", - "type": "basic.input", - "data": { - "label": "i0" - }, - "position": { - "x": 80, - "y": 120 - } - }, - { - "id": "5fb29465-2ee7-45bb-afa4-9a3de895c774", - "type": "basic.input", - "data": { - "label": "i1" - }, - "position": { - "x": 80, - "y": 208 - } - }, - { - "id": "67ed5e09-486d-4f97-929f-aefea9c43951", - "type": "basic.input", - "data": { - "label": "sel" - }, - "position": { - "x": 80, - "y": 296 - } - }, - { - "id": "061aa997-2f30-4591-8841-fb6abf5c3b2e", - "type": "basic.output", - "data": { - "label": "o" - }, - "position": { - "x": 792, - "y": 208 - } - }, - { - "id": "ba573190-2ead-411a-a323-1b15a22d46db", - "type": "basic.code", - "data": { - "code": "reg _o;\n\nalways @(*) begin\n case(sel0)\n 0: _o = in0;\n 1: _o = in1;\n default: _o = in0;\n endcase\nend\n\nassign o = _o;", - "ports": { - "in": [ - "in0", - "in1", - "sel0" - ], - "out": [ - "o" - ] - } - }, - "position": { - "x": 312, - "y": 112 - } - } - ], - "wires": [ - { - "source": { - "block": "ba573190-2ead-411a-a323-1b15a22d46db", - "port": "o" - }, - "target": { - "block": "061aa997-2f30-4591-8841-fb6abf5c3b2e", - "port": "in" - } - }, - { - "source": { - "block": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", - "port": "out" - }, - "target": { - "block": "ba573190-2ead-411a-a323-1b15a22d46db", - "port": "in0" - } - }, - { - "source": { - "block": "5fb29465-2ee7-45bb-afa4-9a3de895c774", - "port": "out" - }, - "target": { - "block": "ba573190-2ead-411a-a323-1b15a22d46db", - "port": "in1" - } - }, - { - "source": { - "block": "67ed5e09-486d-4f97-929f-aefea9c43951", - "port": "out" - }, - "target": { - "block": "ba573190-2ead-411a-a323-1b15a22d46db", - "port": "sel0" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/combinational/mux_4_1.ice b/app/resources/blocks/logic/combinational/mux_4_1.ice new file mode 100644 index 000000000..6b9b53ad6 --- /dev/null +++ b/app/resources/blocks/logic/combinational/mux_4_1.ice @@ -0,0 +1,281 @@ +{ + "version": "1.1", + "package": { + "name": "Mux 4:1", + "version": "1.0.0", + "description": "Multiplexer 4:1", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-162%20419.9h-24v-7.2l-41-11.8v9h-25v2h25v18h-25v2h25v9l41-11.7v-7.4h24v-1.9zm-63%2018.5v-35l37%2010.8v13.5l-37%2010.7z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", + "type": "basic.input", + "data": { + "name": "i0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 32 + } + }, + { + "id": "5fb29465-2ee7-45bb-afa4-9a3de895c774", + "type": "basic.input", + "data": { + "name": "i1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 104 + } + }, + { + "id": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "type": "basic.code", + "data": { + "code": "reg _o;\nwire [1:0] _sel;\n\nassign _sel = {sel1, sel0};\n\nalways @(*) begin\n case(_sel)\n 0: _o = in0;\n 1: _o = in1;\n 2: _o = in2;\n 3: _o = in3;\n default: _o = in0;\n endcase\nend\n\nassign o = _o;", + "params": [], + "ports": { + "in": [ + { + "name": "in0" + }, + { + "name": "in1" + }, + { + "name": "in2" + }, + { + "name": "in3" + }, + { + "name": "sel0" + }, + { + "name": "sel1" + } + ], + "out": [ + { + "name": "o" + } + ] + } + }, + "position": { + "x": 296, + "y": 152 + } + }, + { + "id": "67ed5e09-486d-4f97-929f-aefea9c43951", + "type": "basic.input", + "data": { + "name": "i2", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 184 + } + }, + { + "id": "061aa997-2f30-4591-8841-fb6abf5c3b2e", + "type": "basic.output", + "data": { + "name": "o", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 776, + "y": 248 + } + }, + { + "id": "8be9cded-6d06-4b23-b73c-94c7ff311dbc", + "type": "basic.input", + "data": { + "name": "i3", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 256 + } + }, + { + "id": "1b7db016-c89a-4f65-b6f0-0f87c851c077", + "type": "basic.input", + "data": { + "name": "sel0", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 328 + } + }, + { + "id": "a014971e-5470-490b-9058-b4b00f2dd125", + "type": "basic.input", + "data": { + "name": "sel1", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 40, + "y": 400 + } + } + ], + "wires": [ + { + "source": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "o" + }, + "target": { + "block": "061aa997-2f30-4591-8841-fb6abf5c3b2e", + "port": "in" + } + }, + { + "source": { + "block": "a014971e-5470-490b-9058-b4b00f2dd125", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "sel1" + } + }, + { + "source": { + "block": "1b7db016-c89a-4f65-b6f0-0f87c851c077", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "sel0" + } + }, + { + "source": { + "block": "8be9cded-6d06-4b23-b73c-94c7ff311dbc", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "in3" + } + }, + { + "source": { + "block": "67ed5e09-486d-4f97-929f-aefea9c43951", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "in2" + }, + "vertices": [ + { + "x": 192, + "y": 248 + } + ] + }, + { + "source": { + "block": "5fb29465-2ee7-45bb-afa4-9a3de895c774", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "in1" + }, + "vertices": [ + { + "x": 224, + "y": 168 + } + ] + }, + { + "source": { + "block": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", + "port": "out" + }, + "target": { + "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", + "port": "in0" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/combinational/mux_4_1.iceb b/app/resources/blocks/logic/combinational/mux_4_1.iceb deleted file mode 100644 index ac11b104c..000000000 --- a/app/resources/blocks/logic/combinational/mux_4_1.iceb +++ /dev/null @@ -1,200 +0,0 @@ -{ - "image": "resources/images/mux.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 0.9999999735145888 - }, - "graph": { - "blocks": [ - { - "id": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "type": "basic.code", - "data": { - "code": "reg _o;\nwire [1:0] _sel;\n\nassign _sel = {sel1, sel0};\n\nalways @(*) begin\n case(_sel)\n 0: _o = in0;\n 1: _o = in1;\n 2: _o = in2;\n 3: _o = in3;\n default: _o = in0;\n endcase\nend\n\nassign o = _o;", - "ports": { - "in": [ - "in0", - "in1", - "in2", - "in3", - "sel0", - "sel1" - ], - "out": [ - "o" - ] - } - }, - "position": { - "x": 296, - "y": 152 - } - }, - { - "id": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", - "type": "basic.input", - "data": { - "label": "i0" - }, - "position": { - "x": 40, - "y": 32 - } - }, - { - "id": "5fb29465-2ee7-45bb-afa4-9a3de895c774", - "type": "basic.input", - "data": { - "label": "i1" - }, - "position": { - "x": 40, - "y": 104 - } - }, - { - "id": "67ed5e09-486d-4f97-929f-aefea9c43951", - "type": "basic.input", - "data": { - "label": "i2" - }, - "position": { - "x": 40, - "y": 184 - } - }, - { - "id": "8be9cded-6d06-4b23-b73c-94c7ff311dbc", - "type": "basic.input", - "data": { - "label": "i3" - }, - "position": { - "x": 40, - "y": 256 - } - }, - { - "id": "1b7db016-c89a-4f65-b6f0-0f87c851c077", - "type": "basic.input", - "data": { - "label": "sel0" - }, - "position": { - "x": 40, - "y": 328 - } - }, - { - "id": "a014971e-5470-490b-9058-b4b00f2dd125", - "type": "basic.input", - "data": { - "label": "sel1" - }, - "position": { - "x": 40, - "y": 400 - } - }, - { - "id": "061aa997-2f30-4591-8841-fb6abf5c3b2e", - "type": "basic.output", - "data": { - "label": "o" - }, - "position": { - "x": 776, - "y": 248 - } - } - ], - "wires": [ - { - "source": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "o" - }, - "target": { - "block": "061aa997-2f30-4591-8841-fb6abf5c3b2e", - "port": "in" - } - }, - { - "source": { - "block": "a014971e-5470-490b-9058-b4b00f2dd125", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "sel1" - } - }, - { - "source": { - "block": "1b7db016-c89a-4f65-b6f0-0f87c851c077", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "sel0" - } - }, - { - "source": { - "block": "8be9cded-6d06-4b23-b73c-94c7ff311dbc", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "in3" - } - }, - { - "source": { - "block": "67ed5e09-486d-4f97-929f-aefea9c43951", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "in2" - }, - "vertices": [ - { - "x": 192, - "y": 248 - } - ] - }, - { - "source": { - "block": "5fb29465-2ee7-45bb-afa4-9a3de895c774", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "in1" - }, - "vertices": [ - { - "x": 224, - "y": 168 - } - ] - }, - { - "source": { - "block": "c3f73f68-1074-4355-b69f-6a20f7bea3e7", - "port": "out" - }, - "target": { - "block": "e4eb896c-1039-4d73-aeb0-ce34b933f4c3", - "port": "in0" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/gate/and.ice b/app/resources/blocks/logic/gate/and.ice new file mode 100644 index 000000000..ebb235e4f --- /dev/null +++ b/app/resources/blocks/logic/gate/and.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "AND", + "version": "1.0.0", + "description": "AND logic gate", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27z%22/%3E%3Cpath%20d=%22M-227%20400.9v39.9h20.4c11.3%200%2020-9%2020-20s-8.7-20-20-20H-227zm2.9%202.8h17.6c9.8%200%2016.7%207.6%2016.7%2017.1%200%209.5-7.4%2017.1-17.1%2017.1H-224c-.1.1-.1-34.2-.1-34.2z%22/%3E%3Cpath%20d=%22M-187.911%20419.9H-162v2h-25.911z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// AND logic gate\n\nassign c = a & b;", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/and.iceb b/app/resources/blocks/logic/gate/and.iceb deleted file mode 100644 index 0e8cfc3e4..000000000 --- a/app/resources/blocks/logic/gate/and.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// AND logic gate\n\nassign c = a & b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/and.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} diff --git a/app/resources/blocks/logic/gate/nand.ice b/app/resources/blocks/logic/gate/nand.ice new file mode 100644 index 000000000..3db99ebb5 --- /dev/null +++ b/app/resources/blocks/logic/gate/nand.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "NAND", + "version": "1.0.0", + "description": "NAND logic gate", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27z%22/%3E%3Cpath%20d=%22M-227%20400.9v39.9h20.4c11.3%200%2020-9%2020-20s-8.7-20-20-20H-227zm2.9%202.8h17.6c9.8%200%2016.7%207.6%2016.7%2017.1%200%209.5-7.4%2017.1-17.1%2017.1H-224c-.1.1-.1-34.2-.1-34.2zM-177.3%20419.9h15.3v2h-15.3z%22/%3E%3Cpath%20d=%22M-181.4%20426.3c-2.9%200-5.3-2.4-5.3-5.3s2.4-5.3%205.3-5.3%205.3%202.4%205.3%205.3-2.4%205.3-5.3%205.3zm0-8.6c-1.8%200-3.3%201.5-3.3%203.3%200%201.8%201.5%203.3%203.3%203.3s3.3-1.5%203.3-3.3c0-1.8-1.5-3.3-3.3-3.3z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// NAND logic gate\n\nassign c = ~(a & b);", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/nand.iceb b/app/resources/blocks/logic/gate/nand.iceb deleted file mode 100644 index 48f695d9a..000000000 --- a/app/resources/blocks/logic/gate/nand.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// NAND logic gate\n\nassign c = ~(a & b);", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/nand.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} diff --git a/app/resources/blocks/logic/gate/nor.ice b/app/resources/blocks/logic/gate/nor.ice new file mode 100644 index 000000000..93768b7ca --- /dev/null +++ b/app/resources/blocks/logic/gate/nor.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "NOR", + "version": "1.0.0", + "description": "NOR logic gate", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27zM-177.3%20419.9h15.3v2h-15.3z%22/%3E%3Cpath%20d=%22M-181.4%20426.2c-2.9%200-5.3-2.4-5.3-5.3s2.4-5.3%205.3-5.3%205.3%202.4%205.3%205.3-2.4%205.3-5.3%205.3zm0-8.6c-1.8%200-3.3%201.5-3.3%203.3%200%201.8%201.5%203.3%203.3%203.3s3.3-1.5%203.3-3.3c0-1.8-1.5-3.3-3.3-3.3z%22/%3E%3Cpath%20d=%22M-185.3%20422.6l-.3-2.1.4-1.6c-10.3-17.8-26-18-30.6-18H-233l2%202.4s5.7%207%205.7%2017.6c0%2010.6-5.7%2017.6-5.7%2017.6l-2%202.4h17.2c2.4%200%207.7%200%2013.6-2.4%205.7-2.3%2012-6.9%2017-15.7l-.1-.2zm-18.2%2013.1c-5.4%202.2-9.8%202.2-12.3%202.2H-227c1.9-3.1%204.8-9%204.8-17s-2.9-13.9-4.8-17h11.3c4.7%200%2018.3-.1%2028%2017-4.8%208.4-10.6%2012.7-15.8%2014.8z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// NOR logic gate\n\nassign c = ~(a | b);", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/nor.iceb b/app/resources/blocks/logic/gate/nor.iceb deleted file mode 100644 index c17336847..000000000 --- a/app/resources/blocks/logic/gate/nor.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// NOR logic gate\n\nassign c = ~(a | b);", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/nor.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} diff --git a/app/resources/blocks/logic/gate/not.ice b/app/resources/blocks/logic/gate/not.ice new file mode 100644 index 000000000..e81bd15da --- /dev/null +++ b/app/resources/blocks/logic/gate/not.ice @@ -0,0 +1,109 @@ +{ + "version": "1.1", + "package": { + "name": "NOT", + "version": "1.0.0", + "description": "NOT logic gate", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2291.33%22%20height=%2245.752%22%20version=%221%22%3E%3Cpath%20d=%22M0%2020.446h27v2H0zM70.322%2020.447h15.3v2h-15.3z%22/%3E%3Cpath%20d=%22M66.05%2026.746c-2.9%200-5.3-2.4-5.3-5.3s2.4-5.3%205.3-5.3%205.3%202.4%205.3%205.3-2.4%205.3-5.3%205.3zm0-8.6c-1.8%200-3.3%201.5-3.3%203.3%200%201.8%201.5%203.3%203.3%203.3%201.8%200%203.3-1.5%203.3-3.3%200-1.8-1.5-3.3-3.3-3.3z%22/%3E%3Cpath%20d=%22M25.962%202.563l33.624%2018.883L25.962%2040.33V2.563z%22%20fill=%22none%22%20stroke=%22#000%22%20stroke-width=%223%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "5365ed8c-e5db-4445-938f-8d689830ea5c", + "type": "basic.code", + "data": { + "code": "// NOT logic gate\n\nassign c = ~ a;", + "params": [], + "ports": { + "in": [ + { + "name": "a" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 144 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", + "port": "a" + } + }, + { + "source": { + "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/not.iceb b/app/resources/blocks/logic/gate/not.iceb deleted file mode 100644 index f45c9860c..000000000 --- a/app/resources/blocks/logic/gate/not.iceb +++ /dev/null @@ -1,78 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 144 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "type": "basic.code", - "data": { - "code": "// NOT logic gate\n\nassign c = ~ a;", - "ports": { - "in": [ - "a" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "port": "a" - } - }, - { - "source": { - "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/not.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/or.ice b/app/resources/blocks/logic/gate/or.ice new file mode 100644 index 000000000..2daface97 --- /dev/null +++ b/app/resources/blocks/logic/gate/or.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "OR", + "version": "1.0.0", + "description": "OR logic gate", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2290%22%20height=%2240%22%20version=%221%22%3E%3Cpath%20d=%22M65%2020h25M26%2010H0M27%2030H0%22%20fill=%22none%22%20stroke=%22#000%22%20stroke-width=%222%22/%3E%3Cpath%20d=%22M19.094%200l2%202.438s5.656%207%205.656%2017.562c0%2010.562-5.656%2017.563-5.656%2017.563l-2%202.437H36.25c2.408%200%207.69.025%2013.625-2.406s12.537-7.344%2017.688-16.875L66.25%2020l1.313-.719C57.258.216%2041.007%200%2036.25%200H19.094zm5.875%203H36.25c4.684%200%2018.287-.13%2027.969%2017-4.767%208.43-10.522%2012.684-15.719%2014.813C43.14%2037.008%2038.658%2037%2036.25%2037H25c1.874-3.108%204.75-9.05%204.75-17%200-7.973-2.909-13.9-4.781-17z%22%20fill-rule=%22evenodd%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// OR logic gate\n\nassign c = a | b;", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/or.iceb b/app/resources/blocks/logic/gate/or.iceb deleted file mode 100644 index cbc8d1b5b..000000000 --- a/app/resources/blocks/logic/gate/or.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// OR logic gate\n\nassign c = a | b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/or.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/xnor.ice b/app/resources/blocks/logic/gate/xnor.ice new file mode 100644 index 000000000..c1bf5bce5 --- /dev/null +++ b/app/resources/blocks/logic/gate/xnor.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "XNOR", + "version": "1.0.0", + "description": "XNOR logic gate", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27zM-177.3%20419.9h15.3v2h-15.3z%22/%3E%3Cpath%20d=%22M-181.4%20426.2c-2.9%200-5.3-2.4-5.3-5.3s2.4-5.3%205.3-5.3%205.3%202.4%205.3%205.3-2.4%205.3-5.3%205.3zm0-8.6c-1.8%200-3.3%201.5-3.3%203.3%200%201.8%201.5%203.3%203.3%203.3s3.3-1.5%203.3-3.3c0-1.8-1.5-3.3-3.3-3.3z%22/%3E%3Cpath%20d=%22M-185.3%20422.6l-.3-2.1.4-1.6c-10.3-17.8-26-18-30.6-18H-233l2%202.4s5.7%207%205.7%2017.6c0%2010.6-5.7%2017.6-5.7%2017.6l-2%202.4h17.2c2.4%200%207.7%200%2013.6-2.4%205.7-2.3%2012-6.9%2017-15.7l-.1-.2zm-18.2%2013.1c-5.4%202.2-9.8%202.2-12.3%202.2H-227c1.9-3.1%204.8-9%204.8-17s-2.9-13.9-4.8-17h11.3c4.7%200%2018.3-.1%2028%2017-4.8%208.4-10.6%2012.7-15.8%2014.8z%22/%3E%3Cpath%20d=%22M-238.3%20440.9h3.6c2.3-3.7%206.5-11.6%206.5-19.8%200-8.5-4.4-16.5-6.8-20.2h-3.6c1.4%202%207.4%2011%207.4%2020.2%200%208.9-5.7%2017.7-7.1%2019.8z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// XNOR logic gate\n\nassign c = ~(a ^ b);", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/xnor.iceb b/app/resources/blocks/logic/gate/xnor.iceb deleted file mode 100644 index b50a4a821..000000000 --- a/app/resources/blocks/logic/gate/xnor.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// XNOR logic gate\n\nassign c = ~(a ^ b);", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/xnor.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} diff --git a/app/resources/blocks/logic/gate/xor.ice b/app/resources/blocks/logic/gate/xor.ice new file mode 100644 index 000000000..30a46a1cd --- /dev/null +++ b/app/resources/blocks/logic/gate/xor.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "XOR", + "version": "1.0.0", + "description": "XOR logic gate", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27zM-186.5%20419.9h24.5v2h-24.5z%22/%3E%3Cpath%20d=%22M-184.6%20420.9c0-1-.6-2-.6-2-10.3-17.8-26-18-30.6-18H-233l2%202.4s5.7%207%205.7%2017.6c0%2010.6-5.7%2017.6-5.7%2017.6l-2%202.4h17.2c2.4%200%207.7%200%2013.6-2.4%205.7-2.3%2012-6.9%2017-15.7.1%200%20.6-1%20.6-1.9zm-18.9%2014.8c-5.4%202.2-9.8%202.2-12.3%202.2H-227c1.9-3.1%204.8-9%204.8-17s-2.9-13.9-4.8-17h11.3c4.7%200%2018.3-.1%2028%2017-4.8%208.4-10.6%2012.7-15.8%2014.8z%22/%3E%3Cpath%20d=%22M-238.3%20440.9h3.6c2.3-3.7%206.5-11.6%206.5-19.8%200-8.5-4.4-16.5-6.8-20.2h-3.6c1.4%202%207.4%2011%207.4%2020.2%200%208.9-5.7%2017.7-7.1%2019.8z%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// XOR logic gate\n\nassign c = a ^ b;", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } + }, + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 80 + } + }, + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 752, + "y": 144 + } + }, + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 64, + "y": 208 + } + } + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } + }, + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } + }, + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/gate/xor.iceb b/app/resources/blocks/logic/gate/xor.iceb deleted file mode 100644 index eba78a403..000000000 --- a/app/resources/blocks/logic/gate/xor.iceb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// XOR logic gate\n\nassign c = a ^ b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "resources/images/xor.svg", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} diff --git a/app/resources/blocks/logic/sequential/debouncer.ice b/app/resources/blocks/logic/sequential/debouncer.ice new file mode 100644 index 000000000..f9c78407d --- /dev/null +++ b/app/resources/blocks/logic/sequential/debouncer.ice @@ -0,0 +1,141 @@ +{ + "version": "1.1", + "package": { + "name": "Debouncer", + "version": "1.0.0", + "description": "Remove the rebound on a mechanical switch", + "author": "Juan González", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-251.547%20436.672h22.802v-30.353h5.862v30.353h5.259v-30.353h3.447v30.353h2.984v-30.353h3.506v30.523h6.406V405.77h38.868%22%20fill=%22none%22%20stroke=%22#000%22%20stroke-width=%221.4%22%20stroke-linecap=%22round%22%20stroke-linejoin=%22round%22/%3E%3Cpath%20d=%22M-232.57%20403.877l26.946%2032.391M-205.624%20403.877l-26.946%2032.391%22%20fill=%22none%22%20stroke=%22red%22%20stroke-width=%223%22%20stroke-linecap=%22round%22/%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "92490e7e-c3ba-4e9c-a917-2a771d99f1ef", + "type": "basic.code", + "data": { + "code": "//-- Debouncer Circuit\n//-- It produces a stable output when the\n//-- input signal is bouncing\n\nreg btn_prev = 0;\nreg btn_out_r = 0;\n\nreg [16:0] counter = 0;\n\n\nalways @(posedge clk) begin\n\n //-- If btn_prev and btn_in are differents\n if (btn_prev ^ in == 1'b1) begin\n \n //-- Reset the counter\n counter <= 0;\n \n //-- Capture the button status\n btn_prev <= in;\n end\n \n //-- If no timeout, increase the counter\n else if (counter[16] == 1'b0)\n counter <= counter + 1;\n \n else\n //-- Set the output to the stable value\n btn_out_r <= btn_prev;\n\nend\n\nassign out = btn_out_r;\n", + "params": [], + "ports": { + "in": [ + { + "name": "clk" + }, + { + "name": "in" + } + ], + "out": [ + { + "name": "out" + } + ] + } + }, + "position": { + "x": 264, + "y": 112 + } + }, + { + "id": "4bf41c17-a2da-4140-95f7-2a80d51b1e1a", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 48, + "y": 144 + } + }, + { + "id": "22ff3fa1-943b-4d1a-bd89-36e1c054d077", + "type": "basic.output", + "data": { + "name": "out", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 768, + "y": 208 + } + }, + { + "id": "c9e1af2a-6f09-4cf6-a5b3-fdf7ec2c6530", + "type": "basic.input", + "data": { + "name": "in", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 48, + "y": 272 + } + } + ], + "wires": [ + { + "source": { + "block": "92490e7e-c3ba-4e9c-a917-2a771d99f1ef", + "port": "out" + }, + "target": { + "block": "22ff3fa1-943b-4d1a-bd89-36e1c054d077", + "port": "in" + } + }, + { + "source": { + "block": "4bf41c17-a2da-4140-95f7-2a80d51b1e1a", + "port": "out" + }, + "target": { + "block": "92490e7e-c3ba-4e9c-a917-2a771d99f1ef", + "port": "clk" + } + }, + { + "source": { + "block": "c9e1af2a-6f09-4cf6-a5b3-fdf7ec2c6530", + "port": "out" + }, + "target": { + "block": "92490e7e-c3ba-4e9c-a917-2a771d99f1ef", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/sequential/dff_ar.ice b/app/resources/blocks/logic/sequential/dff_ar.ice new file mode 100644 index 000000000..e623bf232 --- /dev/null +++ b/app/resources/blocks/logic/sequential/dff_ar.ice @@ -0,0 +1,237 @@ +{ + "version": "1.1", + "package": { + "name": "DFF async", + "version": "1.0.0", + "description": "Delay flip-flop with asynchronous reset", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cg%20font-weight=%22400%22%20font-size=%2224.601%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%3E%3Ctext%20y=%22421.867%22%20x=%22-231.121%22%20style=%22line-height:125%25%22%20transform=%22translate(0%20-1.964)%22%3E%3Ctspan%20y=%22421.867%22%20x=%22-231.121%22%3EDFF%3C/tspan%3E%3C/text%3E%3Ctext%20y=%22438.935%22%20x=%22-227.001%22%20style=%22line-height:125%25%22%20transform=%22translate(0%20-1.964)%22%3E%3Ctspan%20y=%22438.935%22%20x=%22-227.001%22%20font-size=%2213.75%22%3Easync%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "type": "basic.input", + "data": { + "name": "D", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 112 + } + }, + { + "id": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "type": "basic.code", + "data": { + "code": "// D flip-flop with asynchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk or negedge rst_n)\nbegin\n if(rst_n == 0)\n _q = 1'b0;\n else if(en)\n _q <= d;\nend\n\nassign {q, q_n} = {_q, ~_q};\n", + "params": [], + "ports": { + "in": [ + { + "name": "d" + }, + { + "name": "en" + }, + { + "name": "rst_n" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "q" + }, + { + "name": "q_n" + } + ] + } + }, + "position": { + "x": 344, + "y": 120 + } + }, + { + "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "type": "basic.output", + "data": { + "name": "Q", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 152 + } + }, + { + "id": "50d69ac2-949d-476e-a711-420ba9f510cd", + "type": "basic.input", + "data": { + "name": "en", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 184 + } + }, + { + "id": "07105e68-401b-49e9-b85f-2cddbfee9fbe", + "type": "basic.input", + "data": { + "name": "rst*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 256 + } + }, + { + "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "type": "basic.output", + "data": { + "name": "Q*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 280 + } + }, + { + "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 328 + } + } + ], + "wires": [ + { + "source": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "q" + }, + "target": { + "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "port": "in" + } + }, + { + "source": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "q_n" + }, + "target": { + "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "port": "in" + } + }, + { + "source": { + "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "port": "out" + }, + "target": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "clk" + } + }, + { + "source": { + "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "port": "out" + }, + "target": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "d" + } + }, + { + "source": { + "block": "50d69ac2-949d-476e-a711-420ba9f510cd", + "port": "out" + }, + "target": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "en" + } + }, + { + "source": { + "block": "07105e68-401b-49e9-b85f-2cddbfee9fbe", + "port": "out" + }, + "target": { + "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", + "port": "rst_n" + } + } + ] + }, + "state": { + "pan": { + "x": -100, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/sequential/dff_ar.iceb b/app/resources/blocks/logic/sequential/dff_ar.iceb deleted file mode 100644 index 346b5ebe0..000000000 --- a/app/resources/blocks/logic/sequential/dff_ar.iceb +++ /dev/null @@ -1,166 +0,0 @@ -{ - "image": "resources/images/dff_ar.svg", - "state": { - "pan": { - "x": -100, - "y": 0 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "type": "basic.output", - "data": { - "label": "Q" - }, - "position": { - "x": 824, - "y": 152 - } - }, - { - "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "type": "basic.output", - "data": { - "label": "Q*" - }, - "position": { - "x": 824, - "y": 280 - } - }, - { - "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "type": "basic.input", - "data": { - "label": "D" - }, - "position": { - "x": 168, - "y": 112 - } - }, - { - "id": "50d69ac2-949d-476e-a711-420ba9f510cd", - "type": "basic.input", - "data": { - "label": "en" - }, - "position": { - "x": 168, - "y": 184 - } - }, - { - "id": "07105e68-401b-49e9-b85f-2cddbfee9fbe", - "type": "basic.input", - "data": { - "label": "rst*" - }, - "position": { - "x": 168, - "y": 256 - } - }, - { - "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "type": "basic.input", - "data": { - "label": "clk" - }, - "position": { - "x": 168, - "y": 328 - } - }, - { - "id": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "type": "basic.code", - "data": { - "code": "// D flip-flop with asynchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk or negedge rst_n)\nbegin\n if(rst_n == 0)\n _q = 1'b0;\n else if(en)\n _q <= d;\nend\n\nassign {q, q_n} = {_q, ~_q};\n", - "ports": { - "in": [ - "d", - "en", - "rst_n", - "clk" - ], - "out": [ - "q", - "q_n" - ] - } - }, - "position": { - "x": 344, - "y": 120 - } - } - ], - "wires": [ - { - "source": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "q" - }, - "target": { - "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "port": "in" - } - }, - { - "source": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "q_n" - }, - "target": { - "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "port": "in" - } - }, - { - "source": { - "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "port": "out" - }, - "target": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "clk" - } - }, - { - "source": { - "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "port": "out" - }, - "target": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "d" - } - }, - { - "source": { - "block": "50d69ac2-949d-476e-a711-420ba9f510cd", - "port": "out" - }, - "target": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "en" - } - }, - { - "source": { - "block": "07105e68-401b-49e9-b85f-2cddbfee9fbe", - "port": "out" - }, - "target": { - "block": "cfacb99e-850b-4ddc-a25b-fda4c93f1c5a", - "port": "rst_n" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/sequential/dff_sr.ice b/app/resources/blocks/logic/sequential/dff_sr.ice new file mode 100644 index 000000000..10d174586 --- /dev/null +++ b/app/resources/blocks/logic/sequential/dff_sr.ice @@ -0,0 +1,237 @@ +{ + "version": "1.1", + "package": { + "name": "DFF", + "version": "1.0.0", + "description": "Delay flip-flop with synchronous reset", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22-231.121%22%20y=%22429.867%22%20font-weight=%22400%22%20font-size=%2224.601%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%3E%3Ctspan%20x=%22-231.121%22%20y=%22429.867%22%3EDFF%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "type": "basic.input", + "data": { + "name": "D", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 104 + } + }, + { + "id": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "type": "basic.code", + "data": { + "code": "// D flip-flop with synchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk)\nbegin\n if(rst_n == 0)\n _q = 1'b0;\n else if(en)\n _q <= d;\nend\n\nassign {q, q_n} = {_q, ~_q};\n", + "params": [], + "ports": { + "in": [ + { + "name": "d" + }, + { + "name": "en" + }, + { + "name": "rst_n" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "q" + }, + { + "name": "q_n" + } + ] + } + }, + "position": { + "x": 344, + "y": 120 + } + }, + { + "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "type": "basic.output", + "data": { + "name": "Q", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 152 + } + }, + { + "id": "50d69ac2-949d-476e-a711-420ba9f510cd", + "type": "basic.input", + "data": { + "name": "en", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 176 + } + }, + { + "id": "07105e68-401b-49e9-b85f-2cddbfee9fbe", + "type": "basic.input", + "data": { + "name": "rst*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 256 + } + }, + { + "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "type": "basic.output", + "data": { + "name": "Q*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 280 + } + }, + { + "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 328 + } + } + ], + "wires": [ + { + "source": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "q" + }, + "target": { + "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "port": "in" + } + }, + { + "source": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "q_n" + }, + "target": { + "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "port": "in" + } + }, + { + "source": { + "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "port": "out" + }, + "target": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "d" + } + }, + { + "source": { + "block": "50d69ac2-949d-476e-a711-420ba9f510cd", + "port": "out" + }, + "target": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "en" + } + }, + { + "source": { + "block": "07105e68-401b-49e9-b85f-2cddbfee9fbe", + "port": "out" + }, + "target": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "rst_n" + } + }, + { + "source": { + "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "port": "out" + }, + "target": { + "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", + "port": "clk" + } + } + ] + }, + "state": { + "pan": { + "x": -100, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/sequential/dff_sr.iceb b/app/resources/blocks/logic/sequential/dff_sr.iceb deleted file mode 100644 index 8b7af360a..000000000 --- a/app/resources/blocks/logic/sequential/dff_sr.iceb +++ /dev/null @@ -1,166 +0,0 @@ -{ - "image": "resources/images/dff_sr.svg", - "state": { - "pan": { - "x": -100, - "y": 0 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "type": "basic.output", - "data": { - "label": "Q" - }, - "position": { - "x": 824, - "y": 152 - } - }, - { - "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "type": "basic.output", - "data": { - "label": "Q*" - }, - "position": { - "x": 824, - "y": 280 - } - }, - { - "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "type": "basic.input", - "data": { - "label": "D" - }, - "position": { - "x": 168, - "y": 104 - } - }, - { - "id": "50d69ac2-949d-476e-a711-420ba9f510cd", - "type": "basic.input", - "data": { - "label": "en" - }, - "position": { - "x": 168, - "y": 176 - } - }, - { - "id": "07105e68-401b-49e9-b85f-2cddbfee9fbe", - "type": "basic.input", - "data": { - "label": "rst*" - }, - "position": { - "x": 168, - "y": 256 - } - }, - { - "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "type": "basic.input", - "data": { - "label": "clk" - }, - "position": { - "x": 168, - "y": 328 - } - }, - { - "id": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "type": "basic.code", - "data": { - "code": "// D flip-flop with synchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk)\nbegin\n if(rst_n == 0)\n _q = 1'b0;\n else if(en)\n _q <= d;\nend\n\nassign {q, q_n} = {_q, ~_q};\n", - "ports": { - "in": [ - "d", - "en", - "rst_n", - "clk" - ], - "out": [ - "q", - "q_n" - ] - } - }, - "position": { - "x": 344, - "y": 120 - } - } - ], - "wires": [ - { - "source": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "q" - }, - "target": { - "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "port": "in" - } - }, - { - "source": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "q_n" - }, - "target": { - "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "port": "in" - } - }, - { - "source": { - "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "port": "out" - }, - "target": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "d" - } - }, - { - "source": { - "block": "50d69ac2-949d-476e-a711-420ba9f510cd", - "port": "out" - }, - "target": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "en" - } - }, - { - "source": { - "block": "07105e68-401b-49e9-b85f-2cddbfee9fbe", - "port": "out" - }, - "target": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "rst_n" - } - }, - { - "source": { - "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "port": "out" - }, - "target": { - "block": "17c79db9-4b5b-4a7c-9f13-c4c9f9e5a4e5", - "port": "clk" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/sequential/tff_ar.ice b/app/resources/blocks/logic/sequential/tff_ar.ice new file mode 100644 index 000000000..4ddcd0ea2 --- /dev/null +++ b/app/resources/blocks/logic/sequential/tff_ar.ice @@ -0,0 +1,237 @@ +{ + "version": "1.1", + "package": { + "name": "TFF async", + "version": "1.0.0", + "description": "Toggle flip-flop with asynchronous reset", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cg%20font-weight=%22400%22%20font-size=%2224.601%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22-227.932%22%20y=%22421.867%22%20transform=%22translate(0%20-1.964)%22%3E%3Ctspan%20x=%22-227.932%22%20y=%22421.867%22%3ETFF%3C/tspan%3E%3C/text%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22-227.001%22%20y=%22438.935%22%20transform=%22translate(0%20-1.964)%22%3E%3Ctspan%20x=%22-227.001%22%20y=%22438.935%22%20font-size=%2213.75%22%3Easync%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "type": "basic.input", + "data": { + "name": "T", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 112 + } + }, + { + "id": "075956ce-9af4-49ea-9123-91786feaba4d", + "type": "basic.code", + "data": { + "code": "// T flip-flop with asynchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk or negedge rst_n)\nbegin\n if(rst_n == 0)\n _q <= 1'b0;\n else\n if(en & t)\n _q = ~_q;\nend\n\nassign {q, q_n} = {_q, ~_q};", + "params": [], + "ports": { + "in": [ + { + "name": "t" + }, + { + "name": "en" + }, + { + "name": "rst_n" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "q" + }, + { + "name": "q_n" + } + ] + } + }, + "position": { + "x": 344, + "y": 120 + } + }, + { + "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "type": "basic.output", + "data": { + "name": "Q", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 152 + } + }, + { + "id": "50d69ac2-949d-476e-a711-420ba9f510cd", + "type": "basic.input", + "data": { + "name": "en", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 184 + } + }, + { + "id": "8fa94192-fba9-4c2a-be61-b8ca88389423", + "type": "basic.input", + "data": { + "name": "rst*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 256 + } + }, + { + "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "type": "basic.output", + "data": { + "name": "Q*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 280 + } + }, + { + "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 328 + } + } + ], + "wires": [ + { + "source": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "q" + }, + "target": { + "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "port": "in" + } + }, + { + "source": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "q_n" + }, + "target": { + "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "port": "in" + } + }, + { + "source": { + "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "port": "out" + }, + "target": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "clk" + } + }, + { + "source": { + "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "port": "out" + }, + "target": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "t" + } + }, + { + "source": { + "block": "50d69ac2-949d-476e-a711-420ba9f510cd", + "port": "out" + }, + "target": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "en" + } + }, + { + "source": { + "block": "8fa94192-fba9-4c2a-be61-b8ca88389423", + "port": "out" + }, + "target": { + "block": "075956ce-9af4-49ea-9123-91786feaba4d", + "port": "rst_n" + } + } + ] + }, + "state": { + "pan": { + "x": -100, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/sequential/tff_ar.iceb b/app/resources/blocks/logic/sequential/tff_ar.iceb deleted file mode 100644 index 96121cf49..000000000 --- a/app/resources/blocks/logic/sequential/tff_ar.iceb +++ /dev/null @@ -1,166 +0,0 @@ -{ - "image": "resources/images/tff_ar.svg", - "state": { - "pan": { - "x": -100, - "y": 0 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "type": "basic.output", - "data": { - "label": "Q" - }, - "position": { - "x": 824, - "y": 152 - } - }, - { - "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "type": "basic.output", - "data": { - "label": "Q*" - }, - "position": { - "x": 824, - "y": 280 - } - }, - { - "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "type": "basic.input", - "data": { - "label": "T" - }, - "position": { - "x": 168, - "y": 112 - } - }, - { - "id": "50d69ac2-949d-476e-a711-420ba9f510cd", - "type": "basic.input", - "data": { - "label": "en" - }, - "position": { - "x": 168, - "y": 184 - } - }, - { - "id": "8fa94192-fba9-4c2a-be61-b8ca88389423", - "type": "basic.input", - "data": { - "label": "rst*" - }, - "position": { - "x": 168, - "y": 256 - } - }, - { - "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "type": "basic.input", - "data": { - "label": "clk" - }, - "position": { - "x": 168, - "y": 328 - } - }, - { - "id": "075956ce-9af4-49ea-9123-91786feaba4d", - "type": "basic.code", - "data": { - "code": "// T flip-flop with asynchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk or negedge rst_n)\nbegin\n if(rst_n == 0)\n _q <= 1'b0;\n else\n if(en & t)\n _q = ~_q;\nend\n\nassign {q, q_n} = {_q, ~_q};", - "ports": { - "in": [ - "t", - "en", - "rst_n", - "clk" - ], - "out": [ - "q", - "q_n" - ] - } - }, - "position": { - "x": 344, - "y": 120 - } - } - ], - "wires": [ - { - "source": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "q" - }, - "target": { - "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "port": "in" - } - }, - { - "source": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "q_n" - }, - "target": { - "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "port": "in" - } - }, - { - "source": { - "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "port": "out" - }, - "target": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "clk" - } - }, - { - "source": { - "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "port": "out" - }, - "target": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "t" - } - }, - { - "source": { - "block": "50d69ac2-949d-476e-a711-420ba9f510cd", - "port": "out" - }, - "target": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "en" - } - }, - { - "source": { - "block": "8fa94192-fba9-4c2a-be61-b8ca88389423", - "port": "out" - }, - "target": { - "block": "075956ce-9af4-49ea-9123-91786feaba4d", - "port": "rst_n" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/blocks/logic/sequential/tff_sr.ice b/app/resources/blocks/logic/sequential/tff_sr.ice new file mode 100644 index 000000000..1d2786f39 --- /dev/null +++ b/app/resources/blocks/logic/sequential/tff_sr.ice @@ -0,0 +1,237 @@ +{ + "version": "1.1", + "package": { + "name": "TFF", + "version": "1.0.0", + "description": "Toggle flip-flop with synchronous reset", + "author": "Carlos Diaz", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22-227.932%22%20y=%22429.867%22%20font-weight=%22400%22%20font-size=%2224.601%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%3E%3Ctspan%20x=%22-227.932%22%20y=%22429.867%22%3ETFF%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "type": "basic.input", + "data": { + "name": "T", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 104 + } + }, + { + "id": "163997db-34b5-4c61-a06c-5ab94207674a", + "type": "basic.code", + "data": { + "code": "// T flip-flop with synchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk)\nbegin\n if(rst_n == 0)\n _q <= 1'b0;\n else\n if(en & t)\n _q = ~_q;\nend\n\nassign {q, q_n} = {_q, ~_q};", + "params": [], + "ports": { + "in": [ + { + "name": "t" + }, + { + "name": "en" + }, + { + "name": "rst_n" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "q" + }, + { + "name": "q_n" + } + ] + } + }, + "position": { + "x": 344, + "y": 120 + } + }, + { + "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "type": "basic.output", + "data": { + "name": "Q", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 152 + } + }, + { + "id": "50d69ac2-949d-476e-a711-420ba9f510cd", + "type": "basic.input", + "data": { + "name": "en", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 176 + } + }, + { + "id": "8fa94192-fba9-4c2a-be61-b8ca88389423", + "type": "basic.input", + "data": { + "name": "rst*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 256 + } + }, + { + "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "type": "basic.output", + "data": { + "name": "Q*", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 824, + "y": 280 + } + }, + { + "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "", + "value": "0" + } + ], + "virtual": true + }, + "position": { + "x": 168, + "y": 328 + } + } + ], + "wires": [ + { + "source": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "q" + }, + "target": { + "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", + "port": "in" + } + }, + { + "source": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "q_n" + }, + "target": { + "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", + "port": "in" + } + }, + { + "source": { + "block": "50d69ac2-949d-476e-a711-420ba9f510cd", + "port": "out" + }, + "target": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "en" + } + }, + { + "source": { + "block": "8fa94192-fba9-4c2a-be61-b8ca88389423", + "port": "out" + }, + "target": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "rst_n" + } + }, + { + "source": { + "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", + "port": "out" + }, + "target": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "t" + } + }, + { + "source": { + "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", + "port": "out" + }, + "target": { + "block": "163997db-34b5-4c61-a06c-5ab94207674a", + "port": "clk" + } + } + ] + }, + "state": { + "pan": { + "x": -100, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": {} +} \ No newline at end of file diff --git a/app/resources/blocks/logic/sequential/tff_sr.iceb b/app/resources/blocks/logic/sequential/tff_sr.iceb deleted file mode 100644 index 520deba8d..000000000 --- a/app/resources/blocks/logic/sequential/tff_sr.iceb +++ /dev/null @@ -1,166 +0,0 @@ -{ - "image": "resources/images/tff_sr.svg", - "state": { - "pan": { - "x": -100, - "y": 0 - }, - "zoom": 1 - }, - "graph": { - "blocks": [ - { - "id": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "type": "basic.output", - "data": { - "label": "Q" - }, - "position": { - "x": 824, - "y": 152 - } - }, - { - "id": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "type": "basic.output", - "data": { - "label": "Q*" - }, - "position": { - "x": 824, - "y": 280 - } - }, - { - "id": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "type": "basic.input", - "data": { - "label": "T" - }, - "position": { - "x": 168, - "y": 104 - } - }, - { - "id": "50d69ac2-949d-476e-a711-420ba9f510cd", - "type": "basic.input", - "data": { - "label": "en" - }, - "position": { - "x": 168, - "y": 176 - } - }, - { - "id": "8fa94192-fba9-4c2a-be61-b8ca88389423", - "type": "basic.input", - "data": { - "label": "rst*" - }, - "position": { - "x": 168, - "y": 256 - } - }, - { - "id": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "type": "basic.input", - "data": { - "label": "clk" - }, - "position": { - "x": 168, - "y": 328 - } - }, - { - "id": "163997db-34b5-4c61-a06c-5ab94207674a", - "type": "basic.code", - "data": { - "code": "// T flip-flop with synchronous reset\n\nreg _q = 1'b0;\n\nalways @(posedge clk)\nbegin\n if(rst_n == 0)\n _q <= 1'b0;\n else\n if(en & t)\n _q = ~_q;\nend\n\nassign {q, q_n} = {_q, ~_q};", - "ports": { - "in": [ - "t", - "en", - "rst_n", - "clk" - ], - "out": [ - "q", - "q_n" - ] - } - }, - "position": { - "x": 344, - "y": 120 - } - } - ], - "wires": [ - { - "source": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "q" - }, - "target": { - "block": "ffdd9aa2-aea3-4aa9-8431-80e799226774", - "port": "in" - } - }, - { - "source": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "q_n" - }, - "target": { - "block": "4a261f0b-523c-4fe0-ae1c-de05b8eb7e8a", - "port": "in" - } - }, - { - "source": { - "block": "50d69ac2-949d-476e-a711-420ba9f510cd", - "port": "out" - }, - "target": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "en" - } - }, - { - "source": { - "block": "8fa94192-fba9-4c2a-be61-b8ca88389423", - "port": "out" - }, - "target": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "rst_n" - } - }, - { - "source": { - "block": "b32a6101-5bd1-4bcf-ae5f-e569b958a6a2", - "port": "out" - }, - "target": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "t" - } - }, - { - "source": { - "block": "6855f64f-fa1c-4371-b2e1-a98970674a96", - "port": "out" - }, - "target": { - "block": "163997db-34b5-4c61-a06c-5ab94207674a", - "port": "clk" - } - } - ] - }, - "deps": {} -} diff --git a/app/resources/boards/iCE40-HX8K/pinout.json b/app/resources/boards/iCE40-HX8K/pinout.json index ab7f19a63..a537f2df7 100644 --- a/app/resources/boards/iCE40-HX8K/pinout.json +++ b/app/resources/boards/iCE40-HX8K/pinout.json @@ -1 +1 @@ -{"pinout": [{"name": "LED0", "value": "B5"}, {"name": "LED1", "value": "B4"}, {"name": "LED2", "value": "A2"}, {"name": "LED3", "value": "A1"}, {"name": "LED4", "value": "C5"}, {"name": "LED5", "value": "C4"}, {"name": "LED6", "value": "B3"}, {"name": "LED7", "value": "C3"}, {"name": "CLK", "value": "J3"}, {"name": "MISO", "value": "P12"}, {"name": "MOSI", "value": "P11"}, {"name": "SCK", "value": "R11"}, {"name": "SS", "value": "R12"}, {"name": "RTS", "value": "B13"}, {"name": "RESET", "value": "N11"}, {"name": "DONE", "value": "M10"}, {"name": "TX", "value": "B12"}, {"name": "RX", "value": "B10"}, {"name": "DCD", "value": "B15"}, {"name": "DSR", "value": "B14"}, {"name": "DTR", "value": "A16"}, {"name": "CTS", "value": "A15"}, {"name": "A16", "value": "A16"}, {"name": "A15", "value": "A15"}, {"name": "B15", "value": "B15"}, {"name": "B13", "value": "B13"}, {"name": "B14", "value": "B14"}, {"name": "B12", "value": "B12"}, {"name": "B11", "value": "B11"}, {"name": "A11", "value": "A11"}, {"name": "B10", "value": "B10"}, {"name": "A10", "value": "A10"}, {"name": "C9", "value": "C9"}, {"name": "A9", "value": "A9"}, {"name": "B9", "value": "B9"}, {"name": "B8", "value": "B8"}, {"name": "A7", "value": "A7"}, {"name": "B7", "value": "B7"}, {"name": "C7", "value": "C7"}, {"name": "A6", "value": "A6"}, {"name": "C6", "value": "C6"}, {"name": "B6", "value": "B6"}, {"name": "C5", "value": "C5"}, {"name": "A5", "value": "A5"}, {"name": "C4", "value": "C4"}, {"name": "B5", "value": "B5"}, {"name": "C3", "value": "C3"}, {"name": "B4", "value": "B4"}, {"name": "B3", "value": "B3"}, {"name": "A2", "value": "A2"}, {"name": "A1", "value": "A1"}, {"name": "R15", "value": "R15"}, {"name": "P16", "value": "P16"}, {"name": "P15", "value": "P15"}, {"name": "N16", "value": "N16"}, {"name": "M15", "value": "M15"}, {"name": "M16", "value": "M16"}, {"name": "L16", "value": "L16"}, {"name": "K15", "value": "K15"}, {"name": "K16", "value": "K16"}, {"name": "K14", "value": "K14"}, {"name": "J14", "value": "J14"}, {"name": "G14", "value": "G14"}, {"name": "F14", "value": "F14"}, {"name": "J15", "value": "J15"}, {"name": "H14", "value": "H14"}, {"name": "H16", "value": "H16"}, {"name": "G15", "value": "G15"}, {"name": "G16", "value": "G16"}, {"name": "F15", "value": "F15"}, {"name": "F16", "value": "F16"}, {"name": "E14", "value": "E14"}, {"name": "E16", "value": "E16"}, {"name": "D15", "value": "D15"}, {"name": "D14", "value": "D14"}, {"name": "B16", "value": "B16"}, {"name": "C16", "value": "C16"}, {"name": "B16", "value": "B16"}, {"name": "R16", "value": "R16"}, {"name": "T15", "value": "T15"}, {"name": "T16", "value": "T16"}, {"name": "T13", "value": "T13"}, {"name": "T14", "value": "T14"}, {"name": "N12", "value": "N12"}, {"name": "P13", "value": "P13"}, {"name": "N10", "value": "N10"}, {"name": "M11", "value": "M11"}, {"name": "T11", "value": "T11"}, {"name": "P10", "value": "P10"}, {"name": "T10", "value": "T10"}, {"name": "R10", "value": "R10"}, {"name": "P8", "value": "P8"}, {"name": "P9", "value": "P9"}, {"name": "T9", "value": "T9"}, {"name": "R9", "value": "R9"}, {"name": "T7", "value": "T7"}, {"name": "T8", "value": "T8"}, {"name": "T6", "value": "T6"}, {"name": "R6", "value": "R6"}, {"name": "T5", "value": "T5"}, {"name": "R5", "value": "R5"}, {"name": "R3", "value": "R3"}, {"name": "R4", "value": "R4"}, {"name": "R2", "value": "R2"}, {"name": "T3", "value": "T3"}, {"name": "T1", "value": "T1"}, {"name": "T2", "value": "T2"}, {"name": "R1", "value": "R1"}, {"name": "P1", "value": "P1"}, {"name": "P2", "value": "P2"}, {"name": "N3", "value": "N3"}, {"name": "N2", "value": "N2"}, {"name": "M2", "value": "M2"}, {"name": "M1", "value": "M1"}, {"name": "L3", "value": "L3"}, {"name": "L1", "value": "L1"}, {"name": "K3", "value": "K3"}, {"name": "K1", "value": "K1"}, {"name": "J2", "value": "J2"}, {"name": "J1", "value": "J1"}, {"name": "H2", "value": "H2"}, {"name": "J3", "value": "J3"}, {"name": "G2", "value": "G2"}, {"name": "H1", "value": "H1"}, {"name": "F2", "value": "F2"}, {"name": "G1", "value": "G1"}, {"name": "E2", "value": "E2"}, {"name": "F1", "value": "F1"}, {"name": "D1", "value": "D1"}, {"name": "D2", "value": "D2"}, {"name": "C1", "value": "C1"}, {"name": "C2", "value": "C2"}, {"name": "B2", "value": "B2"}, {"name": "B1", "value": ""}], "label": "iCE40-HX8K"} \ No newline at end of file +[{"name": "LED0", "value": "B5"}, {"name": "LED1", "value": "B4"}, {"name": "LED2", "value": "A2"}, {"name": "LED3", "value": "A1"}, {"name": "LED4", "value": "C5"}, {"name": "LED5", "value": "C4"}, {"name": "LED6", "value": "B3"}, {"name": "LED7", "value": "C3"}, {"name": "CLK", "value": "J3"}, {"name": "MISO", "value": "P12"}, {"name": "MOSI", "value": "P11"}, {"name": "SCK", "value": "R11"}, {"name": "SS", "value": "R12"}, {"name": "RTS", "value": "B13"}, {"name": "RESET", "value": "N11"}, {"name": "DONE", "value": "M10"}, {"name": "TX", "value": "B12"}, {"name": "RX", "value": "B10"}, {"name": "DCD", "value": "B15"}, {"name": "DSR", "value": "B14"}, {"name": "DTR", "value": "A16"}, {"name": "CTS", "value": "A15"}, {"name": "A16", "value": "A16"}, {"name": "A15", "value": "A15"}, {"name": "B15", "value": "B15"}, {"name": "B13", "value": "B13"}, {"name": "B14", "value": "B14"}, {"name": "B12", "value": "B12"}, {"name": "B11", "value": "B11"}, {"name": "A11", "value": "A11"}, {"name": "B10", "value": "B10"}, {"name": "A10", "value": "A10"}, {"name": "C9", "value": "C9"}, {"name": "A9", "value": "A9"}, {"name": "B9", "value": "B9"}, {"name": "B8", "value": "B8"}, {"name": "A7", "value": "A7"}, {"name": "B7", "value": "B7"}, {"name": "C7", "value": "C7"}, {"name": "A6", "value": "A6"}, {"name": "C6", "value": "C6"}, {"name": "B6", "value": "B6"}, {"name": "C5", "value": "C5"}, {"name": "A5", "value": "A5"}, {"name": "C4", "value": "C4"}, {"name": "B5", "value": "B5"}, {"name": "C3", "value": "C3"}, {"name": "B4", "value": "B4"}, {"name": "B3", "value": "B3"}, {"name": "A2", "value": "A2"}, {"name": "A1", "value": "A1"}, {"name": "R15", "value": "R15"}, {"name": "P16", "value": "P16"}, {"name": "P15", "value": "P15"}, {"name": "N16", "value": "N16"}, {"name": "M15", "value": "M15"}, {"name": "M16", "value": "M16"}, {"name": "L16", "value": "L16"}, {"name": "K15", "value": "K15"}, {"name": "K16", "value": "K16"}, {"name": "K14", "value": "K14"}, {"name": "J14", "value": "J14"}, {"name": "G14", "value": "G14"}, {"name": "F14", "value": "F14"}, {"name": "J15", "value": "J15"}, {"name": "H14", "value": "H14"}, {"name": "H16", "value": "H16"}, {"name": "G15", "value": "G15"}, {"name": "G16", "value": "G16"}, {"name": "F15", "value": "F15"}, {"name": "F16", "value": "F16"}, {"name": "E14", "value": "E14"}, {"name": "E16", "value": "E16"}, {"name": "D15", "value": "D15"}, {"name": "D16", "value": "D16"}, {"name": "D14", "value": "D14"}, {"name": "C16", "value": "C16"}, {"name": "B16", "value": "B16"}, {"name": "R16", "value": "R16"}, {"name": "T15", "value": "T15"}, {"name": "T16", "value": "T16"}, {"name": "T13", "value": "T13"}, {"name": "T14", "value": "T14"}, {"name": "N12", "value": "N12"}, {"name": "P13", "value": "P13"}, {"name": "N10", "value": "N10"}, {"name": "M11", "value": "M11"}, {"name": "T11", "value": "T11"}, {"name": "P10", "value": "P10"}, {"name": "T10", "value": "T10"}, {"name": "R10", "value": "R10"}, {"name": "P8", "value": "P8"}, {"name": "P9", "value": "P9"}, {"name": "T9", "value": "T9"}, {"name": "R9", "value": "R9"}, {"name": "T7", "value": "T7"}, {"name": "T8", "value": "T8"}, {"name": "T6", "value": "T6"}, {"name": "R6", "value": "R6"}, {"name": "T5", "value": "T5"}, {"name": "R5", "value": "R5"}, {"name": "R3", "value": "R3"}, {"name": "R4", "value": "R4"}, {"name": "R2", "value": "R2"}, {"name": "T3", "value": "T3"}, {"name": "T1", "value": "T1"}, {"name": "T2", "value": "T2"}, {"name": "R1", "value": "R1"}, {"name": "P1", "value": "P1"}, {"name": "P2", "value": "P2"}, {"name": "N3", "value": "N3"}, {"name": "N2", "value": "N2"}, {"name": "M2", "value": "M2"}, {"name": "M1", "value": "M1"}, {"name": "L3", "value": "L3"}, {"name": "L1", "value": "L1"}, {"name": "K3", "value": "K3"}, {"name": "K1", "value": "K1"}, {"name": "J2", "value": "J2"}, {"name": "J1", "value": "J1"}, {"name": "H2", "value": "H2"}, {"name": "J3", "value": "J3"}, {"name": "G2", "value": "G2"}, {"name": "H1", "value": "H1"}, {"name": "F2", "value": "F2"}, {"name": "G1", "value": "G1"}, {"name": "E2", "value": "E2"}, {"name": "F1", "value": "F1"}, {"name": "D1", "value": "D1"}, {"name": "D2", "value": "D2"}, {"name": "C1", "value": "C1"}, {"name": "C2", "value": "C2"}, {"name": "B1", "value": "B1"}, {"name": "B2", "value": "B2"}] \ No newline at end of file diff --git a/app/resources/boards/iCE40-HX8K/pinout.pcf b/app/resources/boards/iCE40-HX8K/pinout.pcf index 177ea7be5..4e5bb62b8 100644 --- a/app/resources/boards/iCE40-HX8K/pinout.pcf +++ b/app/resources/boards/iCE40-HX8K/pinout.pcf @@ -167,8 +167,8 @@ set_io --warn-no-port F16 F16 set_io --warn-no-port E14 E14 set_io --warn-no-port E16 E16 set_io --warn-no-port D15 D15 +set_io --warn-no-port D16 D16 set_io --warn-no-port D14 D14 -set_io --warn-no-port B16 B16 set_io --warn-no-port C16 C16 set_io --warn-no-port B16 B16 @@ -296,5 +296,5 @@ set_io --warn-no-port D1 D1 set_io --warn-no-port D2 D2 set_io --warn-no-port C1 C1 set_io --warn-no-port C2 C2 -set_io --warn-no-port B2 B2 set_io --warn-no-port B1 B1 +set_io --warn-no-port B2 B2 diff --git a/app/resources/examples/icestick/1_basic/1_led_on.ice b/app/resources/examples/icestick/1_basic/1_led_on.ice index a4aad45ce..d7e220c22 100644 --- a/app/resources/examples/icestick/1_basic/1_led_on.ice +++ b/app/resources/examples/icestick/1_basic/1_led_on.ice @@ -1,129 +1,151 @@ { - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 + "version": "1.1", + "package": { + "name": "Led on", + "version": "1.0.0", + "description": "", + "author": "", + "image": "" }, - "board": "icestick", - "graph": { - "blocks": [ - { - "id": "a538a5b4-d5d5-4ace-a593-efb1fa9b930c", - "type": "basic.info", - "data": { - "info": "LED-ON Hello world circuit example!\n\nThe simplest digital circuit that turns a \nled on\n\nA bit set to 1 is wired directly to the\noutput FPGA pin, where the led is connected\n\nThe blue box is the bit (set to 1)\nIt is inside the FPGA\n\nThe yellow box is the output FPGA pin. Using\nthe bottom menu the pin can be changed\n\nEXERCISE 1: Upload this circuit into your \nFPGA board and watch the led. \nIt should be turned on\n\nEXERCISE 2: Change the pin number to turn\nanother led on and upload it again" + "design": { + "board": "icestick", + "graph": { + "blocks": [ + { + "id": "eaf792b5-de98-4e2f-b78a-4023eb9a7f2b", + "type": "3e6c249e205080168c1bf4ee8dbc33b50653d5f4", + "position": { + "x": 80, + "y": 64 + } }, - "position": { - "x": 40, - "y": 208 - } - }, - { - "id": "0d05784e-8e32-4c80-b85d-cde4e892dbf3", - "type": "basic.info", - "data": { - "info": "Ejemplo de circuito Hola mundo: LED-ON\n\nEs el circuito digital más sencillo que\nenciende un led\n\nUn bit a 1 se cablea directamente a una\nsalida de la FPGA, donde está conectado\nel LED\n\nLa caja azul es el bit a 1\nEstá dentro de la FPGA\n\nLa caja amarilla es el pin de salida de\nla FPGA. Por medio del menú desplegable\ninferior se puede cambiar el pin\n\nEJERCICIO 1: Carga este circuito en la FPGA\ny observa el LED0. Debe estar encendido\n\nEJERCICIO 2: Cambia el pin de salida para\nencender otro led (por ejemplo el LED1)\ny cárgalo en la FPGA de nuevo" + { + "id": "949075cb-26c0-49da-ba76-2496ea9aa7cc", + "type": "basic.output", + "data": { + "name": "led", + "pins": [ + { + "index": "0", + "name": "D1", + "value": "99" + } + ], + "virtual": false + }, + "position": { + "x": 352, + "y": 64 + } }, - "position": { - "x": 464, - "y": 208 - } - }, - { - "id": "e657ee6f-9430-4fce-a539-72d12d32f5bb", - "type": "bit.1", - "data": {}, - "position": { - "x": 80, - "y": 64 - } - }, - { - "id": "949075cb-26c0-49da-ba76-2496ea9aa7cc", - "type": "basic.output", - "data": { - "label": "led", - "pin": { - "name": "D1", - "value": "99" + { + "id": "a538a5b4-d5d5-4ace-a593-efb1fa9b930c", + "type": "basic.info", + "data": { + "info": "LED-ON Hello world circuit example!\n\nThe simplest digital circuit that turns a \nled on\n\nA bit set to 1 is wired directly to the\noutput FPGA pin, where the led is connected\n\nThe blue box is the bit (set to 1)\nIt is inside the FPGA\n\nThe yellow box is the output FPGA pin. Using\nthe bottom menu the pin can be changed\n\nEXERCISE 1: Upload this circuit into your \nFPGA board and watch the led. \nIt should be turned on\n\nEXERCISE 2: Change the pin number to turn\nanother led on and upload it again" + }, + "position": { + "x": 40, + "y": 208 } }, - "position": { - "x": 352, - "y": 64 + { + "id": "0d05784e-8e32-4c80-b85d-cde4e892dbf3", + "type": "basic.info", + "data": { + "info": "Ejemplo de circuito Hola mundo: LED-ON\n\nEs el circuito digital más sencillo que\nenciende un led\n\nUn bit a 1 se cablea directamente a una\nsalida de la FPGA, donde está conectado\nel LED\n\nLa caja azul es el bit a 1\nEstá dentro de la FPGA\n\nLa caja amarilla es el pin de salida de\nla FPGA. Por medio del menú desplegable\ninferior se puede cambiar el pin\n\nEJERCICIO 1: Carga este circuito en la FPGA\ny observa el LED0. Debe estar encendido\n\nEJERCICIO 2: Cambia el pin de salida para\nencender otro led (por ejemplo el LED1)\ny cárgalo en la FPGA de nuevo" + }, + "position": { + "x": 464, + "y": 208 + } } - } - ], - "wires": [ - { - "source": { - "block": "e657ee6f-9430-4fce-a539-72d12d32f5bb", - "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" - }, - "target": { - "block": "949075cb-26c0-49da-ba76-2496ea9aa7cc", - "port": "in" + ], + "wires": [ + { + "source": { + "block": "eaf792b5-de98-4e2f-b78a-4023eb9a7f2b", + "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" + }, + "target": { + "block": "949075cb-26c0-49da-ba76-2496ea9aa7cc", + "port": "in" + } } - } - ] + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } }, - "deps": { - "bit.1": { - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 1\n\nassign v = 1'b1;", - "ports": { - "in": [], - "out": [ - "v" - ] + "dependencies": { + "3e6c249e205080168c1bf4ee8dbc33b50653d5f4": { + "package": { + "name": "Bit 1", + "version": "1.0.0", + "description": "Assign 1 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.218%22%20y=%22315.455%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.218%22%20y=%22315.455%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E1%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 1\n\nassign v = 1'b1;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 } }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 608, - "y": 192 + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "" + }, + "position": { + "x": 608, + "y": 192 + } } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } } - } - ] - }, - "deps": {}, - "image": "resources/images/1.svg", - "state": { - "pan": { - "x": 0, - "y": 0 + ] }, - "zoom": 1 + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } } } } diff --git a/app/resources/examples/icestick/1_basic/contadorAsc.ice b/app/resources/examples/icestick/1_basic/contadorAsc.ice new file mode 100644 index 000000000..f3021c6f9 --- /dev/null +++ b/app/resources/examples/icestick/1_basic/contadorAsc.ice @@ -0,0 +1,377 @@ +{ + "version": "1.1", + "package": { + "name": "contadorAsc", + "version": "0.1", + "description": "Contador ascendente de 4bits", + "author": "Carlos Diaz", + "image": "" + }, + "design": { + "board": "icestick", + "graph": { + "blocks": [ + { + "id": "579cff99-2d27-41d4-a20b-262ca8a93ca9", + "type": "basic.constant", + "data": { + "name": "INIT_CNT", + "value": "4'h2", + "local": false + }, + "position": { + "x": 312, + "y": 48 + } + }, + { + "id": "c299b4e2-ec25-4472-a58c-5dc46056c414", + "type": "basic.constant", + "data": { + "name": "FIN_CNT", + "value": "4'h5", + "local": false + }, + "position": { + "x": 504, + "y": 48 + } + }, + { + "id": "c1e3529f-d1eb-4ae5-8345-a43512f21577", + "type": "basic.output", + "data": { + "name": "out0", + "pins": [ + { + "index": "0", + "name": "D1", + "value": "99" + } + ], + "virtual": false + }, + "position": { + "x": 744, + "y": 144 + } + }, + { + "id": "86492073-e297-4c25-9678-30ab6dd1fa10", + "type": "basic.code", + "data": { + "code": "// INIT_CNT: Valor inicial de la cuenta\n// FIN_CNT: Valor final de la cuenta\n\n// El registro interno inicia su\n// cuenta a partir del valor del\n// parametro INIT_CNT\nreg [3:0] _o = INIT_CNT;\n\nalways @(posedge clk) begin\n if (en) begin\n _o <= _o + 1;\n // cuando _o vale igual que\n // el parametro FIN_CNT\n // se \"reinicia\" la cuenta\n // a partir de INIT_CNT\n if (_o == FIN_CNT || _o == 4'hFF) begin\n _o <= INIT_CNT;\n end\n end\nend\n\nassign {o3, o2, o1, o0} = _o;\n\n// (tc) terminal count, un clk de ancho a\n// la salida cuando termina _o vale FIN_CNT o 0\nwire tc = ((_o == FIN_CNT || _o == 4'hFF) ? 1 : 0);", + "params": [ + { + "name": "INIT_CNT" + }, + { + "name": "FIN_CNT" + } + ], + "ports": { + "in": [ + { + "name": "en" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "o0" + }, + { + "name": "o1" + }, + { + "name": "o2" + }, + { + "name": "o3" + }, + { + "name": "tc" + } + ] + } + }, + "position": { + "x": 264, + "y": 192 + } + }, + { + "id": "1e21f6ca-9956-475d-a933-5bb01829f464", + "type": "basic.output", + "data": { + "name": "out1", + "pins": [ + { + "index": "0", + "name": "D2", + "value": "98" + } + ], + "virtual": false + }, + "position": { + "x": 744, + "y": 216 + } + }, + { + "id": "aa65e0fd-fea6-4cde-bcea-5b09f97848ff", + "type": "3e6c249e205080168c1bf4ee8dbc33b50653d5f4", + "position": { + "x": 72, + "y": 224 + } + }, + { + "id": "e83e3ae9-0616-4a17-a145-f14954f3f6e0", + "type": "basic.output", + "data": { + "name": "out2", + "pins": [ + { + "index": "0", + "name": "D3", + "value": "97" + } + ], + "virtual": false + }, + "position": { + "x": 744, + "y": 288 + } + }, + { + "id": "8d6dece9-e3b8-42d4-b8eb-386c90440923", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "CLK", + "value": "21" + } + ], + "virtual": false + }, + "position": { + "x": 72, + "y": 352 + } + }, + { + "id": "1f036705-53b5-4833-83ed-adf0a7bf3b98", + "type": "basic.output", + "data": { + "name": "out3", + "pins": [ + { + "index": "0", + "name": "TR8", + "value": "117" + } + ], + "virtual": false + }, + "position": { + "x": 744, + "y": 360 + } + }, + { + "id": "a9409df4-b096-4ad0-a1c6-c6eb9bfa1d89", + "type": "basic.output", + "data": { + "name": "tc", + "pins": [ + { + "index": "0", + "name": "D4", + "value": "96" + } + ], + "virtual": false + }, + "position": { + "x": 744, + "y": 432 + } + } + ], + "wires": [ + { + "source": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "o0" + }, + "target": { + "block": "c1e3529f-d1eb-4ae5-8345-a43512f21577", + "port": "in" + } + }, + { + "source": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "o1" + }, + "target": { + "block": "1e21f6ca-9956-475d-a933-5bb01829f464", + "port": "in" + } + }, + { + "source": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "o2" + }, + "target": { + "block": "e83e3ae9-0616-4a17-a145-f14954f3f6e0", + "port": "in" + } + }, + { + "source": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "o3" + }, + "target": { + "block": "1f036705-53b5-4833-83ed-adf0a7bf3b98", + "port": "in" + } + }, + { + "source": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "tc" + }, + "target": { + "block": "a9409df4-b096-4ad0-a1c6-c6eb9bfa1d89", + "port": "in" + } + }, + { + "source": { + "block": "579cff99-2d27-41d4-a20b-262ca8a93ca9", + "port": "constant-out" + }, + "target": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "INIT_CNT" + } + }, + { + "source": { + "block": "c299b4e2-ec25-4472-a58c-5dc46056c414", + "port": "constant-out" + }, + "target": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "FIN_CNT" + } + }, + { + "source": { + "block": "8d6dece9-e3b8-42d4-b8eb-386c90440923", + "port": "out" + }, + "target": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "clk" + } + }, + { + "source": { + "block": "aa65e0fd-fea6-4cde-bcea-5b09f97848ff", + "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" + }, + "target": { + "block": "86492073-e297-4c25-9678-30ab6dd1fa10", + "port": "en" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": { + "3e6c249e205080168c1bf4ee8dbc33b50653d5f4": { + "package": { + "name": "Bit 1", + "version": "1.0.0", + "description": "Assign 1 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.218%22%20y=%22315.455%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.218%22%20y=%22315.455%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E1%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 1\n\nassign v = 1'b1;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 + } + }, + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "" + }, + "position": { + "x": 608, + "y": 192 + } + } + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + } + } + } +} \ No newline at end of file diff --git a/app/resources/examples/icestick/1_basic/contadorDes.ice b/app/resources/examples/icestick/1_basic/contadorDes.ice new file mode 100644 index 000000000..6a81de53a --- /dev/null +++ b/app/resources/examples/icestick/1_basic/contadorDes.ice @@ -0,0 +1,377 @@ +{ + "version": "1.1", + "package": { + "name": "contadorDes", + "version": "0.1", + "description": "Contador descendente de 4bits", + "author": "Carlos Diaz", + "image": "" + }, + "design": { + "board": "icestick", + "graph": { + "blocks": [ + { + "id": "579cff99-2d27-41d4-a20b-262ca8a93ca9", + "type": "basic.constant", + "data": { + "name": "INIT_CNT", + "value": "4'h6", + "local": false + }, + "position": { + "x": 296, + "y": 48 + } + }, + { + "id": "587cbcbb-9779-4bd4-a6da-501087ccf9d5", + "type": "basic.constant", + "data": { + "name": "FIN_CNT", + "value": "4'h0", + "local": false + }, + "position": { + "x": 488, + "y": 48 + } + }, + { + "id": "c1e3529f-d1eb-4ae5-8345-a43512f21577", + "type": "basic.output", + "data": { + "name": "out0", + "pins": [ + { + "index": "0", + "name": "D1", + "value": "99" + } + ], + "virtual": false + }, + "position": { + "x": 728, + "y": 144 + } + }, + { + "id": "75566233-6418-463a-a42b-1e975f6caf7c", + "type": "basic.code", + "data": { + "code": "// INIT_CNT: Valor inicial de la cuenta\n// FIN_CNT: Valor final de la cuenta\n\n// El registro interno inicia su\n// cuenta a partir del valor del\n// parametro INIT_CNT\nreg [3:0] _o = INIT_CNT;\n\nalways @(posedge clk) begin\n if (en) begin\n _o <= _o - 1;\n // si _o es igual a 0 o al valor\n // de FIN_CNT se reinicia\n // la cuenta\n if (_o == FIN_CNT || _o == 0) begin\n _o <= INIT_CNT;\n end\n end\nend\n\nassign {o3, o2, o1, o0} = _o;\n\n// (tc) terminal count, un clk de ancho a\n// la salida cuando termina _o vale FIN_CNT o 0\nwire tc = ((_o == FIN_CNT || _o == 0) ? 1 : 0);", + "params": [ + { + "name": "INIT_CNT" + }, + { + "name": "FIN_CNT" + } + ], + "ports": { + "in": [ + { + "name": "en" + }, + { + "name": "clk" + } + ], + "out": [ + { + "name": "o0" + }, + { + "name": "o1" + }, + { + "name": "o2" + }, + { + "name": "o3" + }, + { + "name": "tc" + } + ] + } + }, + "position": { + "x": 248, + "y": 192 + } + }, + { + "id": "1e21f6ca-9956-475d-a933-5bb01829f464", + "type": "basic.output", + "data": { + "name": "out1", + "pins": [ + { + "index": "0", + "name": "D2", + "value": "98" + } + ], + "virtual": false + }, + "position": { + "x": 728, + "y": 216 + } + }, + { + "id": "dc5dc1c3-0471-4669-9760-2b2ee9d7d467", + "type": "3e6c249e205080168c1bf4ee8dbc33b50653d5f4", + "position": { + "x": 56, + "y": 224 + } + }, + { + "id": "e83e3ae9-0616-4a17-a145-f14954f3f6e0", + "type": "basic.output", + "data": { + "name": "out2", + "pins": [ + { + "index": "0", + "name": "D3", + "value": "97" + } + ], + "virtual": false + }, + "position": { + "x": 728, + "y": 288 + } + }, + { + "id": "8d6dece9-e3b8-42d4-b8eb-386c90440923", + "type": "basic.input", + "data": { + "name": "clk", + "pins": [ + { + "index": "0", + "name": "CLK", + "value": "21" + } + ], + "virtual": false + }, + "position": { + "x": 56, + "y": 352 + } + }, + { + "id": "1f036705-53b5-4833-83ed-adf0a7bf3b98", + "type": "basic.output", + "data": { + "name": "out3", + "pins": [ + { + "index": "0", + "name": "TR8", + "value": "117" + } + ], + "virtual": false + }, + "position": { + "x": 728, + "y": 360 + } + }, + { + "id": "a9409df4-b096-4ad0-a1c6-c6eb9bfa1d89", + "type": "basic.output", + "data": { + "name": "tc", + "pins": [ + { + "index": "0", + "name": "D4", + "value": "96" + } + ], + "virtual": false + }, + "position": { + "x": 728, + "y": 432 + } + } + ], + "wires": [ + { + "source": { + "block": "587cbcbb-9779-4bd4-a6da-501087ccf9d5", + "port": "constant-out" + }, + "target": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "FIN_CNT" + } + }, + { + "source": { + "block": "579cff99-2d27-41d4-a20b-262ca8a93ca9", + "port": "constant-out" + }, + "target": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "INIT_CNT" + } + }, + { + "source": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "o0" + }, + "target": { + "block": "c1e3529f-d1eb-4ae5-8345-a43512f21577", + "port": "in" + } + }, + { + "source": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "o1" + }, + "target": { + "block": "1e21f6ca-9956-475d-a933-5bb01829f464", + "port": "in" + } + }, + { + "source": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "o2" + }, + "target": { + "block": "e83e3ae9-0616-4a17-a145-f14954f3f6e0", + "port": "in" + } + }, + { + "source": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "o3" + }, + "target": { + "block": "1f036705-53b5-4833-83ed-adf0a7bf3b98", + "port": "in" + } + }, + { + "source": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "tc" + }, + "target": { + "block": "a9409df4-b096-4ad0-a1c6-c6eb9bfa1d89", + "port": "in" + } + }, + { + "source": { + "block": "8d6dece9-e3b8-42d4-b8eb-386c90440923", + "port": "out" + }, + "target": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "clk" + } + }, + { + "source": { + "block": "dc5dc1c3-0471-4669-9760-2b2ee9d7d467", + "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" + }, + "target": { + "block": "75566233-6418-463a-a42b-1e975f6caf7c", + "port": "en" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + }, + "dependencies": { + "3e6c249e205080168c1bf4ee8dbc33b50653d5f4": { + "package": { + "name": "Bit 1", + "version": "1.0.0", + "description": "Assign 1 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.218%22%20y=%22315.455%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.218%22%20y=%22315.455%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E1%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 1\n\nassign v = 1'b1;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 + } + }, + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "" + }, + "position": { + "x": 608, + "y": 192 + } + } + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } + } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } + } + } + } +} \ No newline at end of file diff --git a/app/resources/examples/icezum/1_basic/1_led_on.ice b/app/resources/examples/icezum/1_basic/1_led_on.ice index 672560ecc..44c798809 100644 --- a/app/resources/examples/icezum/1_basic/1_led_on.ice +++ b/app/resources/examples/icezum/1_basic/1_led_on.ice @@ -1,129 +1,151 @@ { - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 0.9999999813303895 + "version": "1.1", + "package": { + "name": "Led on", + "version": "1.0.0", + "description": "", + "author": "", + "image": "" }, - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "a538a5b4-d5d5-4ace-a593-efb1fa9b930c", - "type": "basic.info", - "data": { - "info": "LED-ON Hello world circuit example!\n\nThe simplest digital circuit that turns a \nled on\n\nA bit set to 1 is wired directly to the\noutput FPGA pin, where the led is connected\n\nThe blue box is the bit (set to 1)\nIt is inside the FPGA\n\nThe yellow box is the output FPGA pin. Using\nthe bottom menu the pin can be changed\n\nEXERCISE 1: Upload this circuit into your \nFPGA board and watch the led. \nIt should be turned on\n\nEXERCISE 2: Change the pin number to turn\nanother led on and upload it again" + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "eaf792b5-de98-4e2f-b78a-4023eb9a7f2b", + "type": "3e6c249e205080168c1bf4ee8dbc33b50653d5f4", + "position": { + "x": 80, + "y": 64 + } }, - "position": { - "x": 40, - "y": 208 - } - }, - { - "id": "0d05784e-8e32-4c80-b85d-cde4e892dbf3", - "type": "basic.info", - "data": { - "info": "Ejemplo de circuito Hola mundo: LED-ON\n\nEs el circuito digital más sencillo que\nenciende un led\n\nUn bit a 1 se cablea directamente a una\nsalida de la FPGA, donde está conectado\nel LED\n\nLa caja azul es el bit a 1\nEstá dentro de la FPGA\n\nLa caja amarilla es el pin de salida de\nla FPGA. Por medio del menú desplegable\ninferior se puede cambiar el pin\n\nEJERCICIO 1: Carga este circuito en la FPGA\ny observa el LED0. Debe estar encendido\n\nEJERCICIO 2: Cambia el pin de salida para\nencender otro led (por ejemplo el LED1)\ny cárgalo en la FPGA de nuevo" + { + "id": "949075cb-26c0-49da-ba76-2496ea9aa7cc", + "type": "basic.output", + "data": { + "name": "led", + "pins": [ + { + "index": "0", + "name": "LED0", + "value": "95" + } + ], + "virtual": false + }, + "position": { + "x": 352, + "y": 64 + } }, - "position": { - "x": 464, - "y": 208 - } - }, - { - "id": "e657ee6f-9430-4fce-a539-72d12d32f5bb", - "type": "bit.1", - "data": {}, - "position": { - "x": 80, - "y": 64 - } - }, - { - "id": "949075cb-26c0-49da-ba76-2496ea9aa7cc", - "type": "basic.output", - "data": { - "label": "led", - "pin": { - "name": "LED0", - "value": "95" + { + "id": "a538a5b4-d5d5-4ace-a593-efb1fa9b930c", + "type": "basic.info", + "data": { + "info": "LED-ON Hello world circuit example!\n\nThe simplest digital circuit that turns a \nled on\n\nA bit set to 1 is wired directly to the\noutput FPGA pin, where the led is connected\n\nThe blue box is the bit (set to 1)\nIt is inside the FPGA\n\nThe yellow box is the output FPGA pin. Using\nthe bottom menu the pin can be changed\n\nEXERCISE 1: Upload this circuit into your \nFPGA board and watch the led. \nIt should be turned on\n\nEXERCISE 2: Change the pin number to turn\nanother led on and upload it again" + }, + "position": { + "x": 40, + "y": 208 } }, - "position": { - "x": 352, - "y": 64 + { + "id": "0d05784e-8e32-4c80-b85d-cde4e892dbf3", + "type": "basic.info", + "data": { + "info": "Ejemplo de circuito Hola mundo: LED-ON\n\nEs el circuito digital más sencillo que\nenciende un led\n\nUn bit a 1 se cablea directamente a una\nsalida de la FPGA, donde está conectado\nel LED\n\nLa caja azul es el bit a 1\nEstá dentro de la FPGA\n\nLa caja amarilla es el pin de salida de\nla FPGA. Por medio del menú desplegable\ninferior se puede cambiar el pin\n\nEJERCICIO 1: Carga este circuito en la FPGA\ny observa el LED0. Debe estar encendido\n\nEJERCICIO 2: Cambia el pin de salida para\nencender otro led (por ejemplo el LED1)\ny cárgalo en la FPGA de nuevo" + }, + "position": { + "x": 464, + "y": 208 + } } - } - ], - "wires": [ - { - "source": { - "block": "e657ee6f-9430-4fce-a539-72d12d32f5bb", - "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" - }, - "target": { - "block": "949075cb-26c0-49da-ba76-2496ea9aa7cc", - "port": "in" + ], + "wires": [ + { + "source": { + "block": "eaf792b5-de98-4e2f-b78a-4023eb9a7f2b", + "port": "19c8f68d-5022-487f-9ab0-f0a3cd58bead" + }, + "target": { + "block": "949075cb-26c0-49da-ba76-2496ea9aa7cc", + "port": "in" + } } - } - ] + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } }, - "deps": { - "bit.1": { - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 1\n\nassign v = 1'b1;", - "ports": { - "in": [], - "out": [ - "v" - ] + "dependencies": { + "3e6c249e205080168c1bf4ee8dbc33b50653d5f4": { + "package": { + "name": "Bit 1", + "version": "1.0.0", + "description": "Assign 1 to the output wire", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20width=%2247.303%22%20height=%2227.648%22%20viewBox=%220%200%2044.346456%2025.919999%22%3E%3Ctext%20style=%22line-height:125%25%22%20x=%22325.218%22%20y=%22315.455%22%20font-weight=%22400%22%20font-size=%2212.669%22%20font-family=%22sans-serif%22%20letter-spacing=%220%22%20word-spacing=%220%22%20transform=%22translate(-307.01%20-298.51)%22%3E%3Ctspan%20x=%22325.218%22%20y=%22315.455%22%20style=%22-inkscape-font-specification:'Courier%2010%20Pitch'%22%20font-family=%22Courier%2010%20Pitch%22%3E1%3C/tspan%3E%3C/text%3E%3C/svg%3E" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "type": "basic.code", + "data": { + "code": "// Bit 1\n\nassign v = 1'b1;", + "params": [], + "ports": { + "in": [], + "out": [ + { + "name": "v" + } + ] + } + }, + "position": { + "x": 96, + "y": 96 } }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "" - }, - "position": { - "x": 608, - "y": 192 + { + "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "type": "basic.output", + "data": { + "name": "" + }, + "position": { + "x": 608, + "y": 192 + } } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" + ], + "wires": [ + { + "source": { + "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", + "port": "v" + }, + "target": { + "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", + "port": "in" + } } - } - ] - }, - "deps": {}, - "image": "resources/images/1.svg", - "state": { - "pan": { - "x": 0, - "y": 0 + ] }, - "zoom": 1 + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } } } } diff --git a/app/resources/examples/icezum/1_basic/2_switch_led.ice b/app/resources/examples/icezum/1_basic/2_switch_led.ice index 3adf6917a..b7fa32b04 100644 --- a/app/resources/examples/icezum/1_basic/2_switch_led.ice +++ b/app/resources/examples/icezum/1_basic/2_switch_led.ice @@ -1,91 +1,108 @@ { - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 0.9999999883960295 + "version": "1.1", + "package": { + "name": "Switch led", + "version": "1.0.0", + "description": "", + "author": "", + "image": "" }, - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "aac1b394-533e-4410-9f35-ba80af8abd63", - "type": "basic.input", - "data": { - "label": "button", - "pin": { - "name": "SW1", - "value": "10" + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "aac1b394-533e-4410-9f35-ba80af8abd63", + "type": "basic.input", + "data": { + "name": "button", + "pins": [ + { + "index": "0", + "name": "SW1", + "value": "10" + } + ], + "virtual": false + }, + "position": { + "x": 48, + "y": 80 } }, - "position": { - "x": 48, - "y": 80 - } - }, - { - "id": "30a83e46-176d-40a8-ac0e-f19a131ea9d9", - "type": "basic.output", - "data": { - "label": "led", - "pin": { - "name": "LED0", - "value": "95" + { + "id": "30a83e46-176d-40a8-ac0e-f19a131ea9d9", + "type": "basic.output", + "data": { + "name": "led", + "pins": [ + { + "index": "0", + "name": "LED0", + "value": "95" + } + ], + "virtual": false + }, + "position": { + "x": 320, + "y": 80 } }, - "position": { - "x": 320, - "y": 80 - } - }, - { - "id": "9e124703-5a80-4d0d-8c31-945447862085", - "type": "basic.info", - "data": { - "info": "Switch-led basic example\n\nA simple circuit that connects the input pin,\nwhere there is a button switch, with the\noutpun pin, where there is a led\n\nWhen the button is pressed (1), the led is\nturned on. When the button is released (0), the\nled is turned off\n\nNotice the blue box with a gear. It is a\nconfiguration block for activating the \nFPGA internal pull-up resistor in the SW1 pin" - }, - "position": { - "x": 32, - "y": 224 - } - }, - { - "id": "f76f55d3-ba32-42d8-8c16-9f4cbbd9d27c", - "type": "basic.info", - "data": { - "info": "Ejemplo básico switch-led\n\nSencillo circuito que conecta directamente\nun pin de entrada de la FPGA, donde hay\nun pulsador, con el pin de salida, donde está\nel led\n\nCuando se aprieta el pulsador (1), se enciende\nel led. Cuando se suelta (0) se apaga\n\nFíjate en la caja azul con el engranaje. Es un\nbloque de configuración que permite activar la\nresistencia de pull-up interna del pin de la \nFPGA" + { + "id": "9e124703-5a80-4d0d-8c31-945447862085", + "type": "basic.info", + "data": { + "info": "Switch-led basic example\n\nA simple circuit that connects the input pin,\nwhere there is a button switch, with the\noutpun pin, where there is a led\n\nWhen the button is pressed (1), the led is\nturned on. When the button is released (0), the\nled is turned off\n\nNotice the blue box with a gear. It is a\nconfiguration block for activating the \nFPGA internal pull-up resistor in the SW1 pin" + }, + "position": { + "x": 32, + "y": 224 + } }, - "position": { - "x": 448, - "y": 224 - } - }, - { - "id": "d556c4f6-736a-41a9-9f64-badf2b790010", - "type": "basic.info", - "data": { - "info": "EXERCISE 1: Upload the circuit into your FPGA\nboard and test it!\n\nEXERCISE 2: Change the button to SW2 and test\nit again\n\n---------------------------------------------\nEjercicio 1: Carga el circuito en la FPGA y\n¡pruébalo!\n\nEJERCICIO 2: Cambia el pulsador al SW2 y\npruébalo de nuevo" + { + "id": "f76f55d3-ba32-42d8-8c16-9f4cbbd9d27c", + "type": "basic.info", + "data": { + "info": "Ejemplo básico switch-led\n\nSencillo circuito que conecta directamente\nun pin de entrada de la FPGA, donde hay\nun pulsador, con el pin de salida, donde está\nel led\n\nCuando se aprieta el pulsador (1), se enciende\nel led. Cuando se suelta (0) se apaga\n\nFíjate en la caja azul con el engranaje. Es un\nbloque de configuración que permite activar la\nresistencia de pull-up interna del pin de la \nFPGA" + }, + "position": { + "x": 448, + "y": 224 + } }, - "position": { - "x": 864, - "y": 224 + { + "id": "d556c4f6-736a-41a9-9f64-badf2b790010", + "type": "basic.info", + "data": { + "info": "EXERCISE 1: Upload the circuit into your FPGA\nboard and test it!\n\nEXERCISE 2: Change the button to SW2 and test\nit again\n\n---------------------------------------------\nEjercicio 1: Carga el circuito en la FPGA y\n¡pruébalo!\n\nEJERCICIO 2: Cambia el pulsador al SW2 y\npruébalo de nuevo" + }, + "position": { + "x": 864, + "y": 224 + } } - } - ], - "wires": [ - { - "source": { - "block": "aac1b394-533e-4410-9f35-ba80af8abd63", - "port": "out" - }, - "target": { - "block": "30a83e46-176d-40a8-ac0e-f19a131ea9d9", - "port": "in" + ], + "wires": [ + { + "source": { + "block": "aac1b394-533e-4410-9f35-ba80af8abd63", + "port": "out" + }, + "target": { + "block": "30a83e46-176d-40a8-ac0e-f19a131ea9d9", + "port": "in" + } } - } - ] + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } }, - "deps": {} + "dependencies": {} } \ No newline at end of file diff --git a/app/resources/examples/icezum/1_basic/3_switch_and_gate.ice b/app/resources/examples/icezum/1_basic/3_switch_and_gate.ice index 50c4778b9..8a01e713e 100644 --- a/app/resources/examples/icezum/1_basic/3_switch_and_gate.ice +++ b/app/resources/examples/icezum/1_basic/3_switch_and_gate.ice @@ -1,224 +1,258 @@ { - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 0.9999999999999751 + "version": "1.1", + "package": { + "name": "", + "version": "", + "description": "", + "author": "", + "image": "" }, - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "aa8bab8b-61e4-4e28-b444-0e68d9484ea1", - "type": "basic.input", - "data": { - "label": "button1", - "pin": { - "name": "SW1", - "value": "10" + "design": { + "board": "icezum", + "graph": { + "blocks": [ + { + "id": "aa8bab8b-61e4-4e28-b444-0e68d9484ea1", + "type": "basic.input", + "data": { + "name": "button1", + "pins": [ + { + "index": "0", + "name": "SW1", + "value": "10" + } + ], + "virtual": false + }, + "position": { + "x": 40, + "y": 32 } }, - "position": { - "x": 40, - "y": 32 - } - }, - { - "id": "5d1b4f33-ae65-4154-b4f4-ff1403437600", - "type": "basic.input", - "data": { - "label": "button2", - "pin": { - "name": "SW2", - "value": "11" + { + "id": "840e71b2-bf5a-4e20-8413-d386500c87fa", + "type": "11a6f454705778e2f00adba4e5b28dcd9411bc8f", + "position": { + "x": 256, + "y": 80 } }, - "position": { - "x": 40, - "y": 128 - } - }, - { - "id": "3cad6e72-e7d3-4273-be1c-ce5f9b4c020a", - "type": "basic.output", - "data": { - "label": "led", - "pin": { - "name": "LED7", - "value": "104" + { + "id": "3cad6e72-e7d3-4273-be1c-ce5f9b4c020a", + "type": "basic.output", + "data": { + "name": "led", + "pins": [ + { + "index": "0", + "name": "LED7", + "value": "104" + } + ], + "virtual": false + }, + "position": { + "x": 440, + "y": 80 } }, - "position": { - "x": 440, - "y": 80 - } - }, - { - "id": "cb5b06e5-0d7d-4c89-9c17-0cd7892369c1", - "type": "logic.and", - "data": {}, - "position": { - "x": 264, - "y": 80 - } - }, - { - "id": "cce8504a-dc1f-4deb-9ee3-5f215ac88408", - "type": "basic.info", - "data": { - "info": "Basic AND gate circuit\n\nA 2-inputs AND logic gate is used to turn on\nthe LED7 only when the 2 input buttons\nare pressed\n\nThis example shows the basic behaviour of\nthe AND gate\n\nEXERCISE: Upload this circuit into the FPGA\nboard and play with it" + { + "id": "5d1b4f33-ae65-4154-b4f4-ff1403437600", + "type": "basic.input", + "data": { + "name": "button2", + "pins": [ + { + "index": "0", + "name": "SW2", + "value": "11" + } + ], + "virtual": false + }, + "position": { + "x": 40, + "y": 128 + } }, - "position": { - "x": 40, - "y": 232 - } - }, - { - "id": "edf3b438-4271-45f7-bb14-2a6d040880dd", - "type": "basic.info", - "data": { - "info": "Circuito básico con puerta AND\n\nUna puerta lógica AND de 2 entradas se usa\npara encender un led solo cuando los dos\npulsadores de entrada están apretados\n\nEste ejemplo muestra el comportamiento básico\nde una puerta AND\n\nEJERCICIO: Carga este circuito en la FPGA y \njuega con él" + { + "id": "cce8504a-dc1f-4deb-9ee3-5f215ac88408", + "type": "basic.info", + "data": { + "info": "Basic AND gate circuit\n\nA 2-inputs AND logic gate is used to turn on\nthe LED7 only when the 2 input buttons\nare pressed\n\nThis example shows the basic behaviour of\nthe AND gate\n\nEXERCISE: Upload this circuit into the FPGA\nboard and play with it" + }, + "position": { + "x": 40, + "y": 232 + } }, - "position": { - "x": 464, - "y": 232 + { + "id": "edf3b438-4271-45f7-bb14-2a6d040880dd", + "type": "basic.info", + "data": { + "info": "Circuito básico con puerta AND\n\nUna puerta lógica AND de 2 entradas se usa\npara encender un led solo cuando los dos\npulsadores de entrada están apretados\n\nEste ejemplo muestra el comportamiento básico\nde una puerta AND\n\nEJERCICIO: Carga este circuito en la FPGA y \njuega con él" + }, + "position": { + "x": 464, + "y": 232 + } } - } - ], - "wires": [ - { - "source": { - "block": "cb5b06e5-0d7d-4c89-9c17-0cd7892369c1", - "port": "664caf9e-5f40-4df4-800a-b626af702e62" + ], + "wires": [ + { + "source": { + "block": "840e71b2-bf5a-4e20-8413-d386500c87fa", + "port": "664caf9e-5f40-4df4-800a-b626af702e62" + }, + "target": { + "block": "3cad6e72-e7d3-4273-be1c-ce5f9b4c020a", + "port": "in" + } }, - "target": { - "block": "3cad6e72-e7d3-4273-be1c-ce5f9b4c020a", - "port": "in" - } - }, - { - "source": { - "block": "aa8bab8b-61e4-4e28-b444-0e68d9484ea1", - "port": "out" + { + "source": { + "block": "aa8bab8b-61e4-4e28-b444-0e68d9484ea1", + "port": "out" + }, + "target": { + "block": "840e71b2-bf5a-4e20-8413-d386500c87fa", + "port": "18c2ebc7-5152-439c-9b3f-851c59bac834" + } }, - "target": { - "block": "cb5b06e5-0d7d-4c89-9c17-0cd7892369c1", - "port": "18c2ebc7-5152-439c-9b3f-851c59bac834" + { + "source": { + "block": "5d1b4f33-ae65-4154-b4f4-ff1403437600", + "port": "out" + }, + "target": { + "block": "840e71b2-bf5a-4e20-8413-d386500c87fa", + "port": "97b51945-d716-4b6c-9db9-970d08541249" + } } + ] + }, + "state": { + "pan": { + "x": 0, + "y": 0 }, - { - "source": { - "block": "5d1b4f33-ae65-4154-b4f4-ff1403437600", - "port": "out" - }, - "target": { - "block": "cb5b06e5-0d7d-4c89-9c17-0cd7892369c1", - "port": "97b51945-d716-4b6c-9db9-970d08541249" - } - } - ] + "zoom": 1 + } }, - "deps": { - "logic.and": { - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "" - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "" + "dependencies": { + "11a6f454705778e2f00adba4e5b28dcd9411bc8f": { + "package": { + "name": "AND", + "version": "1.0.0", + "description": "AND logic gate", + "author": "Jesús Arroyo", + "image": "%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%22-252%20400.9%2090%2040%22%3E%3Cpath%20d=%22M-252%20409.9h26v2h-26zM-252%20429.9h27v2h-27z%22/%3E%3Cpath%20d=%22M-227%20400.9v39.9h20.4c11.3%200%2020-9%2020-20s-8.7-20-20-20H-227zm2.9%202.8h17.6c9.8%200%2016.7%207.6%2016.7%2017.1%200%209.5-7.4%2017.1-17.1%2017.1H-224c-.1.1-.1-34.2-.1-34.2z%22/%3E%3Cpath%20d=%22M-187.911%20419.9H-162v2h-25.911z%22/%3E%3C/svg%3E" + }, + "design": { + "graph": { + "blocks": [ + { + "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "type": "basic.code", + "data": { + "code": "// AND logic gate\n\nassign c = a & b;", + "params": [], + "ports": { + "in": [ + { + "name": "a" + }, + { + "name": "b" + } + ], + "out": [ + { + "name": "c" + } + ] + } + }, + "position": { + "x": 256, + "y": 48 + } }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// AND logic gate\n\nassign c = a & b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] + { + "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "type": "basic.input", + "data": { + "name": "" + }, + "position": { + "x": 64, + "y": 80 } }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" + { + "id": "664caf9e-5f40-4df4-800a-b626af702e62", + "type": "basic.output", + "data": { + "name": "" + }, + "position": { + "x": 752, + "y": 144 + } }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" + { + "id": "97b51945-d716-4b6c-9db9-970d08541249", + "type": "basic.input", + "data": { + "name": "" + }, + "position": { + "x": 64, + "y": 208 + } } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" + ], + "wires": [ + { + "source": { + "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "a" + } }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" + { + "source": { + "block": "97b51945-d716-4b6c-9db9-970d08541249", + "port": "out" + }, + "target": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "b" + } }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" + { + "source": { + "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", + "port": "c" + }, + "target": { + "block": "664caf9e-5f40-4df4-800a-b626af702e62", + "port": "in" + } } - } - ] - }, - "deps": {}, - "image": "resources/images/and.svg", - "state": { - "pan": { - "x": 0, - "y": 0 + ] }, - "zoom": 1 + "state": { + "pan": { + "x": 0, + "y": 0 + }, + "zoom": 1 + } } } } diff --git a/app/resources/examples/labels.js b/app/resources/examples/labels.js index 73c95cac6..5d2b29508 100644 --- a/app/resources/examples/labels.js +++ b/app/resources/examples/labels.js @@ -1,10 +1,14 @@ // In this file the examples labels are annotated for translation /// 1. Basic -gettext('1_basic') +gettext('1_basic'); /// 1. Led on -gettext('1_led_on') +gettext('1_led_on'); /// 2. Switch led -gettext('2_switch_led') +gettext('2_switch_led'); /// 3. Switch and gate -gettext('3_switch_and_gate') +gettext('3_switch_and_gate'); +/// contadorAsc +gettext('contadorAsc'); +/// contadorDes +gettext('contadorDes'); diff --git a/app/resources/images/0.svg b/app/resources/images/0.svg deleted file mode 100644 index f5947860d..000000000 --- a/app/resources/images/0.svg +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - 0 - - diff --git a/app/resources/images/1.svg b/app/resources/images/1.svg deleted file mode 100644 index 59fd65245..000000000 --- a/app/resources/images/1.svg +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - 1 - - diff --git a/app/resources/images/7segmentos_ANODO.svg b/app/resources/images/7segmentos_ANODO.svg deleted file mode 100755 index 52a1fa524..000000000 --- a/app/resources/images/7segmentos_ANODO.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - -image/svg+xmlANODO COMÚN - \ No newline at end of file diff --git a/app/resources/images/7segmentos_CATODO.svg b/app/resources/images/7segmentos_CATODO.svg deleted file mode 100755 index 24ffca138..000000000 --- a/app/resources/images/7segmentos_CATODO.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - -image/svg+xmlCATODO COMÚN - \ No newline at end of file diff --git a/app/resources/images/FF/DFF.svg b/app/resources/images/FF/DFF.svg deleted file mode 100755 index 94b2dc2da..000000000 --- a/app/resources/images/FF/DFF.svg +++ /dev/null @@ -1,101 +0,0 @@ - - - -image/svg+xmlDFF -D -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/DFF_AR.svg b/app/resources/images/FF/DFF_AR.svg deleted file mode 100755 index 637626d6e..000000000 --- a/app/resources/images/FF/DFF_AR.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - -image/svg+xmlDFF_AR -D -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/DFF_E.svg b/app/resources/images/FF/DFF_E.svg deleted file mode 100755 index 5c3896340..000000000 --- a/app/resources/images/FF/DFF_E.svg +++ /dev/null @@ -1,115 +0,0 @@ - - - -image/svg+xmlDFF -D -EN -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/DFF_E_AR.svg b/app/resources/images/FF/DFF_E_AR.svg deleted file mode 100755 index a8971a20e..000000000 --- a/app/resources/images/FF/DFF_E_AR.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - -image/svg+xmlDFF_AR -D -EN -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/DFF_E_SR.svg b/app/resources/images/FF/DFF_E_SR.svg deleted file mode 100644 index ad050f7ea..000000000 --- a/app/resources/images/FF/DFF_E_SR.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - -image/svg+xmlDFF_SR -D -EN -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/DFF_SR.svg b/app/resources/images/FF/DFF_SR.svg deleted file mode 100644 index 6161c3987..000000000 --- a/app/resources/images/FF/DFF_SR.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - -image/svg+xmlDFF_SR -D -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF.svg b/app/resources/images/FF/TFF.svg deleted file mode 100755 index 2444f0584..000000000 --- a/app/resources/images/FF/TFF.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - -image/svg+xmlTFF -T -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF_AR.svg b/app/resources/images/FF/TFF_AR.svg deleted file mode 100644 index 44af56a8a..000000000 --- a/app/resources/images/FF/TFF_AR.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - -image/svg+xmlTFF_AR -T -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF_E.svg b/app/resources/images/FF/TFF_E.svg deleted file mode 100755 index 6e784eca9..000000000 --- a/app/resources/images/FF/TFF_E.svg +++ /dev/null @@ -1,115 +0,0 @@ - - - -image/svg+xmlTFF -T -EN -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF_E_AR.svg b/app/resources/images/FF/TFF_E_AR.svg deleted file mode 100644 index c5a839ffa..000000000 --- a/app/resources/images/FF/TFF_E_AR.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - -image/svg+xmlTFF_AR -T -EN -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF_E_SR.svg b/app/resources/images/FF/TFF_E_SR.svg deleted file mode 100644 index 3d6bc9c6f..000000000 --- a/app/resources/images/FF/TFF_E_SR.svg +++ /dev/null @@ -1,120 +0,0 @@ - - - -image/svg+xmlTFF_SR -T -EN -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/FF/TFF_SR.svg b/app/resources/images/FF/TFF_SR.svg deleted file mode 100644 index f8b069372..000000000 --- a/app/resources/images/FF/TFF_SR.svg +++ /dev/null @@ -1,111 +0,0 @@ - - - -image/svg+xmlTFF_SR -T -RST -CLK -Q -Q - \ No newline at end of file diff --git a/app/resources/images/and.svg b/app/resources/images/and.svg deleted file mode 100644 index 6d4834f6c..000000000 --- a/app/resources/images/and.svg +++ /dev/null @@ -1,67 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/app/resources/images/demux.svg b/app/resources/images/demux.svg deleted file mode 100755 index 6fbfbab86..000000000 --- a/app/resources/images/demux.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/dff_ar.svg b/app/resources/images/dff_ar.svg deleted file mode 100644 index f5c1614d1..000000000 --- a/app/resources/images/dff_ar.svg +++ /dev/null @@ -1,70 +0,0 @@ - - - -image/svg+xmlDFF -async - \ No newline at end of file diff --git a/app/resources/images/dff_sr.svg b/app/resources/images/dff_sr.svg deleted file mode 100644 index 25ec7cdcf..000000000 --- a/app/resources/images/dff_sr.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - -image/svg+xmlDFF - \ No newline at end of file diff --git a/app/resources/images/mux.svg b/app/resources/images/mux.svg deleted file mode 100755 index b6e991970..000000000 --- a/app/resources/images/mux.svg +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/nand.svg b/app/resources/images/nand.svg deleted file mode 100755 index 14fee55d2..000000000 --- a/app/resources/images/nand.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/nor.svg b/app/resources/images/nor.svg deleted file mode 100755 index 98ec8066e..000000000 --- a/app/resources/images/nor.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/not.svg b/app/resources/images/not.svg deleted file mode 100644 index ea675b8a6..000000000 --- a/app/resources/images/not.svg +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/or.svg b/app/resources/images/or.svg deleted file mode 100644 index 02e9f2954..000000000 --- a/app/resources/images/or.svg +++ /dev/null @@ -1,167 +0,0 @@ - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/pull_up.svg b/app/resources/images/pull_up.svg deleted file mode 100755 index 5deb3913a..000000000 --- a/app/resources/images/pull_up.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/app/resources/images/pull_up_inv.svg b/app/resources/images/pull_up_inv.svg deleted file mode 100755 index bbe7bf57e..000000000 --- a/app/resources/images/pull_up_inv.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/app/resources/images/tff_ar.svg b/app/resources/images/tff_ar.svg deleted file mode 100644 index 6bcd9837e..000000000 --- a/app/resources/images/tff_ar.svg +++ /dev/null @@ -1,71 +0,0 @@ - - - -image/svg+xmlTFF -async - \ No newline at end of file diff --git a/app/resources/images/tff_sr.svg b/app/resources/images/tff_sr.svg deleted file mode 100644 index 7b1fd3cdf..000000000 --- a/app/resources/images/tff_sr.svg +++ /dev/null @@ -1,56 +0,0 @@ - - - -image/svg+xmlTFF - \ No newline at end of file diff --git a/app/resources/images/tri_state.svg b/app/resources/images/tri_state.svg deleted file mode 100644 index 8be1bc03f..000000000 --- a/app/resources/images/tri_state.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/app/resources/images/xnor.svg b/app/resources/images/xnor.svg deleted file mode 100755 index 4314c5b9c..000000000 --- a/app/resources/images/xnor.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/images/xor.svg b/app/resources/images/xor.svg deleted file mode 100644 index 383007edb..000000000 --- a/app/resources/images/xor.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/resources/locale/en/en.po b/app/resources/locale/en/en.po index 3d116c84f..2a09756ad 100644 --- a/app/resources/locale/en/en.po +++ b/app/resources/locale/en/en.po @@ -32,12 +32,12 @@ msgstr "2. Switch led" msgid "3_switch_and_gate" msgstr "3. Switch and gate" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" msgstr "Unplug and reconnect the board" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "" "

FTDI driver installation instructions

  1. Connect the FPGA " "board
  2. Replace the (Interface 0) driver of the board by " @@ -47,7 +47,7 @@ msgstr "" "board
  3. Replace the (Interface 0) driver of the board by " "libusbK
  4. Unplug and reconnect the board
" -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "" "

FTDI driver uninstallation instructions

  1. Find the FPGA USB " "Device
  2. Select the board interface and uninstall the driver
" @@ -55,79 +55,126 @@ msgstr "" "

FTDI driver uninstallation instructions

  1. Find the FPGA USB " "Device
  2. Select the board interface and uninstall the driver
" -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" msgstr "About Icestudio" -#: app/scripts/controllers/menu.js:421 +#: app/views/menu.html:275 +msgid "Add" +msgstr "Add" + +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" msgstr "Add a block to start" -#: app/views/menu.html:285 +#: app/views/menu.html:35 +msgid "Add as block" +msgstr "Add as block" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" +msgstr "All collections removed" + +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "All stored collections will be lost. Do you want to continue?" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "Author" + +#: app/views/menu.html:331 msgid "Basic" msgstr "Basic" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" msgstr "Basque" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" -msgstr "Block exported as {{name}}" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +msgid "Block updated" +msgstr "Block updated" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" msgstr "Block {{name}} imported" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" msgstr "Board {{name}} not detected" -#: app/scripts/controllers/menu.js:383 app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" msgstr "Board {{name}} selected" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "Boards" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "Build" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" msgstr "Cancel" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." msgstr "Check Internet connection..." -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." msgstr "Check Python..." -#: app/views/menu.html:113 -msgid "Clear all" -msgstr "Clear all" - -#: app/views/menu.html:107 -msgid "Clone selected" -msgstr "Clone selected" - -#: app/views/menu.html:288 +#: app/views/menu.html:337 msgid "Code" msgstr "Code" -#: app/views/menu.html:271 +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" +msgstr "Collection file {{name}} added" + +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" +msgstr "Collection {{name}} removed" + +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "Collection {{name}} selected" + +#: app/views/menu.html:185 app/views/menu.html:271 +msgid "Collections" +msgstr "Collections" + +#: app/views/menu.html:317 msgid "Community forum" msgstr "Community forum" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "Constant" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "Copy" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "Cut" + +#: app/views/menu.html:181 msgid "Datasheet" msgstr "Datasheet" -#: app/scripts/services/tools.service.js:294 +#: app/views/menu.html:189 +msgid "Default" +msgstr "Default" + +#: app/scripts/services/tools.service.js:315 msgid "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" @@ -135,332 +182,391 @@ msgstr "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "Description" + +#: app/views/menu.html:264 msgid "Disable" msgstr "Disable" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" -msgstr "Do you want to clear all?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" +msgstr "Do you want to close the application?" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" -msgstr "Do you want to remove the selected block?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" +msgstr "Do you want to remove the {{name}} collection?" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" msgstr "Documentation" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" msgstr "Drivers" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" msgstr "Drivers disabled" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" msgstr "Drivers enabled" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" msgstr "Duplicated FPGA I/O ports" -#: app/views/menu.html:100 +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "Duplicated block attributes" + +#: app/views/menu.html:88 msgid "Edit" msgstr "Edit" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" msgstr "Enable" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "English" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +msgid "Enter the constant blocks" +msgstr "Enter the constant blocks" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" msgstr "Enter the input ports" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" msgstr "Enter the output ports" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" -msgstr "Enter the project's image path" +#: app/scripts/services/blocks.service.js:215 +msgid "Enter the parameters" +msgstr "Enter the parameters" -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" -msgstr "Enter the project's title" +#: app/scripts/services/blocks.service.js:57 +msgid "Enter the ports" +msgstr "Enter the ports" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" msgstr "Enter the remote hostname user@host (experimental)" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" msgstr "Error: default toolchain not found in '{{dir}}'" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "Error: {{error}}" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "Examples" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." msgstr "Execute remote {{label}} ..." -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "Export" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "Export as block" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." msgstr "Extract default apio files..." -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." msgstr "Extract default apio packages..." -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." msgstr "Extract virtual env files..." -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" msgstr "FPGA I/O ports not defined" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "FPGA pin" + +#: app/views/menu.html:26 msgid "File" msgstr "File" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "" "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" "File {{file}} already exists in the project path. Do you want to replace it?" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" msgstr "File {{file}} does not exist" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" msgstr "File {{file}} imported" -#: app/views/menu.html:159 +#: app/views/menu.html:114 +msgid "Fit content" +msgstr "Fit content" + +#: app/views/menu.html:160 msgid "French" msgstr "French" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" msgstr "GTKWave exported" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" msgstr "Galician" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "Help" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" msgstr "Homebrew is required" -#: app/views/menu.html:120 -msgid "Image path" -msgstr "Image path" +#: app/scripts/services/utils.service.js:694 +msgid "Image" +msgstr "Image" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" msgstr "Image {{name}} saved" -#: app/views/menu.html:73 -msgid "Import block" -msgstr "Import block" - -#: app/views/menu.html:289 -msgid "Info" -msgstr "Info" +#: app/views/menu.html:338 +msgid "Information" +msgstr "Information" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "Input" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" msgstr "Install" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." msgstr "Install default apio..." -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" msgstr "Installation completed" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" msgstr "Installing toolchain" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" msgstr "Internet connection required" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
block already connected" msgstr "Invalid Pull up connection:
block already connected" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
only Input blocks allowed" msgstr "Invalid Pull up connection:
only Input blocks allowed" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
Pull up already connected" msgstr "Invalid block connection:
Pull up already connected" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" msgstr "Invalid connection" -#: app/scripts/services/graph.service.js:127 +#: app/scripts/services/graph.service.js:219 +msgid "Invalid connection: {{a}} → {{b}}" +msgstr "Invalid connection: {{a}} → {{b}}" + +#: app/scripts/services/graph.service.js:180 msgid "Invalid multiple input connections" msgstr "Invalid multiple input connections" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" -msgstr "Label updated" - -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "Language" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "Local parameter" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." msgstr "Make virtual env..." -#: app/views/menu.html:27 -msgid "New project" -msgstr "New project" +#: app/scripts/services/utils.service.js:678 +msgid "Name" +msgstr "Name" + +#: app/views/menu.html:29 +msgid "New" +msgstr "New" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" msgstr "New project {{name}} created" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "No collections stored" + +#: app/scripts/controllers/main.js:15 msgid "OK" msgstr "OK" -#: app/views/menu.html:30 -msgid "Open project" -msgstr "Open project" +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" +msgstr "Old project format {{version}}" + +#: app/views/menu.html:32 +msgid "Open" +msgstr "Open" -#: app/scripts/services/common.service.js:156 +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" +msgstr "Open SVG" + +#: app/scripts/services/project.service.js:395 msgid "Original file {{file}} does not exist" msgstr "Original file {{file}} does not exist" -#: app/views/menu.html:291 +#: app/views/menu.html:335 msgid "Output" msgstr "Output" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" msgstr "PCF file exported" -#: app/views/menu.html:117 +#: app/views/menu.html:104 +msgid "Paste" +msgstr "Paste" + +#: app/views/menu.html:118 msgid "Preferences" msgstr "Preferences" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:121 +msgid "Project information" +msgstr "Project information" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" msgstr "Project {{name}} loaded" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" msgstr "Project {{name}} saved" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" msgstr "Python 2.7 is required" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "Quit" + +#: app/views/design.html:4 msgid "Read only" msgstr "Read only" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "Redo" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" msgstr "Remote host {{name}} not connected" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" msgstr "Remote hostname" -#: app/views/menu.html:223 +#: app/views/menu.html:240 app/views/menu.html:279 msgid "Remove" msgstr "Remove" -#: app/views/menu.html:110 -msgid "Remove selected" -msgstr "Remove selected" +#: app/views/menu.html:291 +msgid "Remove all" +msgstr "Remove all" -#: app/views/menu.html:228 +#: app/scripts/services/utils.service.js:703 +msgid "Reset SVG" +msgstr "Reset SVG" + +#: app/views/menu.html:245 msgid "Reset default" msgstr "Reset default" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" msgstr "Reset view" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "Save" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +msgid "Save SVG" +msgstr "Save SVG" + +#: app/views/menu.html:60 msgid "Save as" msgstr "Save as" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "Select all" + +#: app/views/menu.html:313 msgid "Source code" msgstr "Source code" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "Spanish" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." msgstr "Synchronize remote files ..." -#: app/views/menu.html:50 -msgid "Templates" -msgstr "Templates" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" msgstr "Testbench" -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" msgstr "Testbench exported" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" @@ -468,23 +574,15 @@ msgstr "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" -#: app/scripts/controllers/menu.js:103 app/scripts/controllers/menu.js:126 -msgid "" -"The current project will be removed. Do you want to continue loading the " -"project?" -msgstr "" -"The current project will be removed. Do you want to continue loading the " -"project?" - -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" msgstr "The toolchain will be removed. Do you want to continue?" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" msgstr "The toolchain will be restored to default. Do you want to continue?" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" @@ -492,7 +590,7 @@ msgstr "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" @@ -500,86 +598,114 @@ msgstr "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "Toolchain" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" msgstr "Toolchain installed" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" msgstr "Toolchain not installed" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" msgstr "Toolchain not installed. Please, install the toolchain" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" msgstr "Toolchain removed" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" msgstr "Tools" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "Undo" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "Unknown board" -#: app/views/menu.html:218 +#: app/scripts/app.js:42 +msgid "Untitled" +msgstr "Untitled" + +#: app/views/menu.html:235 msgid "Update" msgstr "Update" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" -msgstr "Update the port label" +#: app/scripts/services/blocks.service.js:712 +msgid "Update the block label" +msgstr "Update the block label" + +#: app/scripts/services/blocks.service.js:639 +msgid "Update the port" +msgstr "Update the port" -#: app/views/menu.html:207 +#: app/views/menu.html:224 msgid "Upload" msgstr "Upload" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "Verify" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" msgstr "Verilog code exported" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 app/views/menu.html:306 msgid "Version" msgstr "Version" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "View" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "View license" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" msgstr "Wrong block format: {{type}}" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +msgid "Wrong parameter name {{name}}" +msgstr "Wrong parameter name {{name}}" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +msgid "Wrong port name {{name}}" +msgstr "Wrong port name {{name}}" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" msgstr "Wrong project format: {{name}}" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" msgstr "Wrong remote hostname {{name}}" +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" +msgstr "Your changes will be lost if you don’t save them" + #. And #: app/resources/blocks/labels.js:34 msgid "and" msgstr "And" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" msgstr "back" @@ -598,6 +724,21 @@ msgstr "Combinational" msgid "config" msgstr "Config" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "contadorAsc" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "contadorDes" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "Debouncer" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -624,17 +765,17 @@ msgid "dff_sr" msgstr "D flip-flop" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" msgstr "Build done" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" msgstr "Upload done" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" msgstr "Verification done" @@ -704,17 +845,17 @@ msgid "sequential" msgstr "Sequential" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "Start building ..." #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "Start uploading ..." #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "Start verification ..." @@ -733,10 +874,6 @@ msgstr "T flip-flop" msgid "tri_state" msgstr "Tri-state" -#: app/scripts/app.js:38 app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "untitled" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -747,14 +884,75 @@ msgstr "Xnor" msgid "xor" msgstr "Xor" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" msgstr "{{board}} datasheet not defined" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" msgstr "{{board}} pinout not defined" +#~ msgid "Info" +#~ msgstr "Info" + +#~ msgid "Clear all" +#~ msgstr "Clear all" + +#~ msgid "Clone selected" +#~ msgstr "Clone selected" + +#~ msgid "Do you want to clear all?" +#~ msgstr "Do you want to clear all?" + +#~ msgid "Do you want to exit the application?" +#~ msgstr "Do you want to exit the application?" + +#~ msgid "Do you want to remove the selected block?" +#~ msgstr "Do you want to remove the selected block?" + +#~ msgid "Enter the project name" +#~ msgstr "Enter the project name" + +#~ msgid "Old project format" +#~ msgstr "Old project format" + +#~ msgid "Remove selected" +#~ msgstr "Remove selected" + +#~ msgid "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" +#~ msgstr "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" + +#~ msgid "Virtual port" +#~ msgstr "Virtual port" + +#~ msgid "untitled" +#~ msgstr "untitled" + +#~ msgid "Block exported as {{name}}" +#~ msgstr "Block exported as {{name}}" + +#~ msgid "Enter the project's image path" +#~ msgstr "Enter the project's image path" + +#~ msgid "Export as block" +#~ msgstr "Export as block" + +#~ msgid "Import block" +#~ msgstr "Import block" + +#~ msgid "New project" +#~ msgstr "New project" + +#~ msgid "Open project" +#~ msgstr "Open project" + +#~ msgid "Templates" +#~ msgstr "Templates" + #~ msgid "Datasheet not defined" #~ msgstr "Datasheet not defined" diff --git a/app/resources/locale/es_ES/es_ES.po b/app/resources/locale/es_ES/es_ES.po index 803984574..320a5f54b 100644 --- a/app/resources/locale/es_ES/es_ES.po +++ b/app/resources/locale/es_ES/es_ES.po @@ -32,12 +32,12 @@ msgstr "2. Interruptor con led" msgid "3_switch_and_gate" msgstr "3. Interruptor con puerta and" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" msgstr "Desconecta y conecta la placa" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "" "

FTDI driver installation instructions

  1. Connect the FPGA " "board
  2. Replace the (Interface 0) driver of the board by " @@ -47,7 +47,7 @@ msgstr "" "placa FPGA
  3. Reemplaza el driver de la (Interface 0) de la " "placa por libusbK
  4. Desconecta y conecta la placa
" -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "" "

FTDI driver uninstallation instructions

  1. Find the FPGA USB " "Device
  2. Select the board interface and uninstall the driver
" @@ -56,79 +56,126 @@ msgstr "" "dispositivo USB FPGA
  • Selecciona la interfaz de la placa y desinstala " "el driver
  • " -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" msgstr "Sobre Icestudio" -#: app/scripts/controllers/menu.js:421 +#: app/views/menu.html:275 +msgid "Add" +msgstr "Añadir" + +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" msgstr "Añade un bloque para comenzar" -#: app/views/menu.html:285 +#: app/views/menu.html:35 +msgid "Add as block" +msgstr "Añadir como bloque" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" +msgstr "Colecciones eliminadas" + +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "Todas las colecciones almacenadas se perderán. ¿Deseas continuar?" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "Autor" + +#: app/views/menu.html:331 msgid "Basic" msgstr "Básico" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" msgstr "Euskera" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" -msgstr "Bloque exportado como {{name}}" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +msgid "Block updated" +msgstr "Bloque actualizado" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" msgstr "Bloque {{name}} importado" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" msgstr "Placa {{name}} no detectada" -#: app/scripts/controllers/menu.js:383 app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" msgstr "Placa {{name}} seleccionada" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "Placas" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "Sintetizar" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" msgstr "Cancelar" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." msgstr "Comprobando conexión a Internet..." -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." msgstr "Comprobando Python..." -#: app/views/menu.html:113 -msgid "Clear all" -msgstr "Borrar todo" - -#: app/views/menu.html:107 -msgid "Clone selected" -msgstr "Clonar seleccionado" - -#: app/views/menu.html:288 +#: app/views/menu.html:337 msgid "Code" msgstr "Código" -#: app/views/menu.html:271 +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" +msgstr "Fichero de colecciones {{name}} añadido" + +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" +msgstr "Colección {{name}} eliminada" + +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "Colección {{name}} seleccionada" + +#: app/views/menu.html:185 app/views/menu.html:271 +msgid "Collections" +msgstr "Colecciones" + +#: app/views/menu.html:317 msgid "Community forum" msgstr "Foro de la comunidad" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "Constante" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "Copiar" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "Cortar" + +#: app/views/menu.html:181 msgid "Datasheet" msgstr "Datasheet" -#: app/scripts/services/tools.service.js:294 +#: app/views/menu.html:189 +msgid "Default" +msgstr "Por defecto" + +#: app/scripts/services/tools.service.js:315 msgid "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" @@ -136,335 +183,394 @@ msgstr "" "No se encuentra la toolchain por defecto, por lo que será descargada. Esta " "operación requiere conexión a Internet. ¿Deseas continuar?" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "Descripción" + +#: app/views/menu.html:264 msgid "Disable" msgstr "Deshabilitar" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" -msgstr "¿Deseas borrar todo?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" +msgstr "¿Deseas cerrar la aplicación?" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" -msgstr "¿Deseas eliminar el bloque seleccionado?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" +msgstr "¿Deseas eliminar la colección {{name}}?" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" msgstr "Documentación" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" msgstr "Drivers" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" msgstr "Drivers deshabilitados" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" msgstr "Drivers habilitados" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" msgstr "Puertos E/S de la FPGA duplicados" -#: app/views/menu.html:100 +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "Atributos del bloque duplicados" + +#: app/views/menu.html:88 msgid "Edit" msgstr "Editar" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" msgstr "Habilitar" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "Inglés" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +msgid "Enter the constant blocks" +msgstr "Introduce los bloques constante" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" msgstr "Introduce los puertos de entrada" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" msgstr "Introduce los puertos de salida" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" -msgstr "Introduce la ruta de la imagen del proyecto" +#: app/scripts/services/blocks.service.js:215 +msgid "Enter the parameters" +msgstr "Introduce los parámetros" -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" -msgstr "Introduce el título del proyecto" +#: app/scripts/services/blocks.service.js:57 +msgid "Enter the ports" +msgstr "Introduce los puertos" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" msgstr "Introduce el nombre del host remoto usuario@host (experimental)" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" msgstr "Error: toolchain por defecto no encontrada en '{{dir}}'" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "Error: {{error}}" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "Ejemplos" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." msgstr "Ejecutar {{label}} remoto ..." -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "Exportar" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "Exportar como bloque" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." msgstr "Extraer ficheros de apio..." -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." msgstr "Extraer paquetes de apio..." -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." msgstr "Extraer ficheros del virtual env" -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" msgstr "Puertos E/S de la FPGA no definidos" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "FPGA pin" + +#: app/views/menu.html:26 msgid "File" msgstr "Archivo" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "" "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" "El archivo {{file}} ya existe en el directorio del proyecto. ¿Deseas " "reemplazarlo?" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" msgstr "El archivo {{file}} no existe" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" msgstr "Archivo {{file}} importado" -#: app/views/menu.html:159 +#: app/views/menu.html:114 +msgid "Fit content" +msgstr "Ajustar contenido" + +#: app/views/menu.html:160 msgid "French" msgstr "Francés" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" msgstr "GTKWave exportado" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" msgstr "Gallego" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "Ayuda" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" msgstr "Es necesario Homebrew" -#: app/views/menu.html:120 -msgid "Image path" -msgstr "Ruta de la imagen" +#: app/scripts/services/utils.service.js:694 +msgid "Image" +msgstr "Imagen" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" msgstr "Imagen {{name}} guardada" -#: app/views/menu.html:73 -msgid "Import block" -msgstr "Importar bloque" - -#: app/views/menu.html:289 -msgid "Info" -msgstr "Info" +#: app/views/menu.html:338 +msgid "Information" +msgstr "Información" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "Entrada" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" msgstr "Instalar" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." msgstr "Instalar apio..." -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" msgstr "Instalación completada" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" msgstr "Instalando la toolchain" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" msgstr "Es necesario conexión a Internet" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
    block already connected" msgstr "Conexión de Pull up no válida:
    hay un bloque conectado" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
    only Input blocks allowed" msgstr "" "Conexión de Pull up no válida:
    sólo se permiten bloques " "Entrada" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
    Pull up already connected" msgstr "Conexión de bloque no válida:
    hay un Pull up conectado" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" msgstr "Conexión no válida" -#: app/scripts/services/graph.service.js:127 +#: app/scripts/services/graph.service.js:219 +msgid "Invalid connection: {{a}} → {{b}}" +msgstr "Conexión no válida: {{a}} → {{b}}" + +#: app/scripts/services/graph.service.js:180 msgid "Invalid multiple input connections" msgstr "Conexiones de entrada múltiple no válidas" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" -msgstr "Etiqueta actualizada" - -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "Idioma" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "Parámetro local" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." msgstr "Crear virtual env..." -#: app/views/menu.html:27 -msgid "New project" -msgstr "Nuevo proyecto" +#: app/scripts/services/utils.service.js:678 +msgid "Name" +msgstr "Nombre" + +#: app/views/menu.html:29 +msgid "New" +msgstr "Nuevo" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" msgstr "Nuevo proyecto {{name}} creado" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "Ninguna colección almacenada" + +#: app/scripts/controllers/main.js:15 msgid "OK" msgstr "OK" -#: app/views/menu.html:30 -msgid "Open project" -msgstr "Abrir proyecto" +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" +msgstr "Formato de proyecto antiguo {{version}}" + +#: app/views/menu.html:32 +msgid "Open" +msgstr "Abrir" -#: app/scripts/services/common.service.js:156 +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" +msgstr "Abrir SVG" + +#: app/scripts/services/project.service.js:395 msgid "Original file {{file}} does not exist" msgstr "El archivo original {{file}} no existe" -#: app/views/menu.html:291 +#: app/views/menu.html:335 msgid "Output" msgstr "Salida" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" msgstr "Fichero PCF exportado" -#: app/views/menu.html:117 +#: app/views/menu.html:104 +msgid "Paste" +msgstr "Pegar" + +#: app/views/menu.html:118 msgid "Preferences" msgstr "Preferencias" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:121 +msgid "Project information" +msgstr "Información del proyecto" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" msgstr "Proyecto {{name}} cargado" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" msgstr "Proyecto {{name}} guardado" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" msgstr "Es necesario Python 2.7" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "Salir" + +#: app/views/design.html:4 msgid "Read only" msgstr "Solo lectura" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "Rehacer" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" msgstr "Host remoto {{name}} no conectado" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" msgstr "Nombre del host remoto" -#: app/views/menu.html:223 +#: app/views/menu.html:240 app/views/menu.html:279 msgid "Remove" msgstr "Eliminar" -#: app/views/menu.html:110 -msgid "Remove selected" -msgstr "Eliminar seleccionado" +#: app/views/menu.html:291 +msgid "Remove all" +msgstr "Eliminar todo" -#: app/views/menu.html:228 +#: app/scripts/services/utils.service.js:703 +msgid "Reset SVG" +msgstr "Resetear SVG" + +#: app/views/menu.html:245 msgid "Reset default" msgstr "Reset default" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" msgstr "Resetear vista" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "Guardar" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +msgid "Save SVG" +msgstr "Guardar SVG" + +#: app/views/menu.html:60 msgid "Save as" msgstr "Guardar como" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "Seleccionar todo" + +#: app/views/menu.html:313 msgid "Source code" msgstr "Código fuente" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "Español" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." msgstr "Sincronizando ficheros remotos ..." -#: app/views/menu.html:50 -msgid "Templates" -msgstr "Plantillas" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" msgstr "Testbench" -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" msgstr "Testbench exportado" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" @@ -472,22 +578,16 @@ msgstr "" "La configuración actual de E/S de la FPGA se perderá. ¿Deseas cambiar a la " "placa {{name}}?" -#: app/scripts/controllers/menu.js:103 app/scripts/controllers/menu.js:126 -msgid "" -"The current project will be removed. Do you want to continue loading the " -"project?" -msgstr "El actual proyecto se borrará. ¿Deseas continuar abriendo el proyecto?" - -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" msgstr "La toolchain será eliminada. ¿Deseas continuar?" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" msgstr "" "La toolchain será restaurada a los valores por defecto: ¿Deseas continuar?" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" @@ -495,7 +595,7 @@ msgstr "" "La toolchain será actualizada. Esta operación requiere conexión a Internet. " "¿Deseas continuar?" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" @@ -503,86 +603,114 @@ msgstr "" "Esta operación de importación requiere una ruta del proyecto. Debes guardar " "el proyecto actual. ¿Deseas continuar?" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "Toolchain" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" msgstr "Toolchain instalada" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" msgstr "La toolchain no está instalada" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" msgstr "La toolchain no está instalada. Por favor, instala la toolchain" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" msgstr "Toolchain eliminada" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" msgstr "Herramientas" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "Deshacer" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "Placa desconocida" -#: app/views/menu.html:218 +#: app/scripts/app.js:42 +msgid "Untitled" +msgstr "Sin título" + +#: app/views/menu.html:235 msgid "Update" msgstr "Actualizar" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" -msgstr "Actualizar la etiqueta del puerto" +#: app/scripts/services/blocks.service.js:712 +msgid "Update the block label" +msgstr "Actualizar la etiqueta del bloque" + +#: app/scripts/services/blocks.service.js:639 +msgid "Update the port" +msgstr "Actualizar el puerto" -#: app/views/menu.html:207 +#: app/views/menu.html:224 msgid "Upload" msgstr "Cargar" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "Verificar" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" msgstr "Código Verilog exportado" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 app/views/menu.html:306 msgid "Version" msgstr "Versión" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "Ver" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "Ver licencia" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" msgstr "Formato de bloque incorrecto: {{type}}" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +msgid "Wrong parameter name {{name}}" +msgstr "Nombre del parámetro {{name}} incorrecto" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +msgid "Wrong port name {{name}}" +msgstr "Nombre del puerto {{name}} incorrecto" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" msgstr "Formato de proyecto incorrecto: {{name}}" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" msgstr "Nombre del host remoto incorrecto {{name}}" +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" +msgstr "Tus cambios se perderán si no los guardas" + #. And #: app/resources/blocks/labels.js:34 msgid "and" msgstr "And" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" msgstr "volver" @@ -601,6 +729,21 @@ msgstr "Combinacional" msgid "config" msgstr "Config" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "Contador ascendente" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "Contador descendente" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "Antirrebotes" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -627,17 +770,17 @@ msgid "dff_sr" msgstr "Biestable D" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" msgstr "Sintetizado realizado" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" msgstr "Carga realizada" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" msgstr "Verificación realizada" @@ -707,17 +850,17 @@ msgid "sequential" msgstr "Secuencial" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "Comenzar sintetizado ..." #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "Comenzar carga ..." #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "Comenzar verificación ..." @@ -736,10 +879,6 @@ msgstr "Biestable T" msgid "tri_state" msgstr "Tri-estado" -#: app/scripts/app.js:38 app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "Sin título" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -750,14 +889,74 @@ msgstr "Xnor" msgid "xor" msgstr "Xor" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" msgstr "{{board}} datasheet no definido" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" msgstr "{{board}} pinout no definido" +#~ msgid "Info" +#~ msgstr "Info" + +#~ msgid "Clear all" +#~ msgstr "Borrar todo" + +#~ msgid "Clone selected" +#~ msgstr "Clonar seleccionado" + +#~ msgid "Do you want to clear all?" +#~ msgstr "¿Deseas borrar todo?" + +#~ msgid "Do you want to exit the application?" +#~ msgstr "¿Deseas salir de la aplicación?" + +#~ msgid "Do you want to remove the selected block?" +#~ msgstr "¿Deseas eliminar el bloque seleccionado?" + +#~ msgid "Enter the project name" +#~ msgstr "Introduce el nombre del proyecto" + +#~ msgid "Old project format" +#~ msgstr "Formato de proyecto antiguo" + +#~ msgid "Remove selected" +#~ msgstr "Eliminar seleccionado" + +#~ msgid "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" +#~ msgstr "" +#~ "El actual proyecto se borrará. ¿Deseas continuar abriendo el proyecto?" + +#~ msgid "Virtual port" +#~ msgstr "Puerto virtual" + +#~ msgid "untitled" +#~ msgstr "Sin título" + +#~ msgid "Block exported as {{name}}" +#~ msgstr "Bloque exportado como {{name}}" + +#~ msgid "Enter the project's image path" +#~ msgstr "Introduce la ruta de la imagen del proyecto" + +#~ msgid "Export as block" +#~ msgstr "Exportar como bloque" + +#~ msgid "Import block" +#~ msgstr "Importar bloque" + +#~ msgid "New project" +#~ msgstr "Nuevo proyecto" + +#~ msgid "Open project" +#~ msgstr "Abrir proyecto" + +#~ msgid "Templates" +#~ msgstr "Plantillas" + #~ msgid "Datasheet not defined" #~ msgstr "Datasheet no definido" diff --git a/app/resources/locale/eu_ES/eu_ES.po b/app/resources/locale/eu_ES/eu_ES.po index b810708b6..03b6e220d 100644 --- a/app/resources/locale/eu_ES/eu_ES.po +++ b/app/resources/locale/eu_ES/eu_ES.po @@ -15,548 +15,696 @@ msgstr "" #. 1. Basic #: app/resources/examples/labels.js:4 msgid "1_basic" -msgstr "1. Basikoa" +msgstr "1. Oinarrizkoa" #. 1. Led on #: app/resources/examples/labels.js:6 msgid "1_led_on" -msgstr "1. Led-a piztu" +msgstr "1. Leda piztu" #. 2. Switch led #: app/resources/examples/labels.js:8 msgid "2_switch_led" -msgstr "2. Etengailua led batekin" +msgstr "2. Pultsadorea leda" #. 3. Switch and gate #: app/resources/examples/labels.js:10 msgid "3_switch_and_gate" -msgstr "3. Etengailua and atearekin" +msgstr "3. Pultsadorea eta AND atea" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" -msgstr "" +msgstr "Plaka deskonektatu eta konekta ezazu berriro" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "" "

    FTDI driver installation instructions

    1. Connect the FPGA " "board
    2. Replace the (Interface 0) driver of the board by " "libusbK
    3. Unplug and reconnect the board
    " msgstr "" +"

    FTDI driver-a instalatzeko instrukzioak

    1. FPGA plaka konekta " +"ezazu
    2. Plakaren (Interface 0) driver-a aldatu eta jar ezazu " +"honakoa: libusbK
    3. Plaka deskonektatu eta konekta ezazu " +"berriro
    " -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "" "

    FTDI driver uninstallation instructions

    1. Find the FPGA USB " "Device
    2. Select the board interface and uninstall the driver
    " msgstr "" +"

    FTDI driver-a desinstalatzeko instrukzioak

    1. FPGAren USB " +"gailua bila ezazu
    2. Plakaren interfazea hauta ezazu eta driver-a " +"desinstalatu
    " -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" -msgstr "Icestudio informazioa" +msgstr "Icestudio-ri buruz..." + +#: app/views/menu.html:275 +msgid "Add" +msgstr "" -#: app/scripts/controllers/menu.js:421 +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" +msgstr "Gehi ezazu bloke bat hasteko" + +#: app/views/menu.html:35 +msgid "Add as block" +msgstr "Blokea sortu" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" msgstr "" -#: app/views/menu.html:285 +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "Egilea" + +#: app/views/menu.html:331 msgid "Basic" -msgstr "Basikoa" +msgstr "Oinarrizkoa" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" -msgstr "Euskera" +msgstr "Euskara" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" -msgstr "Blokea {{name}} bezala esportatua" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +msgid "Block updated" +msgstr "Etiketa freskatua dago" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" -msgstr "{{name}} blokea importatua" +msgstr "{{name}} blokea inportatu duzu" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" -msgstr "{{name}} plaka ez da aurkitzen" +msgstr "{{name}} plaka ez da aurkitu" -#: app/scripts/controllers/menu.js:383 app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" -msgstr "{{name}} paka aukeratul" +msgstr "{{name}} plaka hautatu duzu" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "Plakak" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "Sintetizatu" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" -msgstr "" +msgstr "Utzi" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." -msgstr "" +msgstr "Interneteko sarbidea egiaztatu..." -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." +msgstr "Python egiaztatu..." + +#: app/views/menu.html:337 +msgid "Code" +msgstr "Kodea" + +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" msgstr "" -#: app/views/menu.html:113 -msgid "Clear all" -msgstr "Dena ezabatu" +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" +msgstr "" -#: app/views/menu.html:107 -msgid "Clone selected" -msgstr "Aukeratua klonatu" +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "" -#: app/views/menu.html:288 -msgid "Code" -msgstr "Kodea" +#: app/views/menu.html:185 app/views/menu.html:271 +msgid "Collections" +msgstr "" -#: app/views/menu.html:271 +#: app/views/menu.html:317 msgid "Community forum" msgstr "Komunitatearen foroa" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "Konstantea" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "" + +#: app/views/menu.html:181 msgid "Datasheet" +msgstr "Datu-fitxa" + +#: app/views/menu.html:189 +msgid "Default" msgstr "" -#: app/scripts/services/tools.service.js:294 +#: app/scripts/services/tools.service.js:315 msgid "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" msgstr "" +"Toolchain lehenetsia ez da aurkitu. Hortaz, deskargatu egingo da. Eragiketak " +"Interneteko sarbidea behar du, jarraitu nahi al duzu?" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "Azalpena" + +#: app/views/menu.html:264 msgid "Disable" -msgstr "" +msgstr "Desgaitu" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" -msgstr "¿Dena ezabatu nahi duzu?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" +msgstr "" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" -msgstr "¿Aukeratutako blokea ezabatu nahi duzu?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" +msgstr "" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" -msgstr "Documentazioa" +msgstr "Dokumentazioa" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" -msgstr "" +msgstr "Driverrak" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" -msgstr "" +msgstr "Driverrak desgaitu dira" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" -msgstr "" +msgstr "Driverrak gaitu dira" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" -msgstr "FPGAren E/S portuak bikoiztuak" +msgstr "FPGAren E/S portuak bikoiztu dira" + +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "Blokearen ezaugarriak bikoiztu dira" -#: app/views/menu.html:100 +#: app/views/menu.html:88 msgid "Edit" msgstr "Editatu" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" -msgstr "Enable" +msgstr "Onartu" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "Ingelesa" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +msgid "Enter the constant blocks" +msgstr "Konstante-blokeak sar itzazu" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" -msgstr "" +msgstr "Sarrerako portuak sar itzazu" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" -msgstr "" +msgstr "Irteerako portuak sar itzazu" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" -msgstr "Proiektuaren irudi bidea sartu" +#: app/scripts/services/blocks.service.js:215 +msgid "Enter the parameters" +msgstr "Parametroak sar itzazu" -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" -msgstr "Proiektuari izena jarri" +#: app/scripts/services/blocks.service.js:57 +msgid "Enter the ports" +msgstr "Portuak sar itzazu" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" -msgstr "Enter the remote hostname user@host (experimental)" +msgstr "" +"Urrutiko ostalariaren izena sar ezazu erabiltzailea@host (esperimentala)" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" -msgstr "" +msgstr "Errorea: Toolchain lehenetsia ez da '{{dir}}'-en aurkitu" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "Errorea: {{error}}" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "Adibideak" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." -msgstr "Execute remote {{label}} ..." +msgstr "Exekutatu urrutiko {{label}} ..." -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "Esportatu" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "Blokea bezala esportatu" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." -msgstr "" +msgstr "Apio fitxategiak atera..." -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." -msgstr "" +msgstr "Apio pakete lehenetsiak atera..." -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." -msgstr "" +msgstr "Env birtualaren fitxategiak atera..." -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" -msgstr "FPGAren E/S portuak definitu gabe" +msgstr "FPGAren E/S portuak definitu gabe daude" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "" + +#: app/views/menu.html:26 msgid "File" msgstr "Fitxategia" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "" "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" +"Proiektuaren direktorioan {{file}} fitxategia dagoeneko bada. Fitxategia " +"ordeztu nahi al duzu?" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" -msgstr "{{file}} fitxeroa ez da existitzen" +msgstr "Ez dago {{file}} izeneko fitxategirik" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" +msgstr "{{file}} fitxategia inportatu da" + +#: app/views/menu.html:114 +msgid "Fit content" msgstr "" -#: app/views/menu.html:159 +#: app/views/menu.html:160 msgid "French" -msgstr "" +msgstr "Frantsesa" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" -msgstr "GTKWave esportatua" +msgstr "GTKWave-a esportatu da" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" -msgstr "Galiziako" +msgstr "Galegoa" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "Laguntza" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" -msgstr "Homebrew is required" +msgstr "Homebrew-a behar da" -#: app/views/menu.html:120 -msgid "Image path" -msgstr "Ruta de la imagen" +#: app/scripts/services/utils.service.js:694 +msgid "Image" +msgstr "Irudia" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" -msgstr "" +msgstr "{{name}} izeneko irudia gorde da" -#: app/views/menu.html:73 -msgid "Import block" -msgstr "Blokea inportatu" - -#: app/views/menu.html:289 -msgid "Info" -msgstr "Info" +#: app/views/menu.html:338 +msgid "Information" +msgstr "" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "Sarrera" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" -msgstr "" +msgstr "Instalatu" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." -msgstr "" +msgstr "Apio lehenetsia instalatu..." -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" -msgstr "Instalazioa amaitua" +msgstr "Instalazioa amaitu da" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" -msgstr "Toolchain instalatzen" +msgstr "Toolchain-a instalatzen ari da" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" -msgstr "Internet konexioa behar da" +msgstr "Interneteko sarbidea behar da" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
    block already connected" -msgstr "" +msgstr "Pull up konexio baliogabea:
    blokea dagoeneko konektatua dago" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
    only Input blocks allowed" msgstr "" +"Pull up konexio baliogabea:
    sarrera blokeak soilik dira " +"onargarriak" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
    Pull up already connected" msgstr "" +"Bloke konexio baliogabeak:
    Pull up -a dagoeneko konektatua dago" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" -msgstr "" +msgstr "Konexio baliogabea" -#: app/scripts/services/graph.service.js:127 -msgid "Invalid multiple input connections" -msgstr "" +#: app/scripts/services/graph.service.js:219 +msgid "Invalid connection: {{a}} → {{b}}" +msgstr "Konexio baliogabea: {{a}} → {{b}}" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" -msgstr "Etiketa freskatua" +#: app/scripts/services/graph.service.js:180 +msgid "Invalid multiple input connections" +msgstr "Sarrerako konexio anitzak baliogabeak" -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "Hizkuntza" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "Parametro lokala" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." -msgstr "" +msgstr "Env birtuala sortu..." + +#: app/scripts/services/utils.service.js:678 +msgid "Name" +msgstr "Izena" -#: app/views/menu.html:27 -msgid "New project" -msgstr "Proiektu berria" +#: app/views/menu.html:29 +msgid "New" +msgstr "Berria" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" -msgstr "{{name}} proiektu sortuta" +msgstr "{{name}} proiektua sortu da" + +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/main.js:15 msgid "OK" +msgstr "Ok" + +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" msgstr "" -#: app/views/menu.html:30 -msgid "Open project" -msgstr "Ireki proiektua" +#: app/views/menu.html:32 +msgid "Open" +msgstr "Ireki" + +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" +msgstr "SVGa ireki" -#: app/scripts/services/common.service.js:156 +#: app/scripts/services/project.service.js:395 msgid "Original file {{file}} does not exist" -msgstr "" +msgstr "Jatorrizko {{file}} fitxategia ez dago" -#: app/views/menu.html:291 +#: app/views/menu.html:335 msgid "Output" msgstr "Irteera" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" -msgstr "PCF fitxategia esportatua" +msgstr "PCF fitxategia esportatu da" -#: app/views/menu.html:117 -msgid "Preferences" +#: app/views/menu.html:104 +msgid "Paste" msgstr "" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:118 +msgid "Preferences" +msgstr "Lehentasunak" + +#: app/views/menu.html:121 +msgid "Project information" +msgstr "Proiektuaren informazioa" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" -msgstr "{{name}} proiektua irekita" +msgstr "{{name}} proiektua kargatu da" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" -msgstr "{{name}} proiektua gordeta" +msgstr "{{name}} proiektua gorde da" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" -msgstr "" +msgstr "Python 2.7 behar da" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "Utzi" + +#: app/views/design.html:4 msgid "Read only" msgstr "Irakurtzeko soilik" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" -msgstr "Remote host {{name}} not connected" +msgstr "{{name}} urrutiko ostalaria ez dago konektatua" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" -msgstr "" +msgstr "Urrutiko ostalariaren izena" -#: app/views/menu.html:223 +#: app/views/menu.html:240 app/views/menu.html:279 msgid "Remove" msgstr "Ezabatu" -#: app/views/menu.html:110 -msgid "Remove selected" -msgstr "Aukeratua ezabatu" +#: app/views/menu.html:291 +msgid "Remove all" +msgstr "" -#: app/views/menu.html:228 +#: app/scripts/services/utils.service.js:703 +msgid "Reset SVG" +msgstr "SVGa berrezarri" + +#: app/views/menu.html:245 msgid "Reset default" -msgstr "" +msgstr "Jatorrizkoa berrezarri" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" -msgstr "Bista reseteatu" +msgstr "Bista berrezarri" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "Gorde" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +msgid "Save SVG" +msgstr "SVGa gorde" + +#: app/views/menu.html:60 msgid "Save as" msgstr "Gorde honela" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "" + +#: app/views/menu.html:313 msgid "Source code" -msgstr "Jatorrizko kodea" +msgstr "Iturburu kodea" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "Gaztelera" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." -msgstr "Synchronize remote files ..." +msgstr "Urrutiko fitxategiak sinkronizatu..." -#: app/views/menu.html:50 -msgid "Templates" -msgstr "Ereduak" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" -msgstr "Testbench esportatua" +msgstr "Testbench " -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" -msgstr "Testbench esportatua" +msgstr "Testbench-a esportatu da" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" msgstr "" -"FPGAaren E/S configurazioa galduko da. {{name}} plaka aldatu nahi duzu?" - -#: app/scripts/controllers/menu.js:103 app/scripts/controllers/menu.js:126 -msgid "" -"The current project will be removed. Do you want to continue loading the " -"project?" -msgstr "Proiektu hau ezabatuko da. Proiektua irekitzen jarraitu nahi duzu?" +"FPGAaren E/S konfigurazioa galduko da. {{name}} plaka aldatu nahi duzu?" -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" -msgstr "" +msgstr "Toolchain-a ezabatuko da. Jarraitu nahi al duzu?" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" msgstr "" +"Toolchain-aren jatorrizko balioak berrezarriko dira. Jarraitu nahi al duzu?" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" msgstr "" +"Toolchain-a eguneratuko da. Operazio horrek Interneteko sarbidea behar du. " +"Jarraitu nahi al duzu?" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" msgstr "" +"Inportazio operazioak proiektu-bidea behar du. Uneko proiektua gorde " +"beharko duzu. Jarraitu nahi al duzu?" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "Toolchain" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" -msgstr "Toolchain instalatua" +msgstr "Toolchain-a instalatu da" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" -msgstr "" +msgstr "Toolchain-a ez da instalatu" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" -msgstr "" +msgstr "Toolchain-a ez da instalatu. Mesedez, toolchaina instala ezazu" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" -msgstr "Toolchain ezabatuta" +msgstr "Toolchain-a ezabatu da" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" -msgstr "Erremintak" +msgstr "Tresnak" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "Plaka ezezaguna" -#: app/views/menu.html:218 -msgid "Update" +#: app/scripts/app.js:42 +msgid "Untitled" msgstr "" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" -msgstr "" +#: app/views/menu.html:235 +msgid "Update" +msgstr "Eguneratu" + +#: app/scripts/services/blocks.service.js:712 +msgid "Update the block label" +msgstr "Blokearen etiketa eguneratu" -#: app/views/menu.html:207 +#: app/scripts/services/blocks.service.js:639 +msgid "Update the port" +msgstr "Portua eguneratu" + +#: app/views/menu.html:224 msgid "Upload" msgstr "Kargatu" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "Egiaztatu" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" -msgstr "Verilog kodea esportatua" +msgstr "Verilog kodea esportatu da" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 app/views/menu.html:306 msgid "Version" msgstr "Bertsioa" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "Ikusi" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "Lizentzia ikusi" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" -msgstr "Blokearen formatua okerra: {{type}}" +msgstr "Blokearen formatua okerra da: {{type}}" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +msgid "Wrong parameter name {{name}}" +msgstr "Parametroaren formatua okerra da: {{name}}" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +msgid "Wrong port name {{name}}" +msgstr "Portuaren izena okerra da: {{name}}" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" -msgstr "Proiektu formatua okerra: {{name}}" +msgstr "Proiektuaren formatua okerra da: {{name}}" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" +msgstr "Urrutiko ostalariaren {{name}} izena okerra da" + +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" msgstr "" #. And @@ -564,9 +712,9 @@ msgstr "" msgid "and" msgstr "And" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" -msgstr "" +msgstr "atzera" #. Bit #: app/resources/blocks/labels.js:4 @@ -576,13 +724,28 @@ msgstr "Bit" #. Combinational #: app/resources/blocks/labels.js:16 msgid "combinational" -msgstr "" +msgstr "Konbinazionala" #. Config #: app/resources/blocks/labels.js:6 msgid "config" msgstr "Config" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "Goranzko zenbatzailea" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "Beheranzko zenbatzailea" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "Erreboteen aurkakoa" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -601,32 +764,32 @@ msgstr "Demux 1:8" #. D flip-flop async #: app/resources/blocks/labels.js:50 msgid "dff_ar" -msgstr "Bistable D asink" +msgstr "D biegonkor asink" #. D flip-flop async #: app/resources/blocks/labels.js:52 msgid "dff_sr" -msgstr "Bistable D" +msgstr "D biegonkorra" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" -msgstr "Sintetizatua egina" +msgstr "Sintetizatua egin da" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" -msgstr "Karga egina" +msgstr "Karga egin da" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" -msgstr "Egiaztapena egina" +msgstr "Egiaztapena egin da" #. Gate #: app/resources/blocks/labels.js:32 msgid "gate" -msgstr "Gate" +msgstr "Atea" #. Hex 7 Segment CA #: app/resources/blocks/labels.js:26 @@ -686,42 +849,38 @@ msgstr "Pull up inv" #. Sequential #: app/resources/blocks/labels.js:48 msgid "sequential" -msgstr "" +msgstr "Sekuentziala" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "Sintetizatua hasi ..." #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "Karga hasi ..." #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "Egiaztapena hasi ..." #. T flip-flop async #: app/resources/blocks/labels.js:54 msgid "tff_ar" -msgstr "Bistable T asink" +msgstr "T biegonkor asink" #. T flip-flop #: app/resources/blocks/labels.js:56 msgid "tff_sr" -msgstr "Bistable T" +msgstr "T biegonkorra" #. Tri-state #: app/resources/blocks/labels.js:12 msgid "tri_state" msgstr "Tri-state" -#: app/scripts/app.js:38 app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "Izenik gabe" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -732,22 +891,73 @@ msgstr "Xnor" msgid "xor" msgstr "Xor" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" -msgstr "" +msgstr "{{board}} ez zehaztua" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" -msgstr "" +msgstr "{{board}} pinout ez zehaztua" + +#~ msgid "Info" +#~ msgstr "Info" + +#~ msgid "Clear all" +#~ msgstr "Dena ezabatu" + +#~ msgid "Clone selected" +#~ msgstr "Hautua klonatu" + +#~ msgid "Do you want to clear all?" +#~ msgstr "Dena ezabatu nahi al duzu?" + +#~ msgid "Do you want to exit the application?" +#~ msgstr "Aplikazioa utzi nahi al duzu?" + +#~ msgid "Do you want to remove the selected block?" +#~ msgstr "Hautatutako blokea ezabatu nahi al duzu?" + +#~ msgid "Enter the project name" +#~ msgstr "Proiektuari izena eman" + +#~ msgid "Old project format" +#~ msgstr "Proiektu formatu zaharra" + +#~ msgid "Remove selected" +#~ msgstr "Hautua ezabatu" + +#~ msgid "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" +#~ msgstr "" +#~ "Proiektu hau ezabatuko da. Proiektua irekitzen jarraitu nahi al duzu?" + +#~ msgid "Virtual port" +#~ msgstr "Portu birtuala" + +#~ msgid "untitled" +#~ msgstr "Izenik gabe" + +#~ msgid "Block exported as {{name}}" +#~ msgstr "Blokea {{name}} bezala esportatua" + +#~ msgid "Enter the project's image path" +#~ msgstr "Proiektuaren irudi bidea sartu" + +#~ msgid "Import block" +#~ msgstr "Blokea inportatu" + +#~ msgid "New project" +#~ msgstr "Proiektu berria" + +#~ msgid "Open project" +#~ msgstr "Ireki proiektua" + +#~ msgid "Templates" +#~ msgstr "Ereduak" #~ msgid "comb" #~ msgstr "Comb" #~ msgid "sec" #~ msgstr "Sec" - -#~ msgid "Enter the block's label" -#~ msgstr "Blokearen etiketa sartu" - -#~ msgid "Enter the block's ports" -#~ msgstr "Blokearen portuak sartu" diff --git a/app/resources/locale/fr_FR/fr_FR.po b/app/resources/locale/fr_FR/fr_FR.po index 78a656161..fd9bbf312 100644 --- a/app/resources/locale/fr_FR/fr_FR.po +++ b/app/resources/locale/fr_FR/fr_FR.po @@ -32,12 +32,12 @@ msgstr "2. Switch led" msgid "3_switch_and_gate" msgstr "3. Switch and gate" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" msgstr "Débrancher et reconnecter la carte" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "" "

    FTDI driver installation instructions

    1. Connect the FPGA " "board
    2. Replace the (Interface 0) driver of the board by " @@ -47,7 +47,7 @@ msgstr "" "carte FPGA
    3. Remplacer le pilote (Interface 0) de la carte par " "libusbK
    4. Débrancher puis rebrancher la carte
    " -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "" "

    FTDI driver uninstallation instructions

    1. Find the FPGA USB " "Device
    2. Select the board interface and uninstall the driver
    " @@ -56,409 +56,529 @@ msgstr "" "périphérique USB FPGA
  • Sélectionner la carte interface et " "désinstaller le pilote
  • " -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" msgstr "À propos d'Icestudio" -#: app/scripts/controllers/menu.js:421 +#: app/views/menu.html:275 +msgid "Add" +msgstr "" + +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" msgstr "Ajouter un bloc pour commencer" -#: app/views/menu.html:285 +#: app/views/menu.html:35 +#, fuzzy +msgid "Add as block" +msgstr "Ajouter un bloc pour commencer" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" +msgstr "" + +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "" + +#: app/views/menu.html:331 msgid "Basic" msgstr "Basique" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" msgstr "Basque" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" -msgstr "Bloc exporté comme {{name}}" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +#, fuzzy +msgid "Block updated" +msgstr "Titre mis à jour" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" msgstr "Bloc {{name}} importé" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" msgstr "Carte {{name}} non détectée" -#: app/scripts/controllers/menu.js:383 app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" msgstr "Carte {{name}} séléctionnée" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "Cartes" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "Construire" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" msgstr "Annuler" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." msgstr "Vérifier la connexion Internet..." -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." msgstr "Vérifier Python..." -#: app/views/menu.html:113 -msgid "Clear all" -msgstr "Tout nettoyer" - -#: app/views/menu.html:107 -msgid "Clone selected" -msgstr "Cloner la selection" - -#: app/views/menu.html:288 +#: app/views/menu.html:337 msgid "Code" msgstr "Code" -#: app/views/menu.html:271 +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" +msgstr "" + +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" +msgstr "" + +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "" + +#: app/views/menu.html:185 app/views/menu.html:271 +msgid "Collections" +msgstr "" + +#: app/views/menu.html:317 msgid "Community forum" msgstr "Forum communautaire" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "" + +#: app/views/menu.html:181 msgid "Datasheet" msgstr "Documentation" -#: app/scripts/services/tools.service.js:294 +#: app/views/menu.html:189 +msgid "Default" +msgstr "" + +#: app/scripts/services/tools.service.js:315 msgid "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" msgstr "" +"La toolchain par default n'a pas été trouvée. La toolchain va être " +"téléchargée. Cette operation nécessite une connexion internet.Voulez-vous " +"continuer ?" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "" + +#: app/views/menu.html:264 msgid "Disable" msgstr "Désactiver" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" -msgstr "Voulez vous tout nettoyer?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" +msgstr "" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" -msgstr "Voulez vous supprimer le bloc séléctionné?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" +msgstr "" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" msgstr "Documentation" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" msgstr "Pilote" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" msgstr "Pilote désactivé" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" msgstr "Pilote activé" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" msgstr "Ports d'entrée sortie FPGA dupliqué" -#: app/views/menu.html:100 +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "" + +#: app/views/menu.html:88 msgid "Edit" msgstr "Édition" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" msgstr "Activer" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "Anglais" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +#, fuzzy +msgid "Enter the constant blocks" +msgstr "Entrer les ports de sortie" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" msgstr "Entrer les ports d'entrée" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" msgstr "Entrer les ports de sortie" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" -msgstr "Entrer le chemin image du projet" +#: app/scripts/services/blocks.service.js:215 +#, fuzzy +msgid "Enter the parameters" +msgstr "Entrer les ports d'entrée" -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" -msgstr "Entrer un nom de projet" +#: app/scripts/services/blocks.service.js:57 +#, fuzzy +msgid "Enter the ports" +msgstr "Entrer les ports d'entrée" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" msgstr "Entrer le hostname distant user@host (experimentale)" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" -msgstr "" +msgstr "Erreur: La toolchaine par défaut n'a pas été trouvée dans '{{dir}}'" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "Erreur: {{error}}" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "Exemples" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." msgstr "Executer à distance {{label}} ..." -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "Exporter" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "Exporter un bloc" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." -msgstr "" +msgstr "Extraction des fichiers apio par défaut..." -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." -msgstr "" +msgstr "Extraction des packets apio par défaut" -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." -msgstr "" +msgstr "Extraction des fichiers d'environnement virtuels" -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" msgstr "Ports d'entrée sortie FPGA non définits" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "" + +#: app/views/menu.html:26 msgid "File" msgstr "Fichier" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "" "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" +"Le Fichier {{file}} existe déjà dans le chemin du projet. Voulez vous " +"leremplacer ?" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" msgstr "Le fichier {{file}} n'existe pas" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" msgstr "Fichier {{file}} importé" -#: app/views/menu.html:159 +#: app/views/menu.html:114 +msgid "Fit content" +msgstr "" + +#: app/views/menu.html:160 msgid "French" msgstr "Français" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" msgstr "GTKWave exporté" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" msgstr "Galois" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "Aide" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" msgstr "Homebrew est requis" -#: app/views/menu.html:120 -msgid "Image path" +#: app/scripts/services/utils.service.js:694 +#, fuzzy +msgid "Image" msgstr "Chemin image" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" -msgstr "" - -#: app/views/menu.html:73 -msgid "Import block" -msgstr "Importer un bloc" +msgstr "Image {{name}} sauvée" -#: app/views/menu.html:289 -msgid "Info" -msgstr "Info" +#: app/views/menu.html:338 +msgid "Information" +msgstr "" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "Entrée" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" -msgstr "" +msgstr "Installation" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." -msgstr "" +msgstr "Installer l'apio par défaut..." -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" msgstr "Installation terminée" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" msgstr "Installation de la toolchain" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" msgstr "Une connexion internet est requise" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
    block already connected" -msgstr "" +msgstr "Connexion de Pull up invalide:
    Le bloc est déjà connecté" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
    only Input blocks allowed" -msgstr "" +msgstr "Connexion de Pull up invalide:
    Une seule entrée autorisée" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
    Pull up already connected" -msgstr "" +msgstr "Connexion de bloc invalide:
    Pull up déjà connectée" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" msgstr "Connexion invalide" -#: app/scripts/services/graph.service.js:127 -msgid "Invalid multiple input connections" -msgstr "" +#: app/scripts/services/graph.service.js:219 +#, fuzzy +msgid "Invalid connection: {{a}} → {{b}}" +msgstr "Connexion invalide" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" -msgstr "Titre mis à jour" +#: app/scripts/services/graph.service.js:180 +msgid "Invalid multiple input connections" +msgstr "Connexions de multiples entrées invalides" -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "Langage" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." +msgstr "Faire l'environnement virtuel..." + +#: app/scripts/services/utils.service.js:678 +msgid "Name" msgstr "" -#: app/views/menu.html:27 -msgid "New project" -msgstr "Nouveau projet" +#: app/views/menu.html:29 +msgid "New" +msgstr "" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" msgstr "Nouveau projet {{name}} créé" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "" + +#: app/scripts/controllers/main.js:15 msgid "OK" msgstr "OK" -#: app/views/menu.html:30 -msgid "Open project" -msgstr "Ouvrir un projet" +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" +msgstr "" -#: app/scripts/services/common.service.js:156 -msgid "Original file {{file}} does not exist" +#: app/views/menu.html:32 +msgid "Open" msgstr "" -#: app/views/menu.html:291 +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" +msgstr "" + +#: app/scripts/services/project.service.js:395 +msgid "Original file {{file}} does not exist" +msgstr "Le fichier originel {{file}} n'éxiste pas" + +#: app/views/menu.html:335 msgid "Output" msgstr "Sortie" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" msgstr "Fichier PCF exporté" -#: app/views/menu.html:117 +#: app/views/menu.html:104 +msgid "Paste" +msgstr "" + +#: app/views/menu.html:118 msgid "Preferences" msgstr "Préférences" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:121 +msgid "Project information" +msgstr "" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" msgstr "Projet {{name}} chargé" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" msgstr "Projet {{name}} sauvegardé" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" msgstr "Python 2.7 est requis" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "" + +#: app/views/design.html:4 msgid "Read only" msgstr "Lecture seule" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" msgstr "Remote host {{name}} not connected" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" msgstr "Hostname distant" -#: app/views/menu.html:223 +#: app/views/menu.html:240 app/views/menu.html:279 msgid "Remove" +msgstr "Supprimer" + +#: app/views/menu.html:291 +msgid "Remove all" msgstr "" -#: app/views/menu.html:110 -msgid "Remove selected" -msgstr "Supprimer la selection" +#: app/scripts/services/utils.service.js:703 +#, fuzzy +msgid "Reset SVG" +msgstr "Reinitialiser la vue" -#: app/views/menu.html:228 +#: app/views/menu.html:245 msgid "Reset default" -msgstr "" +msgstr "Réinitialiser avec les paramètres par défaut" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" msgstr "Reinitialiser la vue" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "Sauvegarder" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +#, fuzzy +msgid "Save SVG" +msgstr "Sauvegarder sous" + +#: app/views/menu.html:60 msgid "Save as" msgstr "Sauvegarder sous" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "" + +#: app/views/menu.html:313 msgid "Source code" msgstr "Code source" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "Espagnole" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." msgstr "Synchroniser les fichiers distants ..." -#: app/views/menu.html:50 -msgid "Templates" -msgstr "Modèles" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" msgstr "Banc de tests exporté" -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" msgstr "Banc de tests exporté" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" @@ -466,116 +586,144 @@ msgstr "" "La configuration des entrées sorties du FPGA actuel va être perdue. Voulez " "vous changer pour la carte {{name}}?" -#: app/scripts/controllers/menu.js:103 app/scripts/controllers/menu.js:126 -msgid "" -"The current project will be removed. Do you want to continue loading the " -"project?" -msgstr "Le projet actuel sera supprimé. Continuer de charger le projet?" - -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" msgstr "" "Les répertoires de configuration d'Icestudio et apio vont être supprimés. " "Voulez-vous continuer?" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" -msgstr "" +msgstr "La toolchain va être restaurée par défaut. Voulez vous continuer ?" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" msgstr "" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" msgstr "" +"Cette opération d'import requière un chemin de projet (path). Vous devez " +"sauvez le projet actuel. Voulez vous continuer ?" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "Toolchain" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" msgstr "La toolchain est installée" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" msgstr "La toolchain n'est pas à jour" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" msgstr "La toolchain n'est pas à jour. Installer, ou mettre à jour svp" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" msgstr "Toolchain supprimée" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" msgstr "Outils" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "Carte inconnue" -#: app/views/menu.html:218 -msgid "Update" +#: app/scripts/app.js:42 +msgid "Untitled" msgstr "" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" +#: app/views/menu.html:235 +msgid "Update" msgstr "" -#: app/views/menu.html:207 +#: app/scripts/services/blocks.service.js:712 +#, fuzzy +msgid "Update the block label" +msgstr "Entrer le titre du bloc" + +#: app/scripts/services/blocks.service.js:639 +#, fuzzy +msgid "Update the port" +msgstr "Entrer les ports d'entrée" + +#: app/views/menu.html:224 msgid "Upload" msgstr "Télécharger" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "Verifier" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" msgstr "Code Verilog exporté" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 app/views/menu.html:306 msgid "Version" msgstr "Version" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "Vue" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "Voir la licence" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" msgstr "Mauvais format de bloc: {{type}}" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +#, fuzzy +msgid "Wrong parameter name {{name}}" +msgstr "Mauvais hostname distant {{name}}" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +#, fuzzy +msgid "Wrong port name {{name}}" +msgstr "Mauvais hostname distant {{name}}" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" msgstr "Mauvais format de projet: {{name}}" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" msgstr "Mauvais hostname distant {{name}}" +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" +msgstr "" + #. And #: app/resources/blocks/labels.js:34 msgid "and" msgstr "Et" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" -msgstr "" +msgstr "retour" #. Bit #: app/resources/blocks/labels.js:4 @@ -592,6 +740,21 @@ msgstr "Combinatoire" msgid "config" msgstr "Configuration" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -618,17 +781,17 @@ msgid "dff_sr" msgstr "D flip-flop" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" msgstr "Construction terminée" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" msgstr "Téléchargement terminé" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" msgstr "Vérification faite" @@ -698,17 +861,17 @@ msgid "sequential" msgstr "Séquentiel" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "Début de la construction ..." #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "Début du téléchargement ..." #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "Début de la verification ..." @@ -727,10 +890,6 @@ msgstr "T flip-flop" msgid "tri_state" msgstr "Tri-state" -#: app/scripts/app.js:38 app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "sans titre" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -741,14 +900,73 @@ msgstr "Xnor" msgid "xor" msgstr "Xor" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" msgstr "" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" msgstr "" +#~ msgid "Info" +#~ msgstr "Info" + +#~ msgid "Clear all" +#~ msgstr "Tout nettoyer" + +#~ msgid "Clone selected" +#~ msgstr "Cloner la selection" + +#~ msgid "Do you want to clear all?" +#~ msgstr "Voulez vous tout nettoyer?" + +#, fuzzy +#~ msgid "Do you want to exit the application?" +#~ msgstr "Voulez vous supprimer le bloc séléctionné?" + +#~ msgid "Do you want to remove the selected block?" +#~ msgstr "Voulez vous supprimer le bloc séléctionné?" + +#, fuzzy +#~ msgid "Enter the project name" +#~ msgstr "Entrer un nom de projet" + +#, fuzzy +#~ msgid "Old project format" +#~ msgstr "Mauvais format de projet: {{name}}" + +#~ msgid "Remove selected" +#~ msgstr "Supprimer la selection" + +#~ msgid "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" +#~ msgstr "Le projet actuel sera supprimé. Continuer de charger le projet?" + +#~ msgid "untitled" +#~ msgstr "sans titre" + +#~ msgid "Block exported as {{name}}" +#~ msgstr "Bloc exporté comme {{name}}" + +#~ msgid "Enter the project's image path" +#~ msgstr "Entrer le chemin image du projet" + +#~ msgid "Export as block" +#~ msgstr "Exporter un bloc" + +#~ msgid "Import block" +#~ msgstr "Importer un bloc" + +#~ msgid "New project" +#~ msgstr "Nouveau projet" + +#~ msgid "Open project" +#~ msgstr "Ouvrir un projet" + +#~ msgid "Templates" +#~ msgstr "Modèles" + #~ msgid "Datasheet not defined" #~ msgstr "Documentation non définie" @@ -758,8 +976,5 @@ msgstr "" #~ msgid "sec" #~ msgstr "Séquentiel" -#~ msgid "Enter the block's label" -#~ msgstr "Entrer le titre du bloc" - #~ msgid "Enter the block's ports" #~ msgstr "Entrer les port du bloc" diff --git a/app/resources/locale/gl_ES/gl_ES.po b/app/resources/locale/gl_ES/gl_ES.po index 5537d7090..3e804f266 100644 --- a/app/resources/locale/gl_ES/gl_ES.po +++ b/app/resources/locale/gl_ES/gl_ES.po @@ -32,427 +32,541 @@ msgstr "2. Interruptor con led" msgid "3_switch_and_gate" msgstr "3. Interruptor con porta and" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" msgstr "" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "" "

    FTDI driver installation instructions

    1. Connect the FPGA " "board
    2. Replace the (Interface 0) driver of the board by " "libusbK
    3. Unplug and reconnect the board
    " msgstr "" -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "" "

    FTDI driver uninstallation instructions

    1. Find the FPGA USB " "Device
    2. Select the board interface and uninstall the driver
    " msgstr "" -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" msgstr "Acerca de Icestudio" -#: app/scripts/controllers/menu.js:421 +#: app/views/menu.html:275 +msgid "Add" +msgstr "" + +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" msgstr "" -#: app/views/menu.html:285 +#: app/views/menu.html:35 +#, fuzzy +msgid "Add as block" +msgstr "Exportar como bloque" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" +msgstr "" + +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "" + +#: app/views/menu.html:331 msgid "Basic" msgstr "Básico" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" msgstr "Euskera" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" -msgstr "Bloque exportado como {{name}}" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +#, fuzzy +msgid "Block updated" +msgstr "Etiqueta actualizada" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" msgstr "Bloque {{name}} importado" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" msgstr "Placa {{name}} non detectada" -#: app/scripts/controllers/menu.js:383 app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" msgstr "Placa {{name}} seleccionada" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "Placas" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "Sintetizar" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" msgstr "" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." msgstr "" -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." msgstr "" -#: app/views/menu.html:113 -msgid "Clear all" -msgstr "Suprimir todo" - -#: app/views/menu.html:107 -msgid "Clone selected" -msgstr "Clonar seleccionado" - -#: app/views/menu.html:288 +#: app/views/menu.html:337 msgid "Code" msgstr "Código" -#: app/views/menu.html:271 +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" +msgstr "" + +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" +msgstr "" + +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "" + +#: app/views/menu.html:185 app/views/menu.html:271 +msgid "Collections" +msgstr "" + +#: app/views/menu.html:317 msgid "Community forum" msgstr "Foro da comunidade" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "" + +#: app/views/menu.html:181 msgid "Datasheet" msgstr "" -#: app/scripts/services/tools.service.js:294 +#: app/views/menu.html:189 +msgid "Default" +msgstr "" + +#: app/scripts/services/tools.service.js:315 msgid "" "Default toolchain not found. Toolchain will be downloaded. This operation " "requires Internet connection. Do you want to continue?" msgstr "" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "" + +#: app/views/menu.html:264 msgid "Disable" msgstr "" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" -msgstr "¿Desexa borrar todo?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" +msgstr "" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" -msgstr "¿Desexa eliminar o bloque seleccionado?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" +msgstr "" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" msgstr "Documentación" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" msgstr "" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" msgstr "" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" msgstr "" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" msgstr "Portos E/S da FPGA duplicados" -#: app/views/menu.html:100 +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "" + +#: app/views/menu.html:88 msgid "Edit" msgstr "Editar" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" msgstr "" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "Inglés" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +#, fuzzy +msgid "Enter the constant blocks" +msgstr "Introduza a etiqueta para o bloque" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" msgstr "" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" msgstr "" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" -msgstr "Introduza a ruta da imaxe do proxecto" - -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" +#: app/scripts/services/blocks.service.js:215 +#, fuzzy +msgid "Enter the parameters" msgstr "Introduza o título do proxecto" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/services/blocks.service.js:57 +#, fuzzy +msgid "Enter the ports" +msgstr "Introduza os portos para o bloque" + +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" msgstr "Enter the remote hostname user@host (experimental)" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" msgstr "" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "Error: {{error}}" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "Exemplos" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." msgstr "Execute remote {{label}} ..." -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "Exportar" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "Exportar como bloque" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." msgstr "" -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." msgstr "" -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." msgstr "" -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" msgstr "Portos E/S da FPGA non definidos" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "" + +#: app/views/menu.html:26 msgid "File" msgstr "Ficheiro" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "" "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" msgstr "O ficheiro {{file}} non existe" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" msgstr "" -#: app/views/menu.html:159 +#: app/views/menu.html:114 +msgid "Fit content" +msgstr "" + +#: app/views/menu.html:160 msgid "French" msgstr "" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" msgstr "GTKWave exportado" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" msgstr "Galego" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "Axuda" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" msgstr "" -#: app/views/menu.html:120 -msgid "Image path" +#: app/scripts/services/utils.service.js:694 +#, fuzzy +msgid "Image" msgstr "Ruta da imaxe" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" msgstr "" -#: app/views/menu.html:73 -msgid "Import block" -msgstr "Importar bloque" - -#: app/views/menu.html:289 -msgid "Info" -msgstr "Info" +#: app/views/menu.html:338 +msgid "Information" +msgstr "" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "Entrada" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" msgstr "" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." msgstr "" -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" msgstr "Instalación completada" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" msgstr "Instalando a toolchain" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" msgstr "Requírese dunha conexión a Internet" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
    block already connected" msgstr "" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
    only Input blocks allowed" msgstr "" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
    Pull up already connected" msgstr "" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" msgstr "" -#: app/scripts/services/graph.service.js:127 -msgid "Invalid multiple input connections" +#: app/scripts/services/graph.service.js:219 +msgid "Invalid connection: {{a}} → {{b}}" msgstr "" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" -msgstr "Etiqueta actualizada" +#: app/scripts/services/graph.service.js:180 +msgid "Invalid multiple input connections" +msgstr "" -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "Idioma" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." msgstr "" -#: app/views/menu.html:27 -msgid "New project" -msgstr "Novo proxecto" +#: app/scripts/services/utils.service.js:678 +msgid "Name" +msgstr "" + +#: app/views/menu.html:29 +msgid "New" +msgstr "" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" msgstr "Novo proxecto {{name}} creado" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "" + +#: app/scripts/controllers/main.js:15 msgid "OK" msgstr "" -#: app/views/menu.html:30 -msgid "Open project" -msgstr "Abrir proxecto" +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" +msgstr "" + +#: app/views/menu.html:32 +msgid "Open" +msgstr "" + +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" +msgstr "" -#: app/scripts/services/common.service.js:156 +#: app/scripts/services/project.service.js:395 msgid "Original file {{file}} does not exist" msgstr "" -#: app/views/menu.html:291 +#: app/views/menu.html:335 msgid "Output" msgstr "Saída" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" msgstr "Ficheiro PCF exportado" -#: app/views/menu.html:117 +#: app/views/menu.html:104 +msgid "Paste" +msgstr "" + +#: app/views/menu.html:118 msgid "Preferences" msgstr "" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:121 +msgid "Project information" +msgstr "" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" msgstr "Proxecto {{name}} cargado" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" msgstr "Proxecto {{name}} gardado" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" msgstr "" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "" + +#: app/views/design.html:4 msgid "Read only" msgstr "Só lectura" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" msgstr "" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" msgstr "" -#: app/views/menu.html:223 +#: app/views/menu.html:240 app/views/menu.html:279 msgid "Remove" msgstr "Eliminar" -#: app/views/menu.html:110 -msgid "Remove selected" -msgstr "Suprimir seleccionado" +#: app/views/menu.html:291 +msgid "Remove all" +msgstr "" -#: app/views/menu.html:228 +#: app/scripts/services/utils.service.js:703 +#, fuzzy +msgid "Reset SVG" +msgstr "Restablecer vista" + +#: app/views/menu.html:245 msgid "Reset default" msgstr "" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" msgstr "Restablecer vista" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "Gardar" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +#, fuzzy +msgid "Save SVG" +msgstr "Gardar como" + +#: app/views/menu.html:60 msgid "Save as" msgstr "Gardar como" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "" + +#: app/views/menu.html:313 msgid "Source code" msgstr "Código fonte" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "Castelán" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." msgstr "Synchronize remote files ..." -#: app/views/menu.html:50 -msgid "Templates" -msgstr "Modelos" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" msgstr "Testbench" -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" msgstr "Testbench exportado" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "" "The current FPGA I/O configuration will be lost. Do you want to change to " "{{name}} board?" @@ -460,112 +574,137 @@ msgstr "" "A configuración actual de E/S da FPGA perderase. ¿Desexa cambiar á placa " "{{name}}?" -#: app/scripts/controllers/menu.js:103 app/scripts/controllers/menu.js:126 -msgid "" -"The current project will be removed. Do you want to continue loading the " -"project?" -msgstr "O proxecto actual perderase. ¿Desexa continuar abrindo o proxecto?" - -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" msgstr "" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" msgstr "" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "" "The toolchain will be updated. This operation requires Internet connection. " "Do you want to continue?" msgstr "" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "" "This import operation requires a project path. You need to save the current " "project. Do you want to continue?" msgstr "" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "Toolchain" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" msgstr "Toolchain instalada" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" msgstr "" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" msgstr "" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" msgstr "Toolchain eliminada" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" msgstr "Ferramentas" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "Placa desconocida" -#: app/views/menu.html:218 +#: app/scripts/app.js:42 +msgid "Untitled" +msgstr "" + +#: app/views/menu.html:235 msgid "Update" msgstr "" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" +#: app/scripts/services/blocks.service.js:712 +#, fuzzy +msgid "Update the block label" +msgstr "Introduza a etiqueta para o bloque" + +#: app/scripts/services/blocks.service.js:639 +msgid "Update the port" msgstr "" -#: app/views/menu.html:207 +#: app/views/menu.html:224 msgid "Upload" msgstr "Cargar" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "Verificar" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" msgstr "Código Verilog exportado" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 app/views/menu.html:306 msgid "Version" msgstr "Versión" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "Ver" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "Ver licenza" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" msgstr "Formato de bloque incorrecto: {{type}}" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +#, fuzzy +msgid "Wrong parameter name {{name}}" +msgstr "Formato de proxecto incorrecto: {{name}}\"" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +#, fuzzy +msgid "Wrong port name {{name}}" +msgstr "Formato de proxecto incorrecto: {{name}}\"" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" msgstr "Formato de proxecto incorrecto: {{name}}\"" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" msgstr "" +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" +msgstr "" + #. And #: app/resources/blocks/labels.js:34 msgid "and" msgstr "And" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" msgstr "" @@ -584,6 +723,21 @@ msgstr "" msgid "config" msgstr "Config" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -610,17 +764,17 @@ msgid "dff_sr" msgstr "Bistable D" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" msgstr "Sintetizado realizado" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" msgstr "Carga realizada" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" msgstr "Verificación realizada" @@ -690,17 +844,17 @@ msgid "sequential" msgstr "" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "Iniciar a sintetizado ..." #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "Iniciar a carga ..." #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "Iniciar a verificación ..." @@ -719,10 +873,6 @@ msgstr "Bistable T" msgid "tri_state" msgstr "Tri-state" -#: app/scripts/app.js:38 app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "Sen título" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -733,22 +883,72 @@ msgstr "Xnor" msgid "xor" msgstr "Xor" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" msgstr "" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" msgstr "" +#~ msgid "Info" +#~ msgstr "Info" + +#~ msgid "Clear all" +#~ msgstr "Suprimir todo" + +#~ msgid "Clone selected" +#~ msgstr "Clonar seleccionado" + +#~ msgid "Do you want to clear all?" +#~ msgstr "¿Desexa borrar todo?" + +#, fuzzy +#~ msgid "Do you want to exit the application?" +#~ msgstr "¿Desexa eliminar o bloque seleccionado?" + +#~ msgid "Do you want to remove the selected block?" +#~ msgstr "¿Desexa eliminar o bloque seleccionado?" + +#, fuzzy +#~ msgid "Enter the project name" +#~ msgstr "Introduza o título do proxecto" + +#, fuzzy +#~ msgid "Old project format" +#~ msgstr "Formato de proxecto incorrecto: {{name}}\"" + +#~ msgid "Remove selected" +#~ msgstr "Suprimir seleccionado" + +#~ msgid "" +#~ "The current project will be removed. Do you want to continue loading the " +#~ "project?" +#~ msgstr "O proxecto actual perderase. ¿Desexa continuar abrindo o proxecto?" + +#~ msgid "untitled" +#~ msgstr "Sen título" + +#~ msgid "Block exported as {{name}}" +#~ msgstr "Bloque exportado como {{name}}" + +#~ msgid "Enter the project's image path" +#~ msgstr "Introduza a ruta da imaxe do proxecto" + +#~ msgid "Import block" +#~ msgstr "Importar bloque" + +#~ msgid "New project" +#~ msgstr "Novo proxecto" + +#~ msgid "Open project" +#~ msgstr "Abrir proxecto" + +#~ msgid "Templates" +#~ msgstr "Modelos" + #~ msgid "comb" #~ msgstr "Comb" #~ msgid "sec" #~ msgstr "Sec" - -#~ msgid "Enter the block's label" -#~ msgstr "Introduza a etiqueta para o bloque" - -#~ msgid "Enter the block's ports" -#~ msgstr "Introduza os portos para o bloque" diff --git a/app/resources/locale/template.pot b/app/resources/locale/template.pot index 5cbd1d24c..f3f41363b 100644 --- a/app/resources/locale/template.pot +++ b/app/resources/locale/template.pot @@ -24,524 +24,655 @@ msgstr "" msgid "3_switch_and_gate" msgstr "" -#: app/scripts/services/utils.service.js:421 -#: app/scripts/services/utils.service.js:496 +#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:532 msgid "Unplug and reconnect the board" msgstr "" -#: app/scripts/services/utils.service.js:487 +#: app/scripts/services/utils.service.js:523 msgid "

    FTDI driver installation instructions

    1. Connect the FPGA board
    2. Replace the (Interface 0) driver of the board by libusbK
    3. Unplug and reconnect the board
    " msgstr "" -#: app/scripts/services/utils.service.js:503 +#: app/scripts/services/utils.service.js:539 msgid "

    FTDI driver uninstallation instructions

    1. Find the FPGA USB Device
    2. Select the board interface and uninstall the driver
    " msgstr "" -#: app/views/menu.html:275 +#: app/views/menu.html:321 msgid "About Icestudio" msgstr "" -#: app/scripts/controllers/menu.js:421 +#: app/views/menu.html:275 +msgid "Add" +msgstr "" + +#: app/scripts/controllers/menu.js:431 msgid "Add a block to start" msgstr "" -#: app/views/menu.html:285 +#: app/views/menu.html:35 +msgid "Add as block" +msgstr "" + +#: app/scripts/services/tools.service.js:590 +msgid "All collections removed" +msgstr "" + +#: app/scripts/controllers/menu.js:455 +msgid "All stored collections will be lost. Do you want to continue?" +msgstr "" + +#: app/scripts/services/utils.service.js:681 +msgid "Author" +msgstr "" + +#: app/views/menu.html:331 msgid "Basic" msgstr "" -#: app/views/menu.html:153 +#: app/views/menu.html:154 msgid "Basque" msgstr "" -#: app/scripts/services/common.service.js:183 -msgid "Block exported as {{name}}" +#: app/scripts/services/blocks.service.js:680 +#: app/scripts/services/blocks.service.js:699 +#: app/scripts/services/blocks.service.js:730 +#: app/scripts/services/blocks.service.js:750 +msgid "Block updated" msgstr "" -#: app/scripts/services/common.service.js:164 +#: app/scripts/services/project.service.js:402 msgid "Block {{name}} imported" msgstr "" -#: app/scripts/services/tools.service.js:205 +#: app/scripts/services/tools.service.js:227 msgid "Board {{name}} not detected" msgstr "" -#: app/scripts/controllers/menu.js:383 -#: app/scripts/controllers/menu.js:390 +#: app/scripts/controllers/menu.js:399 msgid "Board {{name}} selected" msgstr "" -#: app/views/menu.html:186 +#: app/views/menu.html:203 msgid "Boards" msgstr "" -#: app/views/menu.html:204 +#: app/views/menu.html:221 msgid "Build" msgstr "" -#: app/scripts/controllers/main.js:15 +#: app/scripts/controllers/main.js:16 msgid "Cancel" msgstr "" -#: app/scripts/services/tools.service.js:417 +#: app/scripts/services/tools.service.js:438 msgid "Check Internet connection..." msgstr "" -#: app/scripts/services/tools.service.js:425 +#: app/scripts/services/tools.service.js:446 msgid "Check Python..." msgstr "" -#: app/views/menu.html:113 -msgid "Clear all" +#: app/views/menu.html:337 +msgid "Code" msgstr "" -#: app/views/menu.html:107 -msgid "Clone selected" +#: app/scripts/services/tools.service.js:577 +msgid "Collection file {{name}} added" msgstr "" -#: app/views/menu.html:288 -msgid "Code" +#: app/scripts/services/tools.service.js:584 +msgid "Collection {{name}} removed" msgstr "" +#: app/scripts/controllers/menu.js:374 +msgid "Collection {{name}} selected" +msgstr "" + +#: app/views/menu.html:185 #: app/views/menu.html:271 +msgid "Collections" +msgstr "" + +#: app/views/menu.html:317 msgid "Community forum" msgstr "" -#: app/views/menu.html:180 +#: app/views/menu.html:336 +msgid "Constant" +msgstr "" + +#: app/views/menu.html:101 +msgid "Copy" +msgstr "" + +#: app/views/menu.html:98 +msgid "Cut" +msgstr "" + +#: app/views/menu.html:181 msgid "Datasheet" msgstr "" -#: app/scripts/services/tools.service.js:294 +#: app/views/menu.html:189 +msgid "Default" +msgstr "" + +#: app/scripts/services/tools.service.js:315 msgid "Default toolchain not found. Toolchain will be downloaded. This operation requires Internet connection. Do you want to continue?" msgstr "" -#: app/views/menu.html:245 +#: app/scripts/services/utils.service.js:680 +msgid "Description" +msgstr "" + +#: app/views/menu.html:264 msgid "Disable" msgstr "" -#: app/scripts/controllers/menu.js:256 -msgid "Do you want to clear all?" +#: app/scripts/controllers/menu.js:218 +msgid "Do you want to close the application?" msgstr "" -#: app/scripts/controllers/menu.js:269 -msgid "Do you want to remove the selected block?" +#: app/scripts/controllers/menu.js:445 +msgid "Do you want to remove the {{name}} collection?" msgstr "" -#: app/views/menu.html:264 +#: app/views/menu.html:310 msgid "Documentation" msgstr "" -#: app/views/menu.html:238 +#: app/views/menu.html:255 msgid "Drivers" msgstr "" -#: app/scripts/services/utils.service.js:418 -#: app/scripts/services/utils.service.js:481 +#: app/scripts/services/utils.service.js:449 +#: app/scripts/services/utils.service.js:517 msgid "Drivers disabled" msgstr "" -#: app/scripts/services/utils.service.js:415 -#: app/scripts/services/utils.service.js:462 +#: app/scripts/services/utils.service.js:446 +#: app/scripts/services/utils.service.js:498 msgid "Drivers enabled" msgstr "" -#: app/scripts/services/tools.service.js:217 +#: app/scripts/services/tools.service.js:239 msgid "Duplicated FPGA I/O ports" msgstr "" -#: app/views/menu.html:100 +#: app/scripts/services/blocks.service.js:314 +msgid "Duplicated block attributes" +msgstr "" + +#: app/views/menu.html:88 msgid "Edit" msgstr "" -#: app/views/menu.html:241 +#: app/views/menu.html:259 msgid "Enable" msgstr "" -#: app/views/menu.html:135 +#: app/views/menu.html:136 msgid "English" msgstr "" -#: app/scripts/services/graph.service.js:438 -#: app/scripts/services/graph.service.js:496 +#: app/scripts/services/blocks.service.js:126 +msgid "Enter the constant blocks" +msgstr "" + +#: app/scripts/services/blocks.service.js:213 msgid "Enter the input ports" msgstr "" -#: app/scripts/services/graph.service.js:439 -#: app/scripts/services/graph.service.js:536 +#: app/scripts/services/blocks.service.js:214 msgid "Enter the output ports" msgstr "" -#: app/scripts/controllers/menu.js:233 -msgid "Enter the project's image path" +#: app/scripts/services/blocks.service.js:215 +msgid "Enter the parameters" msgstr "" -#: app/scripts/controllers/menu.js:82 -msgid "Enter the project's title" +#: app/scripts/services/blocks.service.js:57 +msgid "Enter the ports" msgstr "" -#: app/scripts/controllers/menu.js:241 +#: app/scripts/controllers/menu.js:314 msgid "Enter the remote hostname user@host (experimental)" msgstr "" -#: app/scripts/services/tools.service.js:317 +#: app/scripts/services/tools.service.js:338 msgid "Error: default toolchain not found in '{{dir}}'" msgstr "" -#: app/scripts/services/utils.service.js:610 +#: app/scripts/services/utils.service.js:813 msgid "Error: {{error}}" msgstr "" -#: app/views/menu.html:33 +#: app/views/menu.html:38 msgid "Examples" msgstr "" -#: app/scripts/services/tools.service.js:175 +#: app/scripts/services/tools.service.js:196 msgid "Execute remote {{label}} ..." msgstr "" -#: app/views/menu.html:80 +#: app/views/menu.html:64 msgid "Export" msgstr "" -#: app/views/menu.html:76 -msgid "Export as block" -msgstr "" - -#: app/scripts/services/tools.service.js:449 +#: app/scripts/services/tools.service.js:470 msgid "Extract default apio files..." msgstr "" -#: app/scripts/services/tools.service.js:459 +#: app/scripts/services/tools.service.js:480 msgid "Extract default apio packages..." msgstr "" -#: app/scripts/services/tools.service.js:437 +#: app/scripts/services/tools.service.js:458 msgid "Extract virtual env files..." msgstr "" -#: app/scripts/services/tools.service.js:211 -#: app/scripts/services/tools.service.js:214 +#: app/scripts/services/tools.service.js:233 +#: app/scripts/services/tools.service.js:236 msgid "FPGA I/O ports not defined" msgstr "" -#: app/views/menu.html:24 +#: app/scripts/services/blocks.service.js:58 +#: app/scripts/services/blocks.service.js:640 +msgid "FPGA pin" +msgstr "" + +#: app/views/menu.html:26 msgid "File" msgstr "" -#: app/scripts/services/common.service.js:125 +#: app/scripts/services/project.service.js:360 msgid "File {{file}} already exists in the project path. Do you want to replace it?" msgstr "" -#: app/scripts/services/tools.service.js:148 +#: app/scripts/services/tools.service.js:172 msgid "File {{file}} does not exist" msgstr "" -#: app/scripts/services/common.service.js:153 +#: app/scripts/services/project.service.js:392 msgid "File {{file}} imported" msgstr "" -#: app/views/menu.html:159 +#: app/views/menu.html:114 +msgid "Fit content" +msgstr "" + +#: app/views/menu.html:160 msgid "French" msgstr "" -#: app/scripts/services/common.service.js:223 +#: app/scripts/controllers/menu.js:197 msgid "GTKWave exported" msgstr "" -#: app/views/menu.html:147 +#: app/views/menu.html:148 msgid "Galician" msgstr "" -#: app/views/menu.html:254 +#: app/views/menu.html:300 msgid "Help" msgstr "" -#: app/scripts/services/utils.service.js:452 +#: app/scripts/services/utils.service.js:487 msgid "Homebrew is required" msgstr "" -#: app/views/menu.html:120 -msgid "Image path" +#: app/scripts/services/utils.service.js:694 +msgid "Image" msgstr "" -#: app/scripts/controllers/menu.js:322 +#: app/scripts/controllers/menu.js:647 msgid "Image {{name}} saved" msgstr "" -#: app/views/menu.html:73 -msgid "Import block" -msgstr "" - -#: app/views/menu.html:289 -msgid "Info" +#: app/views/menu.html:338 +msgid "Information" msgstr "" -#: app/views/menu.html:290 +#: app/views/menu.html:334 msgid "Input" msgstr "" -#: app/views/menu.html:215 +#: app/views/menu.html:232 msgid "Install" msgstr "" -#: app/scripts/services/tools.service.js:454 +#: app/scripts/services/tools.service.js:475 msgid "Install default apio..." msgstr "" -#: app/scripts/services/tools.service.js:503 +#: app/scripts/services/tools.service.js:524 msgid "Installation completed" msgstr "" -#: app/scripts/services/tools.service.js:346 -#: app/scripts/services/tools.service.js:383 +#: app/scripts/services/tools.service.js:367 +#: app/scripts/services/tools.service.js:404 msgid "Installing toolchain" msgstr "" -#: app/scripts/services/tools.service.js:419 -#: app/scripts/services/utils.service.js:455 +#: app/scripts/services/tools.service.js:440 +#: app/scripts/services/utils.service.js:491 msgid "Internet connection required" msgstr "" -#: app/scripts/services/graph.service.js:134 +#: app/scripts/services/graph.service.js:186 msgid "Invalid Pull up connection:
    block already connected" msgstr "" -#: app/scripts/services/graph.service.js:150 +#: app/scripts/services/graph.service.js:200 msgid "Invalid Pull up connection:
    only Input blocks allowed" msgstr "" -#: app/scripts/services/graph.service.js:141 +#: app/scripts/services/graph.service.js:192 msgid "Invalid block connection:
    Pull up already connected" msgstr "" -#: app/scripts/services/graph.service.js:113 +#: app/scripts/services/graph.service.js:151 +#: app/scripts/services/graph.service.js:158 +#: app/scripts/services/graph.service.js:165 msgid "Invalid connection" msgstr "" -#: app/scripts/services/graph.service.js:127 -msgid "Invalid multiple input connections" +#: app/scripts/services/graph.service.js:219 +msgid "Invalid connection: {{a}} → {{b}}" msgstr "" -#: app/scripts/services/graph.service.js:298 -msgid "Label updated" +#: app/scripts/services/graph.service.js:180 +msgid "Invalid multiple input connections" msgstr "" -#: app/views/menu.html:131 +#: app/views/menu.html:132 msgid "Language" msgstr "" -#: app/scripts/services/tools.service.js:442 +#: app/scripts/services/blocks.service.js:127 +#: app/scripts/services/blocks.service.js:713 +msgid "Local parameter" +msgstr "" + +#: app/scripts/services/tools.service.js:463 msgid "Make virtual env..." msgstr "" -#: app/views/menu.html:27 -msgid "New project" +#: app/scripts/services/utils.service.js:678 +msgid "Name" +msgstr "" + +#: app/views/menu.html:29 +msgid "New" msgstr "" -#: app/scripts/services/common.service.js:36 +#: app/scripts/services/project.service.js:85 msgid "New project {{name}} created" msgstr "" -#: app/scripts/controllers/main.js:14 +#: app/scripts/controllers/menu.js:463 +msgid "No collections stored" +msgstr "" + +#: app/scripts/controllers/main.js:15 msgid "OK" msgstr "" -#: app/views/menu.html:30 -msgid "Open project" +#: app/scripts/services/project.service.js:101 +#: app/scripts/services/project.service.js:308 +msgid "Old project format {{version}}" +msgstr "" + +#: app/views/menu.html:32 +msgid "Open" +msgstr "" + +#: app/scripts/services/utils.service.js:701 +msgid "Open SVG" msgstr "" -#: app/scripts/services/common.service.js:156 +#: app/scripts/services/project.service.js:395 msgid "Original file {{file}} does not exist" msgstr "" -#: app/views/menu.html:291 +#: app/views/menu.html:335 msgid "Output" msgstr "" -#: app/scripts/services/common.service.js:203 +#: app/scripts/controllers/menu.js:179 msgid "PCF file exported" msgstr "" -#: app/views/menu.html:117 +#: app/views/menu.html:104 +msgid "Paste" +msgstr "" + +#: app/views/menu.html:118 msgid "Preferences" msgstr "" -#: app/scripts/services/common.service.js:55 +#: app/views/menu.html:121 +msgid "Project information" +msgstr "" + +#: app/scripts/services/project.service.js:108 msgid "Project {{name}} loaded" msgstr "" -#: app/scripts/services/common.service.js:68 +#: app/scripts/services/project.service.js:280 msgid "Project {{name}} saved" msgstr "" -#: app/scripts/services/tools.service.js:430 +#: app/scripts/services/tools.service.js:451 msgid "Python 2.7 is required" msgstr "" -#: app/views/project.html:3 +#: app/views/menu.html:82 +msgid "Quit" +msgstr "" + +#: app/views/design.html:4 msgid "Read only" msgstr "" -#: app/scripts/services/tools.service.js:243 +#: app/views/menu.html:94 +msgid "Redo" +msgstr "" + +#: app/scripts/services/tools.service.js:264 msgid "Remote host {{name}} not connected" msgstr "" -#: app/views/menu.html:125 +#: app/views/menu.html:126 msgid "Remote hostname" msgstr "" -#: app/views/menu.html:223 +#: app/views/menu.html:240 +#: app/views/menu.html:279 msgid "Remove" msgstr "" -#: app/views/menu.html:110 -msgid "Remove selected" +#: app/views/menu.html:291 +msgid "Remove all" msgstr "" -#: app/views/menu.html:228 +#: app/scripts/services/utils.service.js:703 +msgid "Reset SVG" +msgstr "" + +#: app/views/menu.html:245 msgid "Reset default" msgstr "" -#: app/views/menu.html:103 +#: app/views/menu.html:111 msgid "Reset view" msgstr "" -#: app/views/menu.html:66 +#: app/views/menu.html:57 msgid "Save" msgstr "" -#: app/views/menu.html:69 +#: app/scripts/services/utils.service.js:702 +msgid "Save SVG" +msgstr "" + +#: app/views/menu.html:60 msgid "Save as" msgstr "" -#: app/views/menu.html:267 +#: app/views/menu.html:107 +msgid "Select all" +msgstr "" + +#: app/views/menu.html:313 msgid "Source code" msgstr "" -#: app/views/menu.html:141 +#: app/views/menu.html:142 msgid "Spanish" msgstr "" -#: app/scripts/services/tools.service.js:164 +#: app/scripts/services/tools.service.js:185 msgid "Synchronize remote files ..." msgstr "" -#: app/views/menu.html:50 -msgid "Templates" -msgstr "" - -#: app/views/menu.html:89 +#: app/views/menu.html:73 msgid "Testbench" msgstr "" -#: app/scripts/services/common.service.js:213 +#: app/scripts/controllers/menu.js:188 msgid "Testbench exported" msgstr "" -#: app/scripts/controllers/menu.js:379 +#: app/scripts/controllers/menu.js:388 msgid "The current FPGA I/O configuration will be lost. Do you want to change to {{name}} board?" msgstr "" -#: app/scripts/controllers/menu.js:103 -#: app/scripts/controllers/menu.js:126 -msgid "The current project will be removed. Do you want to continue loading the project?" -msgstr "" - -#: app/scripts/services/tools.service.js:322 +#: app/scripts/services/tools.service.js:343 msgid "The toolchain will be removed. Do you want to continue?" msgstr "" -#: app/scripts/services/tools.service.js:310 +#: app/scripts/services/tools.service.js:331 msgid "The toolchain will be restored to default. Do you want to continue?" msgstr "" -#: app/scripts/services/tools.service.js:302 +#: app/scripts/services/tools.service.js:323 msgid "The toolchain will be updated. This operation requires Internet connection. Do you want to continue?" msgstr "" -#: app/scripts/services/common.service.js:95 +#: app/scripts/services/project.service.js:329 msgid "This import operation requires a project path. You need to save the current project. Do you want to continue?" msgstr "" -#: app/views/menu.html:211 +#: app/views/menu.html:228 msgid "Toolchain" msgstr "" -#: app/scripts/services/tools.service.js:504 +#: app/scripts/services/tools.service.js:525 msgid "Toolchain installed" msgstr "" -#: app/scripts/services/tools.service.js:508 +#: app/scripts/services/tools.service.js:529 msgid "Toolchain not installed" msgstr "" -#: app/scripts/services/tools.service.js:79 -#: app/scripts/services/utils.service.js:493 -#: app/scripts/services/utils.service.js:509 +#: app/scripts/services/tools.service.js:100 +#: app/scripts/services/utils.service.js:529 +#: app/scripts/services/utils.service.js:545 msgid "Toolchain not installed. Please, install the toolchain" msgstr "" -#: app/scripts/services/tools.service.js:326 +#: app/scripts/services/tools.service.js:347 msgid "Toolchain removed" msgstr "" -#: app/views/menu.html:198 +#: app/views/menu.html:215 msgid "Tools" msgstr "" -#: app/scripts/services/tools.service.js:208 +#: app/views/menu.html:91 +msgid "Undo" +msgstr "" + +#: app/scripts/services/tools.service.js:230 msgid "Unknown board" msgstr "" -#: app/views/menu.html:218 +#: app/scripts/app.js:42 +msgid "Untitled" +msgstr "" + +#: app/views/menu.html:235 msgid "Update" msgstr "" -#: app/scripts/services/graph.service.js:292 -msgid "Update the port label" +#: app/scripts/services/blocks.service.js:712 +msgid "Update the block label" msgstr "" -#: app/views/menu.html:207 +#: app/scripts/services/blocks.service.js:639 +msgid "Update the port" +msgstr "" + +#: app/views/menu.html:224 msgid "Upload" msgstr "" -#: app/views/menu.html:201 +#: app/views/menu.html:218 msgid "Verify" msgstr "" -#: app/scripts/services/common.service.js:193 +#: app/scripts/controllers/menu.js:170 msgid "Verilog code exported" msgstr "" -#: app/views/menu.html:260 +#: app/scripts/services/utils.service.js:679 +#: app/views/menu.html:306 msgid "Version" msgstr "" -#: app/views/menu.html:171 +#: app/views/menu.html:172 msgid "View" msgstr "" -#: app/views/menu.html:257 +#: app/views/menu.html:303 msgid "View license" msgstr "" -#: app/scripts/services/graph.service.js:593 +#: app/scripts/services/blocks.service.js:347 msgid "Wrong block format: {{type}}" msgstr "" -#: app/scripts/services/common.service.js:58 +#: app/scripts/services/blocks.service.js:146 +#: app/scripts/services/blocks.service.js:263 +msgid "Wrong parameter name {{name}}" +msgstr "" + +#: app/scripts/services/blocks.service.js:233 +#: app/scripts/services/blocks.service.js:248 +#: app/scripts/services/blocks.service.js:704 +#: app/scripts/services/blocks.service.js:77 +msgid "Wrong port name {{name}}" +msgstr "" + +#: app/scripts/services/project.service.js:116 msgid "Wrong project format: {{name}}" msgstr "" -#: app/scripts/services/tools.service.js:240 +#: app/scripts/services/tools.service.js:261 msgid "Wrong remote hostname {{name}}" msgstr "" +#: app/scripts/controllers/menu.js:219 +msgid "Your changes will be lost if you don’t save them" +msgstr "" + #. And #: app/resources/blocks/labels.js:34 msgid "and" msgstr "" -#: app/views/project.html:4 +#: app/views/design.html:5 msgid "back" msgstr "" @@ -560,6 +691,21 @@ msgstr "" msgid "config" msgstr "" +#. contadorAsc +#: app/resources/examples/labels.js:12 +msgid "contadorAsc" +msgstr "" + +#. contadorDes +#: app/resources/examples/labels.js:14 +msgid "contadorDes" +msgstr "" + +#. Debouncer +#: app/resources/blocks/labels.js:58 +msgid "debouncer" +msgstr "" + #. Demux 1:2 #: app/resources/blocks/labels.js:18 msgid "demux_1_2" @@ -586,17 +732,17 @@ msgid "dff_sr" msgstr "" #. Build done -#: app/scripts/services/tools.service.js:255 +#: app/scripts/services/tools.service.js:276 msgid "done_build" msgstr "" #. Upload done -#: app/scripts/services/tools.service.js:257 +#: app/scripts/services/tools.service.js:278 msgid "done_upload" msgstr "" #. Verification done -#: app/scripts/services/tools.service.js:253 +#: app/scripts/services/tools.service.js:274 msgid "done_verify" msgstr "" @@ -666,17 +812,17 @@ msgid "sequential" msgstr "" #. Start building ... -#: app/scripts/services/tools.service.js:45 +#: app/scripts/services/tools.service.js:64 msgid "start_build" msgstr "" #. Start uploading ... -#: app/scripts/services/tools.service.js:47 +#: app/scripts/services/tools.service.js:66 msgid "start_upload" msgstr "" #. Start verification ... -#: app/scripts/services/tools.service.js:43 +#: app/scripts/services/tools.service.js:62 msgid "start_verify" msgstr "" @@ -695,11 +841,6 @@ msgstr "" msgid "tri_state" msgstr "" -#: app/scripts/app.js:38 -#: app/scripts/controllers/menu.js:83 -msgid "untitled" -msgstr "" - #. Xnor #: app/resources/blocks/labels.js:44 msgid "xnor" @@ -710,10 +851,10 @@ msgstr "" msgid "xor" msgstr "" -#: app/scripts/controllers/menu.js:370 +#: app/scripts/controllers/menu.js:366 msgid "{{board}} datasheet not defined" msgstr "" -#: app/scripts/controllers/menu.js:360 +#: app/scripts/controllers/menu.js:356 msgid "{{board}} pinout not defined" msgstr "" diff --git a/app/resources/templates/bit/0.ice b/app/resources/templates/bit/0.ice deleted file mode 100644 index 6eb2caab2..000000000 --- a/app/resources/templates/bit/0.ice +++ /dev/null @@ -1,60 +0,0 @@ -{ - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 0\n\nassign v = 1'b0;", - "ports": { - "in": [], - "out": [ - "v" - ] - } - }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 608, - "y": 192 - } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/templates/bit/1.ice b/app/resources/templates/bit/1.ice deleted file mode 100644 index 1c6f8e96b..000000000 --- a/app/resources/templates/bit/1.ice +++ /dev/null @@ -1,60 +0,0 @@ -{ - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "type": "basic.code", - "data": { - "code": "// Bit 1\n\nassign v = 1'b1;", - "ports": { - "in": [], - "out": [ - "v" - ] - } - }, - "position": { - "x": 96, - "y": 96 - } - }, - { - "id": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "type": "basic.output", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 608, - "y": 192 - } - } - ], - "wires": [ - { - "source": { - "block": "b959fb96-ac67-4aea-90b3-ed35a4c17bf5", - "port": "v" - }, - "target": { - "block": "19c8f68d-5022-487f-9ab0-f0a3cd58bead", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/templates/logic/and.ice b/app/resources/templates/logic/and.ice deleted file mode 100644 index 2d7efe070..000000000 --- a/app/resources/templates/logic/and.ice +++ /dev/null @@ -1,113 +0,0 @@ -{ - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// AND logic gate\n\nassign c = a & b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/templates/logic/not.ice b/app/resources/templates/logic/not.ice deleted file mode 100644 index 14945890e..000000000 --- a/app/resources/templates/logic/not.ice +++ /dev/null @@ -1,87 +0,0 @@ -{ - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 64, - "y": 144 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "type": "basic.code", - "data": { - "code": "// NOT logic gate\n\nassign c = ~ a;", - "ports": { - "in": [ - "a" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "port": "a" - } - }, - { - "source": { - "block": "5365ed8c-e5db-4445-938f-8d689830ea5c", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/templates/logic/or.ice b/app/resources/templates/logic/or.ice deleted file mode 100644 index dc45f5f5b..000000000 --- a/app/resources/templates/logic/or.ice +++ /dev/null @@ -1,113 +0,0 @@ -{ - "board": "icezum", - "graph": { - "blocks": [ - { - "id": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "type": "basic.input", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 64, - "y": 80 - } - }, - { - "id": "97b51945-d716-4b6c-9db9-970d08541249", - "type": "basic.input", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 64, - "y": 208 - } - }, - { - "id": "664caf9e-5f40-4df4-800a-b626af702e62", - "type": "basic.output", - "data": { - "label": "", - "pin": { - "name": "", - "value": "" - } - }, - "position": { - "x": 752, - "y": 144 - } - }, - { - "id": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "type": "basic.code", - "data": { - "code": "// OR logic gate\n\nassign c = a | b;", - "ports": { - "in": [ - "a", - "b" - ], - "out": [ - "c" - ] - } - }, - "position": { - "x": 256, - "y": 48 - } - } - ], - "wires": [ - { - "source": { - "block": "18c2ebc7-5152-439c-9b3f-851c59bac834", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "a" - } - }, - { - "source": { - "block": "97b51945-d716-4b6c-9db9-970d08541249", - "port": "out" - }, - "target": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "b" - } - }, - { - "source": { - "block": "00925b04-5004-4307-a737-fa4e97c8b6ab", - "port": "c" - }, - "target": { - "block": "664caf9e-5f40-4df4-800a-b626af702e62", - "port": "in" - } - } - ] - }, - "deps": {}, - "image": "", - "state": { - "pan": { - "x": 0, - "y": 0 - }, - "zoom": 1 - } -} \ No newline at end of file diff --git a/app/resources/viewers/svg/pinout.html b/app/resources/viewers/svg/pinout.html index a06a73cd9..6ac3e7b6b 100644 --- a/app/resources/viewers/svg/pinout.html +++ b/app/resources/viewers/svg/pinout.html @@ -27,7 +27,7 @@ minZoom: 1, maxZoom: 5 }); - }, 100); + }, 300); }; window.onload = function() { loadEmbedSVG(); diff --git a/app/scripts/app.js b/app/scripts/app.js index 8aa6d8414..5cb83d51b 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -5,9 +5,9 @@ angular 'ngRoute', 'ui.bootstrap', 'gettext' - ]).config(['$routeProvider', + ]) + .config(['$routeProvider', function($routeProvider) { - $routeProvider .when('/', { templateUrl: 'views/main.html', @@ -18,9 +18,13 @@ angular }); } ]) - .run(function(profile, common, utils, nodeLangInfo, gettextCatalog) { + .run(function(profile, + project, + utils, + gettextCatalog, + nodeLangInfo) { // Load language - profile.load(function(data) { + profile.load(function() { var lang = profile.data.language; if (lang) { utils.setLocale(lang); @@ -35,6 +39,6 @@ angular } }); setTimeout(function() { - common.updateProjectName(gettextCatalog.getString('untitled')); + project.updateTitle(gettextCatalog.getString('Untitled')); }, 100); }); diff --git a/app/scripts/controllers/design.js b/app/scripts/controllers/design.js new file mode 100644 index 000000000..2d4db5053 --- /dev/null +++ b/app/scripts/controllers/design.js @@ -0,0 +1,57 @@ +'use strict'; + +angular.module('icestudio') + .controller('DesignCtrl', function ($rootScope, + $scope, + project, + boards, + graph, + utils) { + + $scope.boards = boards; + $scope.graph = graph; + + // Intialization + + graph.createPaper($('#paper')); + + // Breadcrumbs + + $scope.breadcrumbsNavitate = function(selectedItem) { + var item; + do { + graph.breadcrumbs.pop(); + item = graph.breadcrumbs.slice(-1)[0]; + } + while (selectedItem !== item); + loadSelectedGraph(); + }; + + $scope.breadcrumbsBack = function() { + graph.breadcrumbs.pop(); + loadSelectedGraph(); + }; + + function loadSelectedGraph() { + var n = graph.breadcrumbs.length; + if (n === 1) { + var design = project.get('design'); + graph.loadDesign(design, false); + } + else { + var dependencies = project.getAllDependencies(); + var type = graph.breadcrumbs[n-1].type; + graph.loadDesign(dependencies[type].design, true); + } + } + + $rootScope.$on('updateProject', function(event, callback) { + project.update(callback, false); + }); + + $rootScope.$on('breadcrumbsBack', function(/*event*/) { + $scope.breadcrumbsBack(); + utils.rootScopeSafeApply(); + }); + + }); diff --git a/app/scripts/controllers/main.js b/app/scripts/controllers/main.js index d8d5f7018..69deec911 100644 --- a/app/scripts/controllers/main.js +++ b/app/scripts/controllers/main.js @@ -1,7 +1,8 @@ 'use strict'; angular.module('icestudio') - .controller('MainCtrl', function($scope, gettextCatalog) { + .controller('MainCtrl', function($scope, + gettextCatalog) { alertify.defaults.movable = false; alertify.defaults.closable = false; diff --git a/app/scripts/controllers/menu.js b/app/scripts/controllers/menu.js index 970320283..6aaba2cea 100644 --- a/app/scripts/controllers/menu.js +++ b/app/scripts/controllers/menu.js @@ -4,44 +4,42 @@ angular.module('icestudio') .controller('MenuCtrl', function ($rootScope, $scope, $timeout, - nodeLangInfo, - nodeFs, - nodePath, - common, - graph, - tools, boards, - resources, profile, - gui, + project, + resources, + graph, + tools, utils, gettextCatalog, - _package) { + gui, + _package, + nodeFs, + nodePath) { - // Initialize scope + //-- Initialize scope - $scope.common = common; $scope.boards = boards; $scope.profile = profile; - - $scope.examples = resources.getExamples(); - $scope.templates = resources.getTemplates(); - $scope.currentBoards = boards.getBoards(); - $scope.menuBlocks = resources.getMenuBlocks(); + $scope.project = project; + $scope.tools = tools; + $scope.resources = resources; $scope.version = _package.version; $scope.toolchain = tools.toolchain; $scope.workingdir = ''; $scope.snapshotdir = ''; - $scope.currentProjectPath = ''; - // Configure window + var zeroProject = true; // New project without changes + + // Initialize selected collection + updateSelectedCollection(); + + // Window events var win = gui.Window.get(); win.on('close', function() { - this.hide(); - profile.save(); - this.close(true); + exit(); }); // Darwin fix for shortcuts @@ -51,285 +49,290 @@ angular.module('icestudio') win.menu = mb; } - function pathSync() { - if ($scope.currentProjectPath) { - var projectPath = utils.dirname($scope.currentProjectPath); - tools.setProjectPath(projectPath); - common.setProjectPath(projectPath); - } - } - - // Menu - + // Menu timer var timer; // mouseover event $scope.showMenu = function (menu) { $timeout.cancel(timer); - $scope.status[menu] = true; + if (!graph.mousedown) { + $scope.status[menu] = true; + } }; // mouseleave event $scope.hideMenu = function (menu) { timer = $timeout(function () { - $scope.status[menu] = false; - }, 500); + $scope.status[menu] = false; + }, 700); }; - // File - - $scope.newProject = function() { - alertify.prompt(gettextCatalog.getString('Enter the project\'s title'), - gettextCatalog.getString('untitled'), - function(evt, name) { - if (name) { - common.newProject(name); - $scope.currentProjectPath = ''; - pathSync(); - } - }); + // Load app arguments + setTimeout(function() { + for (var i in gui.App.argv) { + processArg(gui.App.argv[i]); + } + }, 0); + + function processArg(arg) { + if (nodeFs.existsSync(arg)) { + // Open filepath + var filepath = arg; + var emptyPath = filepath.startsWith('resources'); // it is an example + if (!emptyPath) { + updateWorkingdir(filepath); + } + project.open(filepath, emptyPath); + zeroProject = false; + } + else { + // Move window + var data = arg.split('x'); + var offset = { + x: parseInt(data[0]), + y: parseInt(data[1]) + }; + win.moveTo(offset.x, offset.y); + } } - $scope.openProject = function() { - setTimeout(function() { - var ctrl = angular.element('#input-open-project'); - ctrl.on('change', function(event) { - var file = event.target.files[0]; - event.target.files.clear(); - if (file) { - if (file.path.endsWith('.ice')) { - $scope.workingdir = utils.dirname(file.path) + utils.sep; - if (!graph.isEmpty()) { - alertify.confirm(gettextCatalog.getString('The current project will be removed. Do you want to continue loading the project?'), - function() { - common.openProject(file.path); - $scope.currentProjectPath = file.path; - pathSync(); - }); - } - else { - common.openProject(file.path); - $scope.currentProjectPath = file.path; - pathSync(); - } - } - } - }); - ctrl.click(); - }, 0); - } + //-- File - $scope.openStoredProject = function(name, project) { - if (project) { - if (!graph.isEmpty()) { - alertify.confirm(gettextCatalog.getString('The current project will be removed. Do you want to continue loading the project?'), - function() { - common.loadProject(name, project); - $scope.currentProjectPath = ''; - pathSync(); - }); + $scope.newProject = function() { + utils.newWindow(); + }; + + $scope.openProject = function() { + utils.openDialog('#input-open-project', '.ice', function(filepath) { + if (zeroProject) { + // If this is the first action, open + // the projec in the same window + updateWorkingdir(filepath); + project.open(filepath); + zeroProject = false; } - else { - common.loadProject(name, project); - $scope.currentProjectPath = ''; - pathSync(); + else if (project.changed || !equalWorkingFilepath(filepath)) { + // If this is not the first action, and + // the file path is different, open + // the project in a new window + utils.newWindow(filepath); } + }); + }; + + $scope.openExample = function(filepath) { + if (zeroProject) { + // If this is the first action, open + // the projec in the same window + project.open(filepath, true); + zeroProject = false; } - } + else { + // If this is not the first action, and + // the file path is different, open + // the project in a new window + utils.newWindow(filepath); + } + }; $scope.saveProject = function() { - var filepath = $scope.currentProjectPath; + var filepath = project.path; if (filepath) { - common.saveProject(filepath); + project.save(filepath); + resetChanged(); } else { $scope.saveProjectAs(); } - } + }; $scope.saveProjectAs = function(localCallback) { utils.saveDialog('#input-save-project', '.ice', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.saveProject(filepath); - $scope.currentProjectPath = filepath; - pathSync(); - if (localCallback) + updateWorkingdir(filepath); + project.save(filepath); + resetChanged(); + if (localCallback) { localCallback(); + } }); - } + }; $rootScope.$on('saveProjectAs', function(event, callback) { $scope.saveProjectAs(callback); - }) - - $scope.importBlock = function() { - setTimeout(function() { - var ctrl = angular.element('#input-import-block'); - ctrl.on('change', function(event) { - var files = JSON.parse(JSON.stringify(event.target.files)); - for (var i in files) { - if (files[i] && - files[i].path && - files[i].path.endsWith('.iceb')) { - common.importBlock(files[i].path); - } - } - event.target.files.clear(); - }); - ctrl.click(); - }, 0); - } + }); - $scope.exportAsBlock = function() { - checkGraph(function() { - utils.saveDialog('#input-export-block', '.iceb', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.exportAsBlock(filepath); - }); + $scope.addAsBlock = function() { + utils.openDialog('#input-add-as-block', '.ice', function(filepaths) { + filepaths = filepaths.split(';'); + for (var i in filepaths) { + project.addAsBlock(filepaths[i]); + } }); - } + }; $scope.exportVerilog = function() { checkGraph(function() { utils.saveDialog('#input-export-verilog', '.v', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.exportVerilog(filepath); + project.export('verilog', filepath, gettextCatalog.getString('Verilog code exported')); + updateWorkingdir(filepath); }); }); - } + }; $scope.exportPCF = function() { checkGraph(function() { utils.saveDialog('#input-export-pcf', '.pcf', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.exportPCF(filepath); + project.export('pcf', filepath, gettextCatalog.getString('PCF file exported')); + updateWorkingdir(filepath); }); }); - } + }; $scope.exportTestbench = function() { checkGraph(function() { utils.saveDialog('#input-export-testbench', '.v', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.exportTestbench(filepath); + project.export('testbench', filepath, gettextCatalog.getString('Testbench exported')); + updateWorkingdir(filepath); }); }); - } + }; $scope.exportGTKwave = function() { checkGraph(function() { utils.saveDialog('#input-export-gtkwave', '.gtkw', function(filepath) { - $scope.workingdir = utils.dirname(filepath) + utils.sep; - common.exportGTKWave(filepath); + project.export('gtkwave', filepath, gettextCatalog.getString('GTKWave exported')); + updateWorkingdir(filepath); }); }); - } - - // Edit + }; - $scope.setImagePath = function() { - var current = common.project.image; - alertify.prompt(gettextCatalog.getString('Enter the project\'s image path'), (current) ? current : '', - function(evt, imagePath) { - common.setImagePath(imagePath); - }); + function updateWorkingdir(filepath) { + $scope.workingdir = utils.dirname(filepath) + utils.sep; } - $scope.setRemoteHostname = function() { - var current = profile.data.remoteHostname; - alertify.prompt(gettextCatalog.getString('Enter the remote hostname user@host (experimental)'), (current) ? current : '', - function(evt, remoteHostname) { - profile.data.remoteHostname = remoteHostname; - }); + function equalWorkingFilepath(filepath) { + return $scope.workingdir + project.name + '.ice' === filepath; } - $scope.selectLanguage = function(language) { - if (profile.data.language != language) { - profile.data.language = language; - utils.setLocale(language); + $scope.quit = function() { + exit(); + }; + + function exit() { + if (project.changed) { + alertify.confirm( + '' + gettextCatalog.getString('Do you want to close the application?') + '
    ' + + gettextCatalog.getString('Your changes will be lost if you don’t save them'), + function() { + _exit(); + }); + } + else { + _exit(); + } + function _exit() { + //win.hide(); + profile.save(); + win.close(true); } } - $scope.clearGraph = function() { - checkGraph(function() { - alertify.confirm(gettextCatalog.getString('Do you want to clear all?'), - function() { - common.clearProject(); - }); - }); - } - $scope.cloneSelected = function() { - common.cloneSelected(); - } + //-- Edit + + $scope.undoGraph = function() { + graph.undo(); + }; + + $scope.redoGraph = function() { + graph.redo(); + }; - $scope.removeSelected = function() { + $scope.cutSelected = function() { if (graph.hasSelection()) { - alertify.confirm(gettextCatalog.getString('Do you want to remove the selected block?'), - function() { - common.removeSelected(); - }); + graph.cutSelected(); } - } + }; - // Key events + $scope.copySelected = function() { + if (graph.hasSelection()) { + graph.copySelected(); + } + }; - var promptShown = false; + var paste = true; - alertify.prompt().set({ - onshow: function() { - promptShown = true; - }, - onclose: function() { - promptShown = false; + $scope.pasteSelected = function() { + if (paste) { + paste = false; + graph.pasteSelected(); + setTimeout(function() { + paste = true; + }, 250); } - }); + }; - $(document).on('keydown', function(event) { - if (graph.isEnabled() && !promptShown) { - if (event.keyCode == 46 || // Supr - (event.keyCode == 88 && event.ctrlKey)) { // Ctrl + x - $scope.removeSelected(); - } - else if (event.keyCode == 67 && event.ctrlKey) { // Ctrl + c - $scope.cloneSelected(); - } - if (process.platform === 'darwin') { - if (event.keyCode == 8) { // Back - $scope.removeSelected(); - } - } - } - if (event.keyCode == 80 && event.ctrlKey) { // Ctrl + p - // Print and save a window snapshot - takeSnapshot(); - } - }); + $scope.selectAll = function() { + checkGraph(function() { + graph.selectAll(); + }); + }; - function takeSnapshot() { - win.capturePage(function(img) { - var base64Data = img.replace(/^data:image\/(png|jpg|jpeg);base64,/, ""); - saveSnapshot(base64Data); - }, 'png'); + function removeSelected() { + if (graph.hasSelection()) { + //alertify.confirm(gettextCatalog.getString('Do you want to remove the selected block?'), + //function() { + project.removeSelected(); + //}); + } } - function saveSnapshot(base64Data) { - utils.saveDialog('#input-save-snapshot', '.png', function(filepath) { - nodeFs.writeFile(filepath, base64Data, 'base64', function (err) { - $scope.snapshotdir = utils.dirname(filepath) + utils.sep; - $scope.$apply(); - if (!err) alertify.success(gettextCatalog.getString('Image {{name}} saved', { name: utils.bold(utils.basename(filepath)) })); - else throw err; + $scope.resetView = function() { + graph.resetView(); + }; + + $scope.fitContent = function () { + graph.fitContent(); + }; + + $scope.setProjectInformation = function() { + var p = project.get('package'); + var values = [ + p.name, + p.version, + p.description, + p.author, + p.image + ]; + utils.projectinfoprompt(values, function(evt, values) { + project.set('package', { + name: values[0], + version: values[1], + description: values[2], + author: values[3], + image: values[4] }); }); - } + }; - // View + $scope.setRemoteHostname = function() { + var current = profile.data.remoteHostname; + alertify.prompt(gettextCatalog.getString('Enter the remote hostname user@host (experimental)'), (current) ? current : '', + function(evt, remoteHostname) { + profile.data.remoteHostname = remoteHostname; + }); + }; - $scope.resetState = function() { - graph.resetState(); - } + $scope.selectLanguage = function(language) { + if (profile.data.language !== language) { + profile.data.language = language; + utils.setLocale(language); + } + }; + + + //-- View $scope.showPCF = function() { gui.Window.open('resources/viewers/plain/pcf.html?board=' + boards.selectedBoard.name, { @@ -341,7 +344,7 @@ angular.module('icestudio') height: 700, icon: 'resources/images/icestudio-logo.png' }); - } + }; $scope.showPinout = function() { var board = boards.selectedBoard; @@ -359,7 +362,7 @@ angular.module('icestudio') else { alertify.notify(gettextCatalog.getString('{{board}} pinout not defined', { board: utils.bold(board.info.label) }), 'warning', 5); } - } + }; $scope.showDatasheet = function() { var board = boards.selectedBoard; @@ -369,93 +372,112 @@ angular.module('icestudio') else { alertify.notify(gettextCatalog.getString('{{board}} datasheet not defined', { board: utils.bold(board.info.label) }), 'error', 5); } + }; + + $scope.selectCollection = function(collection) { + if (resources.selectedCollection.name !== collection.name) { + var name = resources.selectCollection(collection.name); + profile.data.collection = name; + alertify.success(gettextCatalog.getString('Collection {{name}} selected', { name: utils.bold(name) })); + } + }; + + function updateSelectedCollection() { + profile.data.collection = resources.selectCollection(profile.data.collection); } - // Boards + + //-- Boards $scope.selectBoard = function(board) { - if (boards.selectedBoard.name != board.name) { + if (boards.selectedBoard.name !== board.name) { if (!graph.isEmpty()) { alertify.confirm(gettextCatalog.getString('The current FPGA I/O configuration will be lost. Do you want to change to {{name}} board?', { name: utils.bold(board.info.label) }), function() { - boards.selectBoard(board.name); - graph.resetIOChoices(); - alertify.success(gettextCatalog.getString('Board {{name}} selected', { name: utils.bold(board.info.label) })); - $rootScope.$apply(); + _boardSelected(); }); } else { - boards.selectBoard(board.name); - graph.resetIOChoices(); - alertify.success(gettextCatalog.getString('Board {{name}} selected', { name: utils.bold(board.info.label) })); + _boardSelected(); } } - } + function _boardSelected() { + graph.selectBoard(board.name); + alertify.success(gettextCatalog.getString('Board {{name}} selected', { name: utils.bold(board.info.label) })); + } + }; + - // Tools + //-- Tools $scope.verifyCode = function() { checkGraph(function() { tools.verifyCode(); }); - } + }; $scope.buildCode = function() { checkGraph(function() { tools.buildCode(); }); - } + }; $scope.uploadCode = function() { checkGraph(function() { tools.uploadCode(); }); - } + }; function checkGraph(callback) { if (!graph.isEmpty()) { - if (callback) + if (callback) { callback(); + } } else { alertify.notify(gettextCatalog.getString('Add a block to start'), 'warning', 5); } } - $scope.installToolchain = function() { - tools.installToolchain(); - } - - $scope.updateToolchain = function() { - tools.updateToolchain(); - } - - $scope.removeToolchain = function() { - tools.removeToolchain(); - } + $scope.addCollection = function() { + utils.openDialog('#input-add-collection', '.zip', function(filepaths) { + filepaths = filepaths.split(';'); + for (var i in filepaths) { + tools.addCollection(filepaths[i]); + } + }); + }; - $scope.resetToolchain = function() { - tools.resetToolchain(); - } + $scope.removeCollection = function(collection) { + alertify.confirm(gettextCatalog.getString('Do you want to remove the {{name}} collection?', { name: utils.bold(collection.name) }), + function() { + tools.removeCollection(collection); + updateSelectedCollection(); + utils.rootScopeSafeApply(); + }); + }; - $scope.enableDrivers = function() { - tools.enableDrivers(); - } + $scope.removeAllCollections = function() { + if (resources.currentCollections.length > 1) { + alertify.confirm(gettextCatalog.getString('All stored collections will be lost. Do you want to continue?'), + function() { + tools.removeAllCollections(); + updateSelectedCollection(); + utils.rootScopeSafeApply(); + }); + } + else { + alertify.notify(gettextCatalog.getString('No collections stored'), 'warning', 5); + } + }; - $scope.disableDrivers = function() { - tools.disableDrivers(); - } - // Help + //-- Help $scope.openUrl = function(url) { - /*gui.Window.open(url, { - nodejs: false, - "new-instance": false - });*/ event.preventDefault(); gui.Shell.openExternal(url); - } + }; $scope.about = function() { var content = [ @@ -469,9 +491,173 @@ angular.module('icestudio') '

    Version: ' + $scope.version + '

    ', '

    License: GPL v2

    ', '

    Created by Jesús Arroyo Torrens

    ', - '

    © FPGAwars 2016

    ', + '

    © FPGAwars 2016-2017

    ', ' ', ''].join('\n'); alertify.alert(content); + }; + + + // Events + + var storedUndoStack = []; + var currentUndoStack = []; + + $(document).on('stackChanged', function(evt, undoStack) { + currentUndoStack = undoStack; + project.changed = JSON.stringify(storedUndoStack) !== JSON.stringify(undoStack); + project.updateTitle(); + zeroProject = false; + }); + + function resetChanged() { + storedUndoStack = currentUndoStack; + project.changed = false; + project.updateTitle(); + zeroProject = false; + } + + // Shortcuts + + var promptShown = false; + + alertify.prompt().set({ + onshow: function() { + promptShown = true; + }, + onclose: function() { + promptShown = false; + } + }); + + $(document).on('keydown', function(event) { + if (!promptShown) { + if (graph.isEnabled()) { + if (event.ctrlKey) { + switch (event.keyCode) { + case 78: // Ctrl+N + $scope.newProject(); + break; + case 79: // Ctrl+O + $scope.openProject(); + break; + case 83: + if (event.shiftKey) { // Ctrl+Shift+S + $scope.saveProjectAs(); + } + else { // Ctrl+S + $scope.saveProject(); + } + break; + case 81: // Ctrl+Q + $scope.quit(); + break; + case 90: + if (event.shiftKey) { // Ctrl+Shift+Z + $scope.redoGraph(); + event.preventDefault(); + } + else { // Ctrl+Z + $scope.undoGraph(); + event.preventDefault(); + } + break; + case 89: // Ctrl+Y + $scope.redoGraph(); + event.preventDefault(); + break; + case 88: // Ctrl+X + $scope.cutSelected(); + break; + case 67: // Ctrl+C + $scope.copySelected(); + break; + case 86: // Ctrl+V + $scope.pasteSelected(); + break; + case 65: // Ctrl+A + $scope.selectAll(); + break; + case 82: // Ctrl+R + $scope.verifyCode(); + break; + case 66: // Ctrl+B + $scope.buildCode(); + break; + case 85: // Ctrl+U + $scope.uploadCode(); + break; + } + } + + if (graph.hasSelection()) { + switch (event.keyCode) { + case 37: // Arrow Left + graph.stepLeft(); + break; + case 38: // Arrow Up + graph.stepUp(); + break; + case 39: // Arrow Right + graph.stepRight(); + break; + case 40: // Arrow Down + graph.stepDown(); + break; + } + } + + if (event.keyCode === 46) { // Supr + removeSelected(); + } + } + if (event.ctrlKey) { + switch (event.keyCode) { + case 48: // Ctrl+0 + $scope.resetView(); + break; + case 70: // Ctrl+F + $scope.fitContent(); + break; + } + } + if (event.keyCode === 8) { // Back + if (!graph.isEnabled()) { + $rootScope.$broadcast('breadcrumbsBack'); + } + else { + if (process.platform === 'darwin') { + removeSelected(); + } + } + } + } + if (event.ctrlKey && event.keyCode === 80) { // Ctrl+P + // Print and save a window snapshot + takeSnapshot(); + } + }); + + function takeSnapshot() { + win.capturePage(function(img) { + var base64Data = img.replace(/^data:image\/(png|jpg|jpeg);base64,/, ''); + saveSnapshot(base64Data); + }, 'png'); + } + + function saveSnapshot(base64Data) { + utils.saveDialog('#input-save-snapshot', '.png', function(filepath) { + nodeFs.writeFile(filepath, base64Data, 'base64', function (err) { + $scope.snapshotdir = utils.dirname(filepath) + utils.sep; + $scope.$apply(); + if (!err) { + alertify.success(gettextCatalog.getString('Image {{name}} saved', { name: utils.bold(utils.basename(filepath)) })); + } + else { + throw err; + } + }); + }); } + }); diff --git a/app/scripts/controllers/project.js b/app/scripts/controllers/project.js deleted file mode 100644 index 035da079f..000000000 --- a/app/scripts/controllers/project.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; - -angular.module('icestudio') - .controller('ProjectCtrl', function ($rootScope, - $scope, - common, - boards, - graph, - gettextCatalog) { - - $scope.common = common; - $scope.boards = boards; - $scope.graph = graph; - - // Intialization - - graph.createPaper($('#paper')); - - - // Breadcrumbs - - $scope.breadcrumbsNavitate = function(selectedItem) { - var item; - do { - graph.breadcrumbs.pop(); - item = graph.breadcrumbs.slice(-1)[0]; - } - while (selectedItem != item); - loadSelectedGraph(); - } - - $scope.breadcrumbsBack = function() { - graph.breadcrumbs.pop(); - loadSelectedGraph(); - } - - function loadSelectedGraph() { - if (graph.breadcrumbs.length == 1) { - graph.loadGraph(common.project); - graph.appEnable(true); - } - else { - var disabled = true; - var project = common.project; - for (var i = 1; i < graph.breadcrumbs.length; i++) { - project = project.deps[graph.breadcrumbs[i].name]; - } - graph.loadGraph(project, disabled); - graph.appEnable(false); - } - } - - $rootScope.$on('refreshProject', function(event, callback) { - common.refreshProject(callback); - }); - - }); diff --git a/app/scripts/factories/joint.factory.js b/app/scripts/factories/joint.factory.js index 3c9d19e27..97262d600 100644 --- a/app/scripts/factories/joint.factory.js +++ b/app/scripts/factories/joint.factory.js @@ -3,4 +3,4 @@ angular.module('icestudio') .factory('joint', function($window) { return $window.joint; - }) + }); diff --git a/app/scripts/factories/node.factory.js b/app/scripts/factories/node.factory.js index cd7fcde48..7f0facf3d 100644 --- a/app/scripts/factories/node.factory.js +++ b/app/scripts/factories/node.factory.js @@ -48,4 +48,10 @@ angular.module('icestudio') }) .factory('nodeLangInfo', function() { return require('node-lang-info'); + }) + .factory('nodeUnzip', function() { + return require('unzip'); + }) + .factory('SVGO', function() { + return require('svgo'); }); diff --git a/app/scripts/plugins/connectors/joint.connectors.js b/app/scripts/plugins/connectors/joint.connectors.js index 152a961ec..8c141240b 100644 --- a/app/scripts/plugins/connectors/joint.connectors.js +++ b/app/scripts/plugins/connectors/joint.connectors.js @@ -1,42 +1,43 @@ +'use strict'; joint.connectors.ice = function(sourcePoint, targetPoint, vertices) { - var points = []; + var points = []; - points.push({ x: sourcePoint.x, y: sourcePoint.y }); - _.each(vertices, function(vertex) { - points.push({ x: vertex.x, y: vertex.y }); - }); - points.push({ x: targetPoint.x, y: targetPoint.y }); + points.push({ x: sourcePoint.x, y: sourcePoint.y }); + _.each(vertices, function(vertex) { + points.push({ x: vertex.x, y: vertex.y }); + }); + points.push({ x: targetPoint.x, y: targetPoint.y }); - var step = 16; - var n = points.length; + var step = 8; + var n = points.length; - var sq = { x: points[0].x - points[1].x, y: points[0].y - points[1].y }; - var tq = { x: points[n-1].x - points[n-2].x, y: points[n-1].y - points[n-2].y }; + var sq = { x: points[0].x - points[1].x, y: points[0].y - points[1].y }; + var tq = { x: points[n-1].x - points[n-2].x, y: points[n-1].y - points[n-2].y }; - var sx = Math.sign(sq.x) * step; - var sy = Math.sign(sq.y) * step; + var sx = Math.sign(sq.x) * step; + var sy = Math.sign(sq.y) * step; - var tx = (tq.y == 0) ? Math.sign(tq.x) * step : 0; - var ty = (tq.x == 0) ? Math.sign(tq.y) * step : 0; + var tx = (tq.y === 0) ? Math.sign(tq.x) * step : 0; + var ty = (tq.x === 0) ? Math.sign(tq.y) * step : 0; - var full = ['M']; - var wrap = ['M']; + var full = ['M']; + var wrap = ['M']; - var dVertices = []; - _.each(vertices, function(vertex) { dVertices.push(vertex.x, vertex.y); }); + var dVertices = []; + _.each(vertices, function(vertex) { dVertices.push(vertex.x, vertex.y); }); - full.push(sourcePoint.x + sx, sourcePoint.y + sy); - wrap.push(sourcePoint.x, sourcePoint.y); + full.push(sourcePoint.x + sx, sourcePoint.y + sy); + wrap.push(sourcePoint.x, sourcePoint.y); - full = full.concat(dVertices); - wrap = wrap.concat(dVertices); + full = full.concat(dVertices); + wrap = wrap.concat(dVertices); - full.push(targetPoint.x + tx, targetPoint.y + ty); - wrap.push(targetPoint.x, targetPoint.y); + full.push(targetPoint.x + tx, targetPoint.y + ty); + wrap.push(targetPoint.x, targetPoint.y); - return { - full: full.join(' '), - wrap: wrap.join(' ') - }; + return { + full: full.join(' '), + wrap: wrap.join(' ') + }; }; diff --git a/app/scripts/plugins/dia/joint.dia.command.js b/app/scripts/plugins/dia/joint.dia.command.js new file mode 100755 index 000000000..224d1e2e8 --- /dev/null +++ b/app/scripts/plugins/dia/joint.dia.command.js @@ -0,0 +1,403 @@ +/* +Copyright (c) 2016-2017 FPGAwars +Copyright (c) 2013 client IO +*/ + +'use strict'; + +joint.dia.CommandManager = Backbone.Model.extend({ + + defaults: { + cmdBeforeAdd: null, + cmdNameRegex: /^(?:add|remove|board|change:\w+)$/ + }, + + // length of prefix 'change:' in the event name + PREFIX_LENGTH: 7, + + initialize: function(options) { + + _.bindAll(this, 'initBatchCommand', 'storeBatchCommand'); + + this.paper = options.paper; + this.graph = options.graph; + + this.reset(); + this.listen(); + }, + + listen: function() { + + this.listenTo(this.graph, 'all', this.addCommand, this); + + this.listenTo(this.graph, 'batch:start', this.initBatchCommand, this); + this.listenTo(this.graph, 'batch:stop', this.storeBatchCommand, this); + }, + + createCommand: function(options) { + + var cmd = { + action: undefined, + data: { id: undefined, type: undefined, previous: {}, next: {}}, + batch: options && options.batch + }; + + return cmd; + }, + + addCommand: function(cmdName, cell, graph, options) { + + if (cmdName === 'change:labels' || + cmdName === 'change:z') { + return; + } + + if (!this.get('cmdNameRegex').test(cmdName)) { + return; + } + + if (typeof this.get('cmdBeforeAdd') === 'function' && !this.get('cmdBeforeAdd').apply(this, arguments)) { + return; + } + + var push = _.bind(function(cmd) { + + this.redoStack = []; + + if (!cmd.batch) { + this.undoStack.push(cmd); + this.triggerChange(); + this.trigger('add', cmd); + } else { + this.lastCmdIndex = Math.max(this.lastCmdIndex, 0); + // Commands possible thrown away. Someone might be interested. + this.trigger('batch', cmd); + } + + }, this); + + var command; + + if (this.batchCommand) { + // set command as the one used last. + // in most cases we are working with same object, doing same action + // etc. translate an object piece by piece + command = this.batchCommand[Math.max(this.lastCmdIndex,0)]; + + // Check if we are start working with new object or performing different action with it. + // Note, that command is uninitialized when lastCmdIndex equals -1. (see 'initBatchCommand()') + // in that case we are done, command we were looking for is already set + if (this.lastCmdIndex >= 0 && (command.data.id !== cell.id || command.action !== cmdName)) { + + // trying to find command first, which was performing same action with the object + // as we are doing now with cell + command = _.find(this.batchCommand, function(cmd, index) { + this.lastCmdIndex = index; + return cmd.data.id === cell.id && cmd.action === cmdName; + }, this); + + if (!command) { + // command with such an id and action was not found. Let's create new one + this.lastCmdIndex = this.batchCommand.push(this.createCommand({ batch: true })) - 1; + command = _.last(this.batchCommand); + } + } + + } else { + + // single command + command = this.createCommand(); + command.batch = false; + } + + if (cmdName === 'add' || cmdName === 'remove') { + + // In a batch: delete an "add-remove" sequence if it is applied to the same cell + if (cmdName === 'remove' && this.batchCommand && this.lastCmdIndex > 0) { + var prevCommand = this.batchCommand[this.lastCmdIndex-1]; + if (prevCommand.action === 'add' && prevCommand.data.id === cell.id) { + this.batchCommand.pop(); + this.batchCommand.pop(); + return; + } + } + + command.action = cmdName; + command.data.id = cell.id; + command.data.type = cell.attributes.type; + command.data.attributes = _.merge({}, cell.toJSON()); + command.options = options || {}; + + return push(command); + } + + if (cmdName === 'board') { + + command.action = cmdName; + command.data = cell.data; + + return push(command); + } + + // `changedAttribute` holds the attribute name corresponding + // to the change event triggered on the model. + var changedAttribute = cmdName.substr(this.PREFIX_LENGTH); + + if (!command.batch || !command.action) { + // Do this only once. Set previous box and action (also serves as a flag so that + // we don't repeat this branche). + command.action = cmdName; + command.data.id = cell.id; + command.data.type = cell.attributes.type; + command.data.previous[changedAttribute] = _.clone(cell.previous(changedAttribute)); + command.options = options || {}; + } + + command.data.next[changedAttribute] = _.clone(cell.get(changedAttribute)); + + return push(command); + }, + + // Batch commands are those that merge certain commands applied in a row (1) and those that + // hold multiple commands where one action consists of more than one command (2) + // (1) This is useful for e.g. when the user is dragging an object in the paper which would + // normally lead to 1px translation commands. Applying undo() on such commands separately is + // most likely undesirable. + // (2) e.g When you are removing an element, you don't want all links connected to that element, which + // are also being removed to be part of different command + + initBatchCommand: function() { + + //console.log('initBatchCommand', this.batchCommand); + + if (!this.batchCommand) { + + this.batchCommand = [this.createCommand({ batch: true})]; + this.lastCmdIndex = -1; + + // batch level counts how many times has been initBatchCommand executed. + // It is useful when we doing an operation recursively. + this.batchLevel = 0; + + } else { + + // batch command is already active + this.batchLevel++; + } + }, + + storeBatchCommand: function() { + + //console.log('storeBatchCommand', this.batchCommand, this.batchLevel); + + // In order to store batch command it is necesary to run storeBatchCommand as many times as + // initBatchCommand was executed + if (this.batchCommand && this.batchLevel <= 0) { + + // checking if there is any valid command in batch + // for example: calling `initBatchCommand` immediately followed by `storeBatchCommand` + if (this.lastCmdIndex >= 0) { + + this.redoStack = []; + + this.undoStack.push(this.batchCommand); + this.triggerChange(); + this.trigger('add', this.batchCommand); + } + + delete this.batchCommand; + delete this.lastCmdIndex; + delete this.batchLevel; + + } else if (this.batchCommand && this.batchLevel > 0) { + + // low down batch command level, but not store it yet + this.batchLevel--; + } + }, + + revertCommand: function(command) { + + this.stopListening(); + + var batchCommand; + + if (_.isArray(command)) { + batchCommand = command; + } else { + batchCommand = [command]; + } + + for (var i = batchCommand.length - 1; i >= 0; i--) { + + var cmd = batchCommand[i], cell = this.graph.getCell(cmd.data.id); + + switch (cmd.action) { + + case 'add': + cell.remove(); + break; + + case 'remove': + this.graph.addCell(cmd.data.attributes); + break; + + case 'board': + this.triggerBoard(cmd.data.previous); + break; + + default: + var data = null; + var options = null; + var attribute = cmd.action.substr(this.PREFIX_LENGTH); + //console.log('UNDO', cmd.action, cmd); + if (attribute === 'data' && cmd.options.translateBy) { + // Invert relative movement + cmd.options.ty *= -1; + options = cmd.options; + } + if (attribute === 'data' && + (cmd.data.type === 'ice.Code' || + cmd.data.type === 'ice.Info')) { + // Ace editor requires the next deltas to revert + data = cmd.data.next[attribute]; + } + else { + data = cmd.data.previous[attribute]; + } + cell.set(attribute, data, options); + if (cell) { + var cellView = this.paper.findViewByModel(cell); + if (cellView) { + cellView.apply({ undo: true }); + } + } + break; + } + } + + this.listen(); + }, + + applyCommand: function(command) { + + this.stopListening(); + + var batchCommand; + + if (_.isArray(command)) { + batchCommand = command; + } else { + batchCommand = [command]; + } + + for (var i = 0; i < batchCommand.length; i++) { + + var cmd = batchCommand[i], cell = this.graph.getCell(cmd.data.id); + + switch (cmd.action) { + + case 'add': + this.graph.addCell(cmd.data.attributes); + break; + + case 'remove': + cell.remove(); + break; + + case 'board': + this.triggerBoard(cmd.data.next); + break; + + default: + var data = null; + var options = null; + var attribute = cmd.action.substr(this.PREFIX_LENGTH); + //console.log('REDO', cmd.action, cmd); + if (attribute === 'data' && cmd.options.translateBy) { + cmd.options.ty *= -1; + options = cmd.options; + } + data = cmd.data.next[attribute]; + cell.set(attribute, data, options); + if (cell) { + var cellView = this.paper.findViewByModel(cell); + if (cellView) { + cellView.apply({ undo: false }); + } + } + break; + } + } + + this.listen(); + }, + + undo: function(state) { + + var command = this.undoStack.pop(); + this.triggerChange(); + + if (command) { + + if (command.action === 'add') { + command.data.attributes.state = state; + } + + this.revertCommand(command); + this.redoStack.push(command); + } + }, + + + redo: function(state) { + + var command = this.redoStack.pop(); + + if (command) { + + if (command.action === 'add') { + command.data.attributes.state = state; + } + + this.applyCommand(command); + this.undoStack.push(command); + this.triggerChange(); + } + }, + + cancel: function() { + + if (this.hasUndo()) { + + this.revertCommand(this.undoStack.pop()); + this.redoStack = []; + } + }, + + reset: function() { + + this.undoStack = []; + this.redoStack = []; + }, + + hasUndo: function() { + + return this.undoStack.length > 0; + }, + + hasRedo: function() { + + return this.redoStack.length > 0; + }, + + triggerChange: function() { + var currentUndoStack = _.clone(this.undoStack); + $(document).trigger('stackChanged', [currentUndoStack]); + }, + + triggerBoard: function(name) { + $(document).trigger('boardChanged', [name]); + } + +}); diff --git a/app/scripts/plugins/routers/joint.routers.js b/app/scripts/plugins/routers/joint.routers.js index c1591d61d..982bad08c 100644 --- a/app/scripts/plugins/routers/joint.routers.js +++ b/app/scripts/plugins/routers/joint.routers.js @@ -1,522 +1,535 @@ joint.routers.ice = (function(g, _, joint) { - 'use strict'; - - var config = { - - // size of the step to find a route - step: 8, - - // use of the perpendicular linkView option to connect center of element with first vertex - perpendicular: true, - - // should be source or target not to be consider as an obstacle - excludeEnds: [], // 'source', 'target' - - // should be any element with a certain type not to be consider as an obstacle - excludeTypes: ['basic.Text'], - - // if number of route finding loops exceed the maximum, stops searching and returns - // fallback route - maximumLoops: 2000, - - // possible starting directions from an element - startDirections: ['right'], - - // possible ending directions to an element - endDirections: ['left'], - - // specify directions above - directionMap: { - right: { x: 1, y: 0 }, - bottom: { x: 0, y: 1 }, - left: { x: -1, y: 0 }, - top: { x: 0, y: -1 } - }, - - // maximum change of the direction - maxAllowedDirectionChange: 90, - - // padding applied on the element bounding boxes - paddingBox: function() { - - var step = 1; - - return { - x: -step, - y: -step, - width: 2 * step, - height: 2 * step - }; - }, - - // an array of directions to find next points on the route - directions: function() { - - var step = this.step; - - return [ - { offsetX: step , offsetY: 0 , cost: step }, - { offsetX: 0 , offsetY: step , cost: step }, - { offsetX: -step , offsetY: 0 , cost: step }, - { offsetX: 0 , offsetY: -step , cost: step } - ]; - }, - - // a penalty received for direction change - penalties: function() { - - return { - 0: 0, - 45: this.step / 2, - 90: this.step / 2 - }; - }, - - // * Deprecated * - // a simple route used in situations, when main routing method fails - // (exceed loops, inaccessible). - /* i.e. - function(from, to, opts) { - // Find an orthogonal route ignoring obstacles. - var point = ((opts.previousDirAngle || 0) % 180 === 0) - ? g.point(from.x, to.y) - : g.point(to.x, from.y); - return [point, to]; - }, - */ - fallbackRoute: _.constant(null), - - // if a function is provided, it's used to route the link while dragging an end - // i.e. function(from, to, opts) { return []; } - draggingRoute: null - }; - - // Map of obstacles - // Helper structure to identify whether a point lies in an obstacle. - function ObstacleMap(opt) { - - this.map = {}; - this.options = opt; - // tells how to divide the paper when creating the elements map - this.mapGridSize = 100; + 'use strict'; + + var config = { + + // size of the step to find a route + step: 8, + + // use of the perpendicular linkView option to connect center of element with first vertex + perpendicular: true, + + // should be source or target not to be consider as an obstacle + excludeEnds: [], // 'source', 'target' + + // should be any element with a certain type not to be consider as an obstacle + excludeTypes: ['basic.Text'], + + // if number of route finding loops exceed the maximum, stops searching and returns + // fallback route + maximumLoops: 2000, + + // possible starting directions from an element + startDirections: ['right', 'bottom'], + + // possible ending directions to an element + endDirections: ['left', 'top'], + + // specify directions above + directionMap: { + right: { x: 1, y: 0 }, + bottom: { x: 0, y: 1 }, + left: { x: -1, y: 0 }, + top: { x: 0, y: -1 } + }, + + // maximum change of the direction + maxAllowedDirectionChange: 90, + + // padding applied on the element bounding boxes + paddingBox: function() { + + var step = 1; + + return { + x: -step, + y: -step, + width: 2 * step, + height: 2 * step + }; + }, + + // an array of directions to find next points on the route + directions: function() { + + var step = this.step; + + return [ + { offsetX: step , offsetY: 0 , cost: step }, + { offsetX: 0 , offsetY: step , cost: step }, + { offsetX: -step , offsetY: 0 , cost: step }, + { offsetX: 0 , offsetY: -step , cost: step } + ]; + }, + + // a penalty received for direction change + penalties: function() { + + return { + 0: 0, + 45: this.step / 2, + 90: this.step / 2 + }; + }, + + // * Deprecated * + // a simple route used in situations, when main routing method fails + // (exceed loops, inaccessible). + /* i.e. + function(from, to, opts) { + // Find an orthogonal route ignoring obstacles. + var point = ((opts.previousDirAngle || 0) % 180 === 0) + ? g.point(from.x, to.y) + : g.point(to.x, from.y); + return [point, to]; + }, + */ + fallbackRoute: _.constant(null), + + // if a function is provided, it's used to route the link while dragging an end + // i.e. function(from, to, opts) { return []; } + draggingRoute: null + }; + + // Map of obstacles + // Helper structure to identify whether a point lies in an obstacle. + function ObstacleMap(opt) { + + this.map = {}; + this.options = opt; + // tells how to divide the paper when creating the elements map + this.mapGridSize = 100; + } + + ObstacleMap.prototype.build = function(graph, link) { + + var opt = this.options; + + // source or target element could be excluded from set of obstacles + var excludedEnds = _.chain(opt.excludeEnds) + .map(link.get, link) + .pluck('id') + .map(graph.getCell, graph).value(); + + // Exclude any embedded elements from the source and the target element. + var excludedAncestors = []; + + var source = graph.getCell(link.get('source').id); + if (source) { + excludedAncestors = _.union(excludedAncestors, _.map(source.getAncestors(), 'id')); } - ObstacleMap.prototype.build = function(graph, link) { + var target = graph.getCell(link.get('target').id); + if (target) { + excludedAncestors = _.union(excludedAncestors, _.map(target.getAncestors(), 'id')); + } - var opt = this.options; + // builds a map of all elements for quicker obstacle queries (i.e. is a point contained + // in any obstacle?) (a simplified grid search) + // The paper is divided to smaller cells, where each of them holds an information which + // elements belong to it. When we query whether a point is in an obstacle we don't need + // to go through all obstacles, we check only those in a particular cell. + var mapGridSize = this.mapGridSize; + + _.chain(graph.getElements()) + // remove source and target element if required + .difference(excludedEnds) + // remove all elements whose type is listed in excludedTypes array + .reject(function(element) { + // reject any element which is an ancestor of either source or target + return _.contains(opt.excludeTypes, element.get('type')) || _.contains(excludedAncestors, element.id); + }) + // change elements (models) to their bounding boxes + .invoke('getBBox') + // expand their boxes by specific padding + .invoke('moveAndExpand', opt.paddingBox) + // build the map + .foldl(function(map, bbox) { + + var origin = bbox.origin().snapToGrid(mapGridSize); + var corner = bbox.corner().snapToGrid(mapGridSize); + + for (var x = origin.x; x <= corner.x; x += mapGridSize) { + for (var y = origin.y; y <= corner.y; y += mapGridSize) { + + var gridKey = x + '@' + y; + + map[gridKey] = map[gridKey] || []; + map[gridKey].push(bbox); + } + } - // source or target element could be excluded from set of obstacles - var excludedEnds = _.chain(opt.excludeEnds) - .map(link.get, link) - .pluck('id') - .map(graph.getCell, graph).value(); + return map; - // Exclude any embedded elements from the source and the target element. - var excludedAncestors = []; + }, this.map).value(); - var source = graph.getCell(link.get('source').id); - if (source) { - excludedAncestors = _.union(excludedAncestors, _.map(source.getAncestors(), 'id')); - }; + return this; + }; - var target = graph.getCell(link.get('target').id); - if (target) { - excludedAncestors = _.union(excludedAncestors, _.map(target.getAncestors(), 'id')); - } + ObstacleMap.prototype.isPointAccessible = function(point) { - // builds a map of all elements for quicker obstacle queries (i.e. is a point contained - // in any obstacle?) (a simplified grid search) - // The paper is divided to smaller cells, where each of them holds an information which - // elements belong to it. When we query whether a point is in an obstacle we don't need - // to go through all obstacles, we check only those in a particular cell. - var mapGridSize = this.mapGridSize; - - _.chain(graph.getElements()) - // remove source and target element if required - .difference(excludedEnds) - // remove all elements whose type is listed in excludedTypes array - .reject(function(element) { - // reject any element which is an ancestor of either source or target - return _.contains(opt.excludeTypes, element.get('type')) || _.contains(excludedAncestors, element.id); - }) - // change elements (models) to their bounding boxes - .invoke('getBBox') - // expand their boxes by specific padding - .invoke('moveAndExpand', opt.paddingBox) - // build the map - .foldl(function(map, bbox) { - - var origin = bbox.origin().snapToGrid(mapGridSize); - var corner = bbox.corner().snapToGrid(mapGridSize); - - for (var x = origin.x; x <= corner.x; x += mapGridSize) { - for (var y = origin.y; y <= corner.y; y += mapGridSize) { - - var gridKey = x + '@' + y; - - map[gridKey] = map[gridKey] || []; - map[gridKey].push(bbox); - } - } - - return map; - - }, this.map).value(); - - return this; - }; - - ObstacleMap.prototype.isPointAccessible = function(point) { - - var mapKey = point.clone().snapToGrid(this.mapGridSize).toString(); - - return _.every(this.map[mapKey], function(obstacle) { - return !obstacle.containsPoint(point); - }); - }; - - // Sorted Set - // Set of items sorted by given value. - function SortedSet() { - this.items = []; - this.hash = {}; - this.values = {}; - this.OPEN = 1; - this.CLOSE = 2; - } + var mapKey = point.clone().snapToGrid(this.mapGridSize).toString(); - SortedSet.prototype.add = function(item, value) { + return _.every(this.map[mapKey], function(obstacle) { + return !obstacle.containsPoint(point); + }); + }; - if (this.hash[item]) { - // item removal - this.items.splice(this.items.indexOf(item), 1); - } else { - this.hash[item] = this.OPEN; - } - - this.values[item] = value; + // Sorted Set + // Set of items sorted by given value. + function SortedSet() { + this.items = []; + this.hash = {}; + this.values = {}; + this.OPEN = 1; + this.CLOSE = 2; + } - var index = _.sortedIndex(this.items, item, function(i) { - return this.values[i]; - }, this); + SortedSet.prototype.add = function(item, value) { - this.items.splice(index, 0, item); - }; + if (this.hash[item]) { + // item removal + this.items.splice(this.items.indexOf(item), 1); + } else { + this.hash[item] = this.OPEN; + } - SortedSet.prototype.remove = function(item) { - this.hash[item] = this.CLOSE; - }; + this.values[item] = value; - SortedSet.prototype.isOpen = function(item) { - return this.hash[item] === this.OPEN; - }; + var index = _.sortedIndex(this.items, item, function(i) { + return this.values[i]; + }, this); - SortedSet.prototype.isClose = function(item) { - return this.hash[item] === this.CLOSE; - }; + this.items.splice(index, 0, item); + }; - SortedSet.prototype.isEmpty = function() { - return this.items.length === 0; - }; + SortedSet.prototype.remove = function(item) { + this.hash[item] = this.CLOSE; + }; - SortedSet.prototype.pop = function() { - var item = this.items.shift(); - this.remove(item); - return item; - }; + SortedSet.prototype.isOpen = function(item) { + return this.hash[item] === this.OPEN; + }; - function normalizePoint(point) { - return g.point( - point.x === 0 ? 0 : Math.abs(point.x) / point.x, - point.y === 0 ? 0 : Math.abs(point.y) / point.y - ); - } + SortedSet.prototype.isClose = function(item) { + return this.hash[item] === this.CLOSE; + }; - // reconstructs a route by concating points with their parents - function reconstructRoute(parents, point, startCenter, endCenter) { + SortedSet.prototype.isEmpty = function() { + return this.items.length === 0; + }; - var route = []; - var prevDiff = normalizePoint(endCenter.difference(point)); - var current = point; - var parent; + SortedSet.prototype.pop = function() { + var item = this.items.shift(); + this.remove(item); + return item; + }; - while ((parent = parents[current])) { + function normalizePoint(point) { + return g.point( + point.x === 0 ? 0 : Math.abs(point.x) / point.x, + point.y === 0 ? 0 : Math.abs(point.y) / point.y + ); + } - var diff = normalizePoint(current.difference(parent)); + // reconstructs a route by concating points with their parents + function reconstructRoute(parents, point, startCenter, endCenter) { - if (!diff.equals(prevDiff)) { + var route = []; + var prevDiff = normalizePoint(endCenter.difference(point)); + var current = point; + var parent; - route.unshift(current); - prevDiff = diff; - } + while ((parent = parents[current])) { - current = parent; - } + var diff = normalizePoint(current.difference(parent)); - var startDiff = normalizePoint(g.point(current).difference(startCenter)); - if (!startDiff.equals(prevDiff)) { - route.unshift(current); - } + if (!diff.equals(prevDiff)) { + route.unshift(current); + prevDiff = diff; + } - return route; + current = parent; } - // find points around the rectangle taking given directions in the account - function getRectPoints(bbox, directionList, opt) { + var startDiff = normalizePoint(g.point(current).difference(startCenter)); + if (!startDiff.equals(prevDiff)) { + route.unshift(current); + } - var step = opt.step; - var center = bbox.center(); - var startPoints = _.chain(opt.directionMap).pick(directionList).map(function(direction) { + return route; + } - var x = direction.x * bbox.width / 2; - var y = direction.y * bbox.height / 2; + // find points around the rectangle taking given directions in the account + function getRectPoints(bbox, directionList, opt) { - var point = center.clone().offset(x, y); + var step = opt.step; + var center = bbox.center(); + var startPoints = _.chain(opt.directionMap).pick(directionList).map(function(direction) { - if (bbox.containsPoint(point)) { + var x = direction.x * bbox.width / 2; + var y = direction.y * bbox.height / 2; - point.offset(direction.x * step, direction.y * step); - } + var point = center.clone().offset(x, y); - return point.snapToGrid(step); + if (bbox.containsPoint(point)) { + point.offset(direction.x * step, direction.y * step); + } - }).value(); + return point.snapToGrid(step); - return startPoints; - }; + }).value(); - // returns a direction index from start point to end point - function getDirectionAngle(start, end, dirLen) { + return startPoints; + } - var q = 360 / dirLen; - return Math.floor(g.normalizeAngle(start.theta(end) + q / 2) / q) * q; - } + // returns a direction index from start point to end point + function getDirectionAngle(start, end, dirLen) { - function getDirectionChange(angle1, angle2) { + var q = 360 / dirLen; + return Math.floor(g.normalizeAngle(start.theta(end) + q / 2) / q) * q; + } - var dirChange = Math.abs(angle1 - angle2); - return dirChange > 180 ? 360 - dirChange : dirChange; - } + function getDirectionChange(angle1, angle2) { - // heurestic method to determine the distance between two points - function estimateCost(from, endPoints) { + var dirChange = Math.abs(angle1 - angle2); + return dirChange > 180 ? 360 - dirChange : dirChange; + } - var min = Infinity; + // heurestic method to determine the distance between two points + function estimateCost(from, endPoints) { - for (var i = 0, len = endPoints.length; i < len; i++) { - var cost = from.manhattanDistance(endPoints[i]); - if (cost < min) min = cost; - }; + var min = Infinity; - return min; + for (var i = 0, len = endPoints.length; i < len; i++) { + var cost = from.manhattanDistance(endPoints[i]); + if (cost < min) { + min = cost; + } } - // finds the route between to points/rectangles implementing A* alghoritm - function findRoute(start, end, map, opt) { + return min; + } - var step = opt.step; - var startPoints, endPoints; - var startCenter, endCenter; + // finds the route between to points/rectangles implementing A* alghoritm + function findRoute(start, end, map, opt) { - // set of points we start pathfinding from - if (start instanceof g.rect) { - startPoints = getRectPoints(start, opt.startDirections, opt); - startCenter = start.center().snapToGrid(step); - } else { - startCenter = start.clone().snapToGrid(step); - startPoints = [startCenter]; - } + var step = opt.step; + var startPoints, endPoints; + var startCenter, endCenter; - // set of points we want the pathfinding to finish at - if (end instanceof g.rect) { - endPoints = getRectPoints(end, opt.endDirections, opt); - endCenter = end.center().snapToGrid(step); - } else { - endCenter = end.clone().snapToGrid(step); - endPoints = [endCenter]; + // set of points we start pathfinding from + if (start instanceof g.rect) { + startPoints = getRectPoints(start, opt.startDirections, opt); + startCenter = start.center().snapToGrid(step); + } else { + startCenter = start.clone().snapToGrid(step); + startPoints = [startCenter]; + } + + // set of points we want the pathfinding to finish at + if (end instanceof g.rect) { + endPoints = getRectPoints(end, opt.endDirections, opt); + endCenter = end.center().snapToGrid(step); + } else { + endCenter = end.clone().snapToGrid(step); + endPoints = [endCenter]; + } + + // take into account only accessible end points + startPoints = _.filter(startPoints, map.isPointAccessible, map); + endPoints = _.filter(endPoints, map.isPointAccessible, map); + + // Check if there is a accessible end point. + // We would have to use a fallback route otherwise. + if (startPoints.length > 0 && endPoints.length > 0) { + + // The set of tentative points to be evaluated, initially containing the start points. + var openSet = new SortedSet(); + // Keeps reference to a point that is immediate predecessor of given element. + var parents = {}; + // Cost from start to a point along best known path. + var costs = {}; + + _.each(startPoints, function(point) { + var key = point.toString(); + openSet.add(key, estimateCost(point, endPoints)); + costs[key] = 0; + }); + + // directions + var dir, dirChange; + var dirs = opt.directions; + var dirLen = dirs.length; + var loopsRemain = opt.maximumLoops; + var endPointsKeys = _.invoke(endPoints, 'toString'); + + // main route finding loop + while (!openSet.isEmpty() && loopsRemain > 0) { + + // remove current from the open list + var currentKey = openSet.pop(); + var currentPoint = g.point(currentKey); + var currentDist = costs[currentKey]; + var previousDirAngle = currentDirAngle; + /* jshint -W116 */ + var currentDirAngle = parents[currentKey] ? getDirectionAngle(parents[currentKey], currentPoint, dirLen) + : opt.previousDirAngle != null ? opt.previousDirAngle : getDirectionAngle(startCenter, currentPoint, dirLen); + /* jshint +W116 */ + + // Check if we reached any endpoint + if (endPointsKeys.indexOf(currentKey) >= 0) { + // We don't want to allow route to enter the end point in opposite direction. + dirChange = getDirectionChange(currentDirAngle, getDirectionAngle(currentPoint, endCenter, dirLen)); + if (currentPoint.equals(endCenter) || dirChange < 180) { + opt.previousDirAngle = currentDirAngle; + return reconstructRoute(parents, currentPoint, startCenter, endCenter); + } } - // take into account only accessible end points - startPoints = _.filter(startPoints, map.isPointAccessible, map); - endPoints = _.filter(endPoints, map.isPointAccessible, map); - - // Check if there is a accessible end point. - // We would have to use a fallback route otherwise. - if (startPoints.length > 0 && endPoints.length > 0) { - - // The set of tentative points to be evaluated, initially containing the start points. - var openSet = new SortedSet(); - // Keeps reference to a point that is immediate predecessor of given element. - var parents = {}; - // Cost from start to a point along best known path. - var costs = {}; - - _.each(startPoints, function(point) { - var key = point.toString(); - openSet.add(key, estimateCost(point, endPoints)); - costs[key] = 0; - }); - - // directions - var dir, dirChange; - var dirs = opt.directions; - var dirLen = dirs.length; - var loopsRemain = opt.maximumLoops; - var endPointsKeys = _.invoke(endPoints, 'toString'); - - // main route finding loop - while (!openSet.isEmpty() && loopsRemain > 0) { - - // remove current from the open list - var currentKey = openSet.pop(); - var currentPoint = g.point(currentKey); - var currentDist = costs[currentKey]; - var previousDirAngle = currentDirAngle; - var currentDirAngle = parents[currentKey] - ? getDirectionAngle(parents[currentKey], currentPoint, dirLen) - : opt.previousDirAngle != null ? opt.previousDirAngle : getDirectionAngle(startCenter, currentPoint, dirLen); - - // Check if we reached any endpoint - if (endPointsKeys.indexOf(currentKey) >= 0) { - // We don't want to allow route to enter the end point in opposite direction. - dirChange = getDirectionChange(currentDirAngle, getDirectionAngle(currentPoint, endCenter, dirLen)); - if (currentPoint.equals(endCenter) || dirChange < 180) { - opt.previousDirAngle = currentDirAngle; - return reconstructRoute(parents, currentPoint, startCenter, endCenter); - } - } - - // Go over all possible directions and find neighbors. - for (var i = 0; i < dirLen; i++) { - - dir = dirs[i]; - dirChange = getDirectionChange(currentDirAngle, dir.angle); - // if the direction changed rapidly don't use this point - // Note that check is relevant only for points with previousDirAngle i.e. - // any direction is allowed for starting points - if (previousDirAngle && dirChange > opt.maxAllowedDirectionChange) { - continue; - } - - var neighborPoint = currentPoint.clone().offset(dir.offsetX, dir.offsetY); - var neighborKey = neighborPoint.toString(); - // Closed points from the openSet were already evaluated. - if (openSet.isClose(neighborKey) || !map.isPointAccessible(neighborPoint)) { - continue; - } - - // The current direction is ok to proccess. - var costFromStart = currentDist + dir.cost + opt.penalties[dirChange]; - - if (!openSet.isOpen(neighborKey) || costFromStart < costs[neighborKey]) { - // neighbor point has not been processed yet or the cost of the path - // from start is lesser than previously calcluated. - parents[neighborKey] = currentPoint; - costs[neighborKey] = costFromStart; - openSet.add(neighborKey, costFromStart + estimateCost(neighborPoint, endPoints)); - }; - }; - - loopsRemain--; - } + // Go over all possible directions and find neighbors. + for (var i = 0; i < dirLen; i++) { + + dir = dirs[i]; + dirChange = getDirectionChange(currentDirAngle, dir.angle); + // if the direction changed rapidly don't use this point + // Note that check is relevant only for points with previousDirAngle i.e. + // any direction is allowed for starting points + if (previousDirAngle && dirChange > opt.maxAllowedDirectionChange) { + continue; + } + + var neighborPoint = currentPoint.clone().offset(dir.offsetX, dir.offsetY); + var neighborKey = neighborPoint.toString(); + // Closed points from the openSet were already evaluated. + if (openSet.isClose(neighborKey) || !map.isPointAccessible(neighborPoint)) { + continue; + } + + // The current direction is ok to proccess. + var costFromStart = currentDist + dir.cost + opt.penalties[dirChange]; + + if (!openSet.isOpen(neighborKey) || costFromStart < costs[neighborKey]) { + // neighbor point has not been processed yet or the cost of the path + // from start is lesser than previously calcluated. + parents[neighborKey] = currentPoint; + costs[neighborKey] = costFromStart; + openSet.add(neighborKey, costFromStart + estimateCost(neighborPoint, endPoints)); + } } - // no route found ('to' point wasn't either accessible or finding route took - // way to much calculations) - return opt.fallbackRoute(startCenter, endCenter, opt); + loopsRemain--; + } } - // resolve some of the options - function resolveOptions(opt) { + // no route found ('to' point wasn't either accessible or finding route took + // way to much calculations) + return opt.fallbackRoute(startCenter, endCenter, opt); + } - opt.directions = _.result(opt, 'directions'); - opt.penalties = _.result(opt, 'penalties'); - opt.paddingBox = _.result(opt, 'paddingBox'); + // resolve some of the options + function resolveOptions(opt) { - _.each(opt.directions, function(direction) { + opt.directions = _.result(opt, 'directions'); + opt.penalties = _.result(opt, 'penalties'); + opt.paddingBox = _.result(opt, 'paddingBox'); - var point1 = g.point(0, 0); - var point2 = g.point(direction.offsetX, direction.offsetY); + _.each(opt.directions, function(direction) { - direction.angle = g.normalizeAngle(point1.theta(point2)); - }); - } + var point1 = g.point(0, 0); + var point2 = g.point(direction.offsetX, direction.offsetY); + + direction.angle = g.normalizeAngle(point1.theta(point2)); + }); + } + + // initiation of the route finding + function router(vertices, opt) { - // initiation of the route finding - function router(vertices, opt) { + resolveOptions(opt); - resolveOptions(opt); + /* jshint -W040 */ - // enable/disable linkView perpendicular option - this.options.perpendicular = !!opt.perpendicular; + // enable/disable linkView perpendicular option + this.options.perpendicular = !!opt.perpendicular; - // expand boxes by specific padding - var sourceBBox = g.rect(this.sourceBBox).moveAndExpand(opt.paddingBox); - var targetBBox = g.rect(this.targetBBox).moveAndExpand(opt.paddingBox); + // expand boxes by specific padding + var sourceBBox = g.rect(this.sourceBBox).moveAndExpand(opt.paddingBox); + var targetBBox = g.rect(this.targetBBox).moveAndExpand(opt.paddingBox); - // pathfinding - var map = (new ObstacleMap(opt)).build(this.paper.model, this.model); - var oldVertices = _.map(vertices, g.point); - var newVertices = []; - var tailPoint = sourceBBox.center().snapToGrid(opt.step); + // pathfinding + var map = (new ObstacleMap(opt)).build(this.paper.model, this.model); + var oldVertices = _.map(vertices, g.point); + var newVertices = []; + var tailPoint = sourceBBox.center().snapToGrid(opt.step); - // find a route by concating all partial routes (routes need to go through the vertices) - // startElement -> vertex[1] -> ... -> vertex[n] -> endElement - for (var i = 0, len = oldVertices.length; i <= len; i++) { + // find a route by concating all partial routes (routes need to go through the vertices) + // startElement -> vertex[1] -> ... -> vertex[n] -> endElement + for (var i = 0, len = oldVertices.length; i <= len; i++) { - var partialRoute = null; + var partialRoute = null; - var from = to || sourceBBox; - var to = oldVertices[i]; + var from = to || sourceBBox; + var to = oldVertices[i]; - if (!to) { + if (!to) { - to = targetBBox; + to = targetBBox; - // 'to' is not a vertex. If the target is a point (i.e. it's not an element), we - // might use dragging route instead of main routing method if that is enabled. - var endingAtPoint = !this.model.get('source').id || !this.model.get('target').id; + // 'to' is not a vertex. If the target is a point (i.e. it's not an element), we + // might use dragging route instead of main routing method if that is enabled. + var endingAtPoint = !this.model.get('source').id || !this.model.get('target').id; - if (endingAtPoint && _.isFunction(opt.draggingRoute)) { - // Make sure we passing points only (not rects). - var dragFrom = from instanceof g.rect ? from.center() : from; - partialRoute = opt.draggingRoute(dragFrom, to.origin(), opt); - } - } + if (endingAtPoint && _.isFunction(opt.draggingRoute)) { + // Make sure we passing points only (not rects). + var dragFrom = from instanceof g.rect ? from.center() : from; + partialRoute = opt.draggingRoute(dragFrom, to.origin(), opt); + } + } + + // if partial route has not been calculated yet use the main routing method to find one + partialRoute = partialRoute || findRoute(from, to, map, opt); - // if partial route has not been calculated yet use the main routing method to find one - partialRoute = partialRoute || findRoute(from, to, map, opt); + if (partialRoute === null) { + // The partial route could not be found. + // use orthogonal (do not avoid elements) route instead. + if (!_.isFunction(joint.routers.orthogonal)) { + throw new Error('Manhattan requires the orthogonal router.'); + } + return joint.routers.orthogonal(vertices, opt, this); + } - if (partialRoute === null) { - // The partial route could not be found. - // use orthogonal (do not avoid elements) route instead. - if (!_.isFunction(joint.routers.orthogonal)) { - throw new Error('Manhattan requires the orthogonal router.'); - } - return joint.routers.orthogonal(vertices, opt, this); - }; + var leadPoint = _.first(partialRoute); - var leadPoint = _.first(partialRoute); + if (leadPoint && leadPoint.equals(tailPoint)) { + // remove the first point if the previous partial route had the same point as last + partialRoute.shift(); + } - if (leadPoint && leadPoint.equals(tailPoint)) { - // remove the first point if the previous partial route had the same point as last - partialRoute.shift(); - } + tailPoint = _.last(partialRoute) || tailPoint; - tailPoint = _.last(partialRoute) || tailPoint; + Array.prototype.push.apply(newVertices, partialRoute); + } - Array.prototype.push.apply(newVertices, partialRoute); - }; + /* jshint +W040 */ - return newVertices; + return newVertices; + } + + // public function + return function(vertices, opt, linkView) { + + if (linkView.sourceMagnet) { + opt.startDirections = [linkView.sourceMagnet.attributes.pos.value]; } - // public function - return function(vertices, opt, linkView) { + if (linkView.targetMagnet) { + opt.endDirections = [linkView.targetMagnet.attributes.pos.value]; + } - return router.call(linkView, vertices, _.extend({}, config, opt)); - }; + return router.call(linkView, vertices, _.extend({}, config, opt)); + }; })(g, _, joint); diff --git a/app/scripts/plugins/shapes/joint.shapes.js b/app/scripts/plugins/shapes/joint.shapes.js index 434d99d7d..2fb7a5683 100644 --- a/app/scripts/plugins/shapes/joint.shapes.js +++ b/app/scripts/plugins/shapes/joint.shapes.js @@ -6,19 +6,19 @@ var sha1 = require('sha1'); const DARWIN = Boolean(os.platform().indexOf('darwin') > -1); if (DARWIN) { - var fontSize = '12'; + var aceFontSize = '12'; } else { - var fontSize = '15'; + var aceFontSize = '15'; } // Model element joint.shapes.ice = {}; -joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, { +joint.shapes.ice.Model = joint.shapes.basic.Generic.extend({ - markup: '', - portMarkup: '', + markup: '', + portMarkup: '', defaults: joint.util.deepSupplement({ type: 'ice.Model', @@ -26,8 +26,10 @@ joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.sh width: 1, height: 1 }, - inPorts: [], - outPorts: [], + leftPorts: [], + rightPorts: [], + topPorts: [], + bottomPorts: [], attrs: { gridUnits: 1, '.': { @@ -40,27 +42,30 @@ joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.sh 'fill-opacity': 0 }, '.port-body': { - r: 16, + r: 8, opacity: 0 }, - '.inPorts .port-body': { + '.leftPorts .port-body': { + pos: 'left', type: 'input', magnet: false }, - '.outPorts .port-body': { + '.rightPorts .port-body': { + pos: 'right', type: 'output', magnet: true }, - '.inPorts .port-label': { - x: 12, - y: -10, - 'text-anchor': 'end', - fill: '#888' + '.topPorts .port-body': { + pos: 'top', + type: 'input', + magnet: false }, - '.outPorts .port-label': { - x: -12, - y: -10, - 'text-anchor': 'start', + '.bottomPorts .port-body': { + pos: 'bottom', + type: 'output', + magnet: true + }, + '.port-label': { fill: '#888' }, '.port-wire': { @@ -70,6 +75,35 @@ joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.sh } }, joint.shapes.basic.Generic.prototype.defaults), + + initialize: function() { + this.updatePortsAttrs(); + this.on('change:leftPorts change:rightPorts change:topPorts change:bottomPorts', this.updatePortsAttrs, this); + this.constructor.__super__.constructor.__super__.initialize.apply(this, arguments); + }, + + updatePortsAttrs: function(/*eventName*/) { + if (this._portSelectors) { + var newAttrs = _.omit(this.get('attrs'), this._portSelectors); + this.set('attrs', newAttrs, { silent: true }); + } + this._portSelectors = []; + var attrs = {}; + + _.each(['left', 'right', 'top', 'bottom'], function(type) { + var port = type + 'Ports'; + _.each(this.get(port), function(portName, index, ports) { + var portAttributes = this.getPortAttrs(portName, index, ports.length, '.' + port, type); + this._portSelectors = this._portSelectors.concat(_.keys(portAttributes)); + _.extend(attrs, portAttributes); + }, this); + }, this); + + this.attr(attrs, { silent: true }); + this.processPorts(); + this.trigger('process:ports'); + }, + getPortAttrs: function(port, index, total, selector, type) { var attrs = {}; @@ -80,10 +114,16 @@ joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.sh var portWireSelector = portSelector + '>.port-wire'; var portBodySelector = portSelector + '>.port-body'; + attrs[portSelector] = { + ref: '.body' + }; + attrs[portLabelSelector] = { text: port.label }; + attrs[portWireSelector] = {}; + attrs[portBodySelector] = { port: { id: port.id, @@ -91,91 +131,149 @@ joint.shapes.ice.Model = joint.shapes.basic.Generic.extend(_.extend({}, joint.sh } }; - var portY = (index + 0.5) / total; - - portY = Math.round(portY * port.gridUnits) / port.gridUnits; - - attrs[portSelector] = { - ref: '.body', - 'ref-y': portY - }; - - attrs[portWireSelector] = { - y: portY - }; - - if (type === 'in') { - attrs[portSelector]['ref-x'] = -16; - attrs[portWireSelector]['d'] = 'M 0 0 L 32 0'; + if ((type === 'leftPorts') || (type === 'topPorts')) { attrs[portSelector]['pointer-events'] = 'none'; attrs[portWireSelector]['pointer-events'] = 'none'; } - else { - attrs[portSelector]['ref-dx'] = 16; - attrs[portWireSelector]['d'] = 'M 0 0 L -32 0'; + + var offset = (port.size && port.size > 1) ? 6 : 0; + var pos = Math.round((index + 0.5) / total * port.gridUnits) / port.gridUnits; + + switch (type) { + case 'left': + attrs[portSelector]['ref-x'] = -8; + attrs[portSelector]['ref-y'] = pos; + attrs[portLabelSelector]['dx'] = 4; + attrs[portLabelSelector]['y'] = -5-offset; + attrs[portLabelSelector]['text-anchor'] = 'end'; + attrs[portWireSelector]['y'] = pos; + attrs[portWireSelector]['d'] = 'M 0 0 L 16 0'; + break; + case 'right': + attrs[portSelector]['ref-dx'] = 8; + attrs[portSelector]['ref-y'] = pos; + attrs[portLabelSelector]['dx'] = -4; + attrs[portLabelSelector]['y'] = -5-offset; + attrs[portLabelSelector]['text-anchor'] = 'start'; + attrs[portWireSelector]['y'] = pos; + attrs[portWireSelector]['d'] = 'M 0 0 L -16 0'; + break; + case 'top': + attrs[portSelector]['ref-y'] = -8; + attrs[portSelector]['ref-x'] = pos; + attrs[portLabelSelector]['dx'] = 5+offset; + attrs[portLabelSelector]['y'] = 4; + attrs[portLabelSelector]['text-anchor'] = 'start'; + attrs[portWireSelector]['x'] = pos; + attrs[portWireSelector]['d'] = 'M 0 0 L 0 16'; + break; + case 'bottom': + attrs[portSelector]['ref-dy'] = 8; + attrs[portSelector]['ref-x'] = pos; + attrs[portLabelSelector]['dx'] = 5+offset; + attrs[portLabelSelector]['y'] = -4; + attrs[portLabelSelector]['text-anchor'] = 'start'; + attrs[portWireSelector]['x'] = pos; + attrs[portWireSelector]['d'] = 'M 0 0 L 0 -16'; + break; } return attrs; } -})); +}); joint.shapes.ice.ModelView = joint.dia.ElementView.extend({ - template: '', + template: '', - initialize: function() { - _.bindAll(this, 'updateBox'); - joint.dia.ElementView.prototype.initialize.apply(this, arguments); + initialize: function() { + _.bindAll(this, 'updateBox'); + joint.dia.ElementView.prototype.initialize.apply(this, arguments); - this.$box = $(joint.util.template(this.template)()); + this.$box = $(joint.util.template(this.template)()); - this.model.on('change', this.updateBox, this); - this.model.on('remove', this.removeBox, this); + this.model.on('change', this.updateBox, this); + this.model.on('remove', this.removeBox, this); - this.updateBox(); + this.updateBox(); - this.listenTo(this.model, 'process:ports', this.update); - joint.dia.ElementView.prototype.initialize.apply(this, arguments); - }, - render: function() { - joint.dia.ElementView.prototype.render.apply(this, arguments); - this.paper.$el.append(this.$box); - this.updateBox(); - return this; - }, - renderPorts: function() { - var $inPorts = this.$('.inPorts').empty(); - var $outPorts = this.$('.outPorts').empty(); - var portTemplate = _.template(this.model.portMarkup); + this.listenTo(this.model, 'process:ports', this.update); + joint.dia.ElementView.prototype.initialize.apply(this, arguments); + }, - _.each(_.filter(this.model.ports, function (p) { return p.type === 'in' }), function (port, index) { - $inPorts.append(V(portTemplate({ id: index, port: port })).node); - }); - _.each(_.filter(this.model.ports, function (p) { return p.type === 'out' }), function (port, index) { - $outPorts.append(V(portTemplate({ id: index, port: port })).node); - }); - }, - update: function() { - this.renderPorts(); - joint.dia.ElementView.prototype.update.apply(this, arguments); - }, - updateBox: function() { - var bbox = this.model.getBBox(); - var state = this.model.attributes.state; - - this.$('.port-wire').css('stroke-width', 2 * state.zoom); - - this.$box.css({ - left: bbox.x * state.zoom + state.pan.x + bbox.width / 2.0 * (state.zoom - 1), - top: bbox.y * state.zoom + state.pan.y + bbox.height / 2.0 * (state.zoom - 1), - width: bbox.width, - height: bbox.height, - transform: 'scale(' + state.zoom + ')' - }); - }, - removeBox: function(evt) { - this.$box.remove(); + apply: function() { + // No operation required + }, + + render: function() { + joint.dia.ElementView.prototype.render.apply(this, arguments); + this.paper.$el.append(this.$box); + this.updateBox(); + return this; + }, + + renderPorts: function() { + var $leftPorts = this.$('.leftPorts').empty(); + var $rightPorts = this.$('.rightPorts').empty(); + var $topPorts = this.$('.topPorts').empty(); + var $bottomPorts = this.$('.bottomPorts').empty(); + var portTemplate = _.template(this.model.portMarkup); + + _.each(_.filter(this.model.ports, function(p) { return p.type === 'left'; }), function(port, index) { + $leftPorts.append(V(portTemplate({ id: index, port: port })).node); + }); + _.each(_.filter(this.model.ports, function(p) { return p.type === 'right'; }), function(port, index) { + $rightPorts.append(V(portTemplate({ id: index, port: port })).node); + }); + _.each(_.filter(this.model.ports, function(p) { return p.type === 'top'; }), function(port, index) { + $topPorts.append(V(portTemplate({ id: index, port: port })).node); + }); + _.each(_.filter(this.model.ports, function(p) { return p.type === 'bottom'; }), function(port, index) { + $bottomPorts.append(V(portTemplate({ id: index, port: port })).node); + }); + }, + + update: function() { + this.renderPorts(); + joint.dia.ElementView.prototype.update.apply(this, arguments); + }, + + updateBox: function() { + var port, wireWidth; + var bbox = this.model.getBBox(); + var state = this.model.get('state'); + var leftPorts = this.model.get('leftPorts'); + var rightPorts = this.model.get('rightPorts'); + + // Render ports width + this.$('.port-wire').css('stroke-width', 2 * state.zoom); + for (var i in leftPorts) { + port = leftPorts[i]; + wireWidth = (port.size > 1) ? 8 : 2; + this.$('#port-wire-' + port.id).css('stroke-width', wireWidth * state.zoom); + } + for (var o in rightPorts) { + port = rightPorts[o]; + wireWidth = (port.size > 1) ? 8 : 2; + this.$('#port-wire-' + port.id).css('stroke-width', wireWidth * state.zoom); } + + /*if (this.$box.css('z-index') > this.model.attributes.zindex) { + this.$box.css('z-index', ++this.model.attributes.zindex); + }*/ + + this.$box.css({ + left: bbox.x * state.zoom + state.pan.x + bbox.width / 2.0 * (state.zoom - 1), + top: bbox.y * state.zoom + state.pan.y + bbox.height / 2.0 * (state.zoom - 1), + width: bbox.width, + height: bbox.height, + transform: 'scale(' + state.zoom + ')' + }); + }, + + removeBox: function(/*evt*/) { + this.$box.remove(); + } }); @@ -189,30 +287,86 @@ joint.shapes.ice.Generic = joint.shapes.ice.Model.extend({ joint.shapes.ice.GenericView = joint.shapes.ice.ModelView.extend({ - template: '\ -
    \ - \ - \ -
    \ - ', + template: '\ +
    \ + \ + \ + \ +
    \ + ', + + events: { + 'mouseover': 'mouseovercard', + 'mouseout': 'mouseoutcard', + 'mouseup': 'mouseupcard', + 'mousedown': 'mousedowncard' + }, - initialize: function() { - joint.shapes.ice.ModelView.prototype.initialize.apply(this, arguments); + enter: false, + down: false, + timer: null, - var image = this.model.get('image'); - var name = this.model.get('label'); + mouseovercard: function(/*evt, x, y*/) { + if (this.tooltip) { + this.enter = true; + var self = this; + this.timer = setTimeout(function() { + if (self.enter && !self.down) { + self.tooltiptext.text(self.tooltip); + self.tooltiptext.css('visibility', 'visible'); + if (self.tooltip.length > 30) { + self.tooltiptext.addClass('tooltip-large'); + } + else { + self.tooltiptext.removeClass('tooltip-large'); + } + } + }, 1000); + } + }, - if (image) { - this.$box.find('img').attr('src', image); - this.$box.find('img').removeClass('hidden'); - this.$box.find('label').addClass('hidden'); - } - else { - this.$box.find('label').text(name); - this.$box.find('img').addClass('hidden'); - this.$box.find('label').removeClass('hidden'); + mouseoutcard: function(/*evt, x, y*/) { + if (this.tooltip) { + this.enter = false; + if (this.timer) { + clearTimeout(this.timer); + this.timer = null; } + this.tooltiptext.css('visibility', 'hidden'); + } + }, + + mouseupcard: function(/*evt, x, y*/) { + this.down = false; + }, + + mousedowncard: function(/*evt, x, y*/) { + this.down = true; + this.mouseoutcard(); + }, + + initialize: function() { + joint.shapes.ice.ModelView.prototype.initialize.apply(this, arguments); + + var image = this.model.get('image'); + var name = this.model.get('label'); + this.tooltip = this.model.get('tooltip'); + this.tooltiptext = this.$box.find('.tooltiptext'); + + if (image) { + this.$box.find('img').attr('src', 'data:image/svg+xml,' + image); + this.$box.find('img').removeClass('hidden'); + this.$box.find('label').addClass('hidden'); } + else { + this.$box.find('label').html(name); + this.$box.find('img').addClass('hidden'); + this.$box.find('label').removeClass('hidden'); + } + if (this.model.get('config')) { + this.$box.addClass('config-block'); + } + } }); // I/O blocks @@ -220,12 +374,6 @@ joint.shapes.ice.GenericView = joint.shapes.ice.ModelView.extend({ joint.shapes.ice.Input = joint.shapes.ice.Model.extend({ defaults: joint.util.deepSupplement({ type: 'ice.Input', - choices: [], - outPorts: [{ - id: "out", - label: "", - gridUnits: 8 - }], size: { width: 96, height: 64 @@ -236,12 +384,6 @@ joint.shapes.ice.Input = joint.shapes.ice.Model.extend({ joint.shapes.ice.Output = joint.shapes.ice.Model.extend({ defaults: joint.util.deepSupplement({ type: 'ice.Output', - choices: [], - inPorts: [{ - id: "in", - label: "", - gridUnits: 8 - }], size: { width: 96, height: 64 @@ -252,79 +394,254 @@ joint.shapes.ice.Output = joint.shapes.ice.Model.extend({ joint.shapes.ice.IOView = joint.shapes.ice.ModelView.extend({ - template: '\ -
    \ - \ - \ - \ -
    \ - ', - - initialize: function() { - joint.shapes.ice.ModelView.prototype.initialize.apply(this, arguments); - - // Prevent paper from handling pointerdown. - this.$box.find('.io-combo').on('mousedown click', function(evt) { evt.stopPropagation(); }); - - this.$box.find('.io-combo').on('change', _.bind(function(evt) { - this.model.attributes.data.pin.name = $(evt.target).find("option:selected").text(); - this.model.attributes.data.pin.value = $(evt.target).val(); - }, this)); - }, - renderLabel: function () { - var name = this.model.attributes.data.label; - this.$box.find('label').text(name); - }, - renderChoices: function() { - if (this.model.get('disabled')) { - this.$box.find('.io-combo').removeClass('select2'); - this.$box.find('.io-combo').css({'display': 'none'}); + initialize: function() { + joint.shapes.ice.ModelView.prototype.initialize.apply(this, arguments); + + this.id = sha1(this.model.get('id')).toString().substring(0, 6); + var virtualPortId = 'virtualPort' + this.id; + var fpgaPortId = 'fpgaPort' + this.id; + var comboId = 'combo' + this.id; + var virtual = this.model.get('data').virtual || this.model.get('disabled'); + + var selectCode = ''; + var selectScript = ''; + var data = this.model.get('data'); + var name = data.name + (data.range || ''); + + if (data.pins) { + for (var i in data.pins) { + //selectCode += '

    ' + this.pins[i].index + '

    '; + selectCode +=''; + + selectScript += '$("#' + comboId + data.pins[i].index + '").select2('; + selectScript += '{placeholder: "", allowClear: true, dropdownCssClass: "bigdrop"});'; } - else { - var choices = this.model.get('choices'); - var $select = this.$box.find('.io-combo').empty(); + } - $select.append(''); - for (var c in choices) { - $select.append(''); + this.$box = $(joint.util.template( + '\ +
    \ + \ +
    \ +
    \ + \ +
    ' + selectCode + '
    \ + \ +
    \ + ' + )()); + + this.updating = false; + + // Prevent paper from handling pointerdown. + var self = this; + var comboSelector = this.$box.find('.select2'); + comboSelector.on('mousedown click', function(evt) { evt.stopPropagation(); }); + comboSelector.on('change', function(evt) { + if (!self.updating) { + var target = $(evt.target); + var i = target.attr('i'); + var name = target.find('option:selected').text(); + var value = target.val(); + var data = JSON.parse(JSON.stringify(self.model.get('data'))); + if (name !== null && value !== null) { + data.pins[i].name = name; + data.pins[i].value = value; + self.model.set('data', data); } + } + }); - if (this.model.get('data').pin) { - this.$box.find('.io-combo').val(this.model.get('data').pin.value); - } + // Apply data + if (!this.model.get('disabled')) { + this.applyChoices(); + this.applyValues(); + this.applyShape(); + } + }, + + applyShape: function() { + var virtualPortId = '#virtualPort' + this.id; + var fpgaPortId = '#fpgaPort' + this.id; + var data = this.model.get('data'); + var name = data.name + (data.range || ''); + var virtual = data.virtual || this.model.get('disabled'); + + this.$box.find('label').text(name || ''); + + if (virtual) { + // Virtual port (green) + $(fpgaPortId).addClass('hidden'); + $(virtualPortId).removeClass('hidden'); + this.model.attributes.size.height = 64; + } + else { + // FPGA I/O port (yellow) + $(virtualPortId).addClass('hidden'); + $(fpgaPortId).removeClass('hidden'); + if (data.pins) { + this.model.attributes.size.height = 32 + 32 * data.pins.length; } - }, - clearValue: function () { - this.model.attributes.data.pin.name = ''; - this.model.attributes.data.pin.value = 0; - this.$box.find('.io-combo').val(''); - }, - update: function () { - this.renderLabel(); - this.renderPorts(); - this.renderChoices(); - joint.dia.ElementView.prototype.update.apply(this, arguments); } + }, + + applyChoices: function() { + var data = this.model.get('data'); + if (data.pins) { + for (var i in data.pins) { + this.$box.find('#combo' + this.id + data.pins[i].index).empty().append(this.model.get('choices')); + } + } + }, + + applyValues: function() { + this.updating = true; + var data = this.model.get('data'); + for (var i in data.pins) { + var index = data.pins[i].index; + var comboId = '#combo' + this.id + index; + var comboSelector = this.$box.find(comboId); + var value = data.pins[i].value; + comboSelector.val(value).change(); + } + this.updating = false; + }, + + clearValues: function() { + this.updating = true; + var name = ''; + var value = 0; + var data = JSON.parse(JSON.stringify(this.model.get('data'))); + for (var i in data.pins) { + var index = data.pins[i].index; + var comboId = '#combo' + this.id + index; + var comboSelector = this.$box.find(comboId); + comboSelector.val(value).change(); + data.pins[i].name = name; + data.pins[i].value = value; + } + this.model.set('data', data); + this.updating = false; + }, + + computeFontSize: function(name) { + var n = name.length; + return Math.min(13, 17-n).toString() + 'px'; + }, + + apply: function() { + this.applyChoices(); + this.applyValues(); + this.applyShape(); + this.render(); + }, + + update: function() { + this.renderPorts(); + joint.dia.ElementView.prototype.update.apply(this, arguments); + } }); joint.shapes.ice.InputView = joint.shapes.ice.IOView; joint.shapes.ice.OutputView = joint.shapes.ice.IOView; +// Constant blocks + +joint.shapes.ice.Constant = joint.shapes.ice.Model.extend({ + defaults: joint.util.deepSupplement({ + type: 'ice.Constant', + size: { + width: 96, + height: 64 + } + }, joint.shapes.ice.Model.prototype.defaults) +}); + + +joint.shapes.ice.ConstantView = joint.shapes.ice.ModelView.extend({ + + template: '\ +
    \ +

    *

    \ + \ + \ +
    \ + ', + + initialize: function() { + joint.shapes.ice.ModelView.prototype.initialize.apply(this, arguments); + + this.updating = false; + + // Prevent paper from handling pointerdown. + var self = this; + this.$box.find('.constant-input').on('mousedown click', function(evt) { evt.stopPropagation(); }); + this.$box.find('.constant-input').on('input', function(evt) { + if (!self.updating) { + var target = $(evt.target); + var data = JSON.parse(JSON.stringify(self.model.get('data'))); + data.value = target.val(); + self.model.set('data', data); + } + }); + + // Apply data + this.apply(); + }, + + applyName: function() { + var name = this.model.get('data').name; + this.$box.find('label').text(name); + }, + + applyValue: function() { + this.updating = true; + if (this.model.get('disabled')) { + this.$box.find('.constant-input').css({'pointer-events': 'none'}); + } + var value = this.model.get('data').value; + this.$box.find('.constant-input').val(value); + this.updating = false; + }, + + applyLocal: function() { + if (this.model.get('data').local) { + this.$box.find('p').removeClass('hidden'); + } + else { + this.$box.find('p').addClass('hidden'); + } + }, + + apply: function() { + this.applyName(); + this.applyValue(); + this.applyLocal(); + }, + + update: function() { + this.renderPorts(); + joint.dia.ElementView.prototype.update.apply(this, arguments); + } +}); + + // Code block +// Size: 64 * x joint.shapes.ice.Code = joint.shapes.ice.Model.extend({ defaults: joint.util.deepSupplement({ type: 'ice.Code', size: { - width: 400, + width: 384, height: 256 }, attrs: { '.body': { - width: 400, + width: 384, height: 256 } } @@ -333,70 +650,146 @@ joint.shapes.ice.Code = joint.shapes.ice.Model.extend({ joint.shapes.ice.CodeView = joint.shapes.ice.ModelView.extend({ - initialize: function() { - _.bindAll(this, 'updateBox'); - joint.dia.ElementView.prototype.initialize.apply(this, arguments); - - var id = sha1(this.model.get('id')).toString().substring(0, 6); - var blockLabel = 'block' + id; - var editorLabel = 'editor' + id; - var contentLabel = 'content' + id; - this.$box = $(joint.util.template( - '\ -
    \ -
    \ - \ - \ -
    \ - ' - )()); - - this.model.on('change', this.updateBox, this); - this.model.on('remove', this.removeBox, this); - - this.updateBox(); - - this.listenTo(this.model, 'process:ports', this.update); - joint.dia.ElementView.prototype.initialize.apply(this, arguments); - - // Prevent paper from handling pointerdown. - this.$box.find('#' + editorLabel).on('mousedown click', function(evt) { evt.stopPropagation(); }); - - this.$box.find('#' + editorLabel).append(this.model.attributes.data.code); - this.$box.find('#' + contentLabel).append(this.model.attributes.data.code); - }, - update: function () { - this.renderPorts(); - var id = sha1(this.model.get('id')).toString().substring(0, 6); - var editorLabel = 'editor' + id; - var editor = ace.edit(this.$box.find('#' + editorLabel)[0]); - editor.setReadOnly(this.model.get('disabled')); - joint.dia.ElementView.prototype.update.apply(this, arguments); - }, - updateBox: function() { - var bbox = this.model.getBBox(); - var state = this.model.attributes.state; + initialize: function() { + _.bindAll(this, 'updateBox'); + joint.dia.ElementView.prototype.initialize.apply(this, arguments); + + var id = sha1(this.model.get('id')).toString().substring(0, 6); + var blockLabel = 'block' + id; + var editorLabel = 'editor' + id; + this.$box = $(joint.util.template( + '\ +
    \ +
    \ + \ +
    \ + ' + )()); + + this.model.on('change', this.updateBox, this); + this.model.on('remove', this.removeBox, this); + + this.updateBox(); + this.updating = false; + + this.listenTo(this.model, 'process:ports', this.update); + joint.dia.ElementView.prototype.initialize.apply(this, arguments); + + var selector = this.$box.find('#' + editorLabel); + + // Prevent paper from handling pointerdown. + selector.on('mousedown click', function(evt) { evt.stopPropagation(); }); + + this.deltas = []; + this.counter = 0; + this.timer = null; + var undoGroupingInterval = 200; + + var self = this; + this.editor = ace.edit(selector[0]); + this.editor.$blockScrolling = Infinity; + this.editor.commands.removeCommand('undo'); + this.editor.commands.removeCommand('redo'); + this.editor.session.on('change', function(delta) { + if (!self.updating) { + // Check consecutive-change interval + if (Date.now() - self.counter < undoGroupingInterval) { + clearTimeout(self.timer); + } + // Update deltas + self.deltas = self.deltas.concat([delta]); + // Launch timer to + self.timer = setTimeout(function() { + var data = JSON.parse(JSON.stringify(self.model.get('data'))); + // Set data + data.code = self.editor.session.getValue(); + data.deltas = self.deltas; + self.model.set('data', data); + // Reset deltas + self.deltas = []; + }, undoGroupingInterval); + // Reset counter + self.counter = Date.now(); + } + }); + this.editor.on('focus', function() { + $(document).trigger('disableSelected'); + }); + $('#' + blockLabel).resize(function() { + self.editor.resize(); + }); + + // Apply data + this.apply(); + }, - this.$('.port-wire').css('stroke-width', 2 * state.zoom); + applyValue: function(opt) { + this.updating = true; + var dontselect = false; + var data = this.model.get('data'); + if (data.deltas && opt) { + var changes = [{ + group: 'doc', + deltas: data.deltas + }]; + if (opt.undo) { + this.editor.session.undoChanges(changes, dontselect); + } + else { + this.editor.session.redoChanges(changes, dontselect); + } + } + else { + this.editor.session.setValue(data.code); + } + setTimeout(function(self) { + self.updating = false; + }, 10, this); + }, + + apply: function(opt) { + this.applyValue(opt); + }, + + update: function() { + this.renderPorts(); + this.editor.setReadOnly(this.model.get('disabled')); + joint.dia.ElementView.prototype.update.apply(this, arguments); + }, - this.$box.css({ width: bbox.width * state.zoom, - height: bbox.height * state.zoom, - left: bbox.x * state.zoom + state.pan.x, - top: bbox.y * state.zoom + state.pan.y }); + updateBox: function() { + var port, wireWidth; + var bbox = this.model.getBBox(); + var state = this.model.get('state'); + var leftPorts = this.model.get('leftPorts'); + var rightPorts = this.model.get('rightPorts'); + + // Render ports width + this.$('.port-wire').css('stroke-width', 2 * state.zoom); + for (var i in leftPorts) { + port = leftPorts[i]; + wireWidth = (port.size > 1) ? 8 : 2; + this.$('#port-wire-' + port.id).css('stroke-width', wireWidth * state.zoom); } + for (var o in rightPorts) { + port = rightPorts[o]; + wireWidth = (port.size > 1) ? 8 : 2; + this.$('#port-wire-' + port.id).css('stroke-width', wireWidth * state.zoom); + } + + this.$box.css({ width: bbox.width * state.zoom, + height: bbox.height * state.zoom, + left: bbox.x * state.zoom + state.pan.x, + top: bbox.y * state.zoom + state.pan.y }); + // 'border-width': 2 * state.zoom: problem int instead of float + } }); @@ -424,72 +817,142 @@ joint.shapes.ice.Info = joint.shapes.basic.Rect.extend({ joint.shapes.ice.InfoView = joint.dia.ElementView.extend({ - initialize: function() { - _.bindAll(this, 'updateBox'); - joint.dia.ElementView.prototype.initialize.apply(this, arguments); - - var id = sha1(this.model.get('id')).toString().substring(0, 6); - var blockLabel = 'block' + id; - var editorLabel = 'editor' + id; - var contentLabel = 'content' + id; - this.$box = $(joint.util.template( - '\ -
    \ -
    \ - \ - \ -
    \ - ' - )()); - - this.model.on('change', this.updateBox, this); - this.model.on('remove', this.removeBox, this); - - this.updateBox(); - - // Prevent paper from handling pointerdown. - this.$box.find('#' + editorLabel).on('mousedown click', function(evt) { evt.stopPropagation(); }); - - this.$box.find('#' + editorLabel).append(this.model.attributes.data.info); - this.$box.find('#' + contentLabel).append(this.model.attributes.data.info); - }, - render: function () { - joint.dia.ElementView.prototype.render.apply(this, arguments); - this.paper.$el.append(this.$box); - this.updateBox(); - return this; - }, - update: function () { - var id = sha1(this.model.get('id')).toString().substring(0, 6); - var editorLabel = 'editor' + id; - var editor = ace.edit(this.$box.find('#' + editorLabel)[0]); - editor.setReadOnly(this.model.get('disabled')); - joint.dia.ElementView.prototype.update.apply(this, arguments); - }, - updateBox: function() { - var bbox = this.model.getBBox(); - var state = this.model.attributes.state; - - this.$box.css({ width: bbox.width * state.zoom, - height: bbox.height * state.zoom, - left: bbox.x * state.zoom + state.pan.x, - top: bbox.y * state.zoom + state.pan.y }); - }, - removeBox: function(evt) { - this.$box.remove(); + initialize: function() { + _.bindAll(this, 'updateBox'); + joint.dia.ElementView.prototype.initialize.apply(this, arguments); + + var id = sha1(this.model.get('id')).toString().substring(0, 6); + var blockLabel = 'block' + id; + var editorLabel = 'editor' + id; + this.$box = $(joint.util.template( + '\ +
    \ +
    \ + \ +
    \ + ' + )()); + + this.model.on('change', this.updateBox, this); + this.model.on('remove', this.removeBox, this); + + this.updateBox(); + this.updating = false; + + var selector = this.$box.find('#' + editorLabel); + + // Prevent paper from handling pointerdown. + selector.on('mousedown click', function(evt) { evt.stopPropagation(); }); + + this.deltas = []; + this.counter = 0; + this.timer = null; + var undoGroupingInterval = 200; + + var self = this; + this.editor = ace.edit(selector[0]); + this.editor.$blockScrolling = Infinity; + this.editor.commands.removeCommand('undo'); + this.editor.commands.removeCommand('redo'); + this.editor.session.on('change', function(delta) { + if (!self.updating) { + // Check consecutive-change interval + if (Date.now() - self.counter < undoGroupingInterval) { + clearTimeout(self.timer); + } + // Update deltas + self.deltas = self.deltas.concat([delta]); + // Launch timer to + self.timer = setTimeout(function() { + // Set data + var data = { + info: self.editor.session.getValue(), + deltas: self.deltas + }; + self.model.set('data', data); + // Reset deltas + self.deltas = []; + }, undoGroupingInterval); + // Reset counter + self.counter = Date.now(); + } + }); + this.editor.on('focus', function() { + $(document).trigger('disableSelected'); + }); + $('#' + blockLabel).resize(function() { + self.editor.resize(); + }); + + // Apply data + this.apply(); + }, + + applyValue: function(opt) { + this.updating = true; + var dontselect = false; + var data = this.model.get('data'); + if (data.deltas && opt) { + var changes = [{ + group: 'doc', + deltas: data.deltas + }]; + if (opt.undo) { + this.editor.session.undoChanges(changes, dontselect); + } + else { + this.editor.session.redoChanges(changes, dontselect); + } + } + else { + this.editor.session.setValue(data.info); } + setTimeout(function(self) { + self.updating = false; + }, 10, this); + }, + + apply: function(opt) { + this.applyValue(opt); + }, + + render: function() { + joint.dia.ElementView.prototype.render.apply(this, arguments); + this.paper.$el.append(this.$box); + this.updateBox(); + return this; + }, + + update: function() { + this.editor.setReadOnly(this.model.get('disabled')); + joint.dia.ElementView.prototype.update.apply(this, arguments); + }, + + updateBox: function() { + var bbox = this.model.getBBox(); + var state = this.model.get('state'); + + this.$box.css({ width: bbox.width * state.zoom, + height: bbox.height * state.zoom, + left: bbox.x * state.zoom + state.pan.x, + top: bbox.y * state.zoom + state.pan.y }); + }, + + remove: function() { + // Remove delta to allow Session Value restore + delete this.model.attributes.data.delta; + joint.dia.LinkView.prototype.remove.apply(this, arguments); + }, + + removeBox: function(/*evt*/) { + this.$box.remove(); + } }); @@ -511,7 +974,7 @@ joint.shapes.ice.Wire = joint.dia.Link.extend({ bifurcationMarkup: [ '', - '', + '', '' ].join(''), @@ -525,18 +988,19 @@ joint.shapes.ice.Wire = joint.dia.Link.extend({ type: 'ice.Wire', - /*labels: [ + labels: [ { - position: .5, + position: 0.5, attrs: { text: { - text: ' /8 ' || '', + text: '', 'font-weight': 'bold', - 'font-size': '150%' + 'font-size': '150%', + 'y': '12px' } } } - ],*/ + ], attrs: { '.connection': { @@ -555,6 +1019,34 @@ joint.shapes.ice.Wire = joint.dia.Link.extend({ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ + initialize: function() { + joint.dia.LinkView.prototype.initialize.apply(this, arguments); + + var self = this; + setTimeout(function() { + var portName = self.model.get('source').port; + var rightPorts = self.sourceView.model.get('rightPorts'); + + // Initialize wire properties + var port; + for (var o in rightPorts) { + port = rightPorts[o]; + if (portName === port.id) { + self.model.attributes.size = port.size; // For wire size connection validation + self.$('.connection').css('stroke-width', (port.size > 1) ? 8 : 2); + self.model.label(0, {attrs: { text: { text: (port.size > 1) ? '' + port.size + '' : '' } } }); + self.model.bifurcationMarkup = self.model.bifurcationMarkup.replace(/<%= r %>/g, (port.size > 1) ? 8 : 4); + self.update(); + break; + } + } + }, 0); + }, + + apply: function() { + this.render(); + }, + render: function() { joint.dia.LinkView.prototype.render.apply(this, arguments); // console.log('render'); @@ -607,7 +1099,9 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ // The markup needs to contain a `.connection` this._V.connection.attr('d', pathData.full); - this._V.connectionWrap && this._V.connectionWrap.attr('d', pathData.wrap); + if(this._V.connectionWrap) { + this._V.connectionWrap.attr('d', pathData.wrap); + } this._translateAndAutoOrientArrows(this._V.markerSource, this._V.markerTarget); }, @@ -621,15 +1115,17 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ // Find all the wires in the same port var portWires = []; _.each(allWires, function(wire) { - if ((wire.attributes.source.id == currentWire.attributes.source.id) && - (wire.attributes.source.port == currentWire.attributes.source.port)) + var wireSource = wire.get('source'); + var cwireSource = currentWire.get('source'); + if ((wireSource.id === cwireSource.id) && + (wireSource.port === cwireSource.port)) { // Wire with the same source of currentWire var wireView = self.paper.findViewByModel(wire); // Clean the wire bifurcations var markerBifurcations = $(wireView._V.markerBifurcations.node).empty(); portWires.push({ - id: wire.attributes.id, + id: wire.get('id'), view: wireView, markers: markerBifurcations }); @@ -644,7 +1140,7 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ ); _.each(portWires, function(wireA) { _.each(portWires, function(wireB) { - if (wireA.id != wireB.id) { + if (wireA.id !== wireB.id) { // Not the same wire findBifurcations(wireA.view, wireB.view, wireA.markers); } @@ -652,6 +1148,8 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ }); } + /* jshint -W082 */ + function findBifurcations(wireA, wireB, markersA) { // Find the corners in A that intersects with any B segment var vA = v(wireA); @@ -659,7 +1157,7 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ if (vA.length > 2) { for (var i = 1; i < vA.length - 1; i++) { - if ((vA[i-1].x != vA[i+1].x) && (vA[i-1].y != vA[i+1].y)) { + if ((vA[i-1].x !== vA[i+1].x) && (vA[i-1].y !== vA[i+1].y)) { // vA[i] is a corner for (var j = 0; j < vB.length - 1; j++) { // Eval if intersects any segment of wire vB @@ -682,21 +1180,23 @@ joint.shapes.ice.WireView = joint.dia.LinkView.extend({ } function evalIntersection(point, segment) { - if (segment[0].x == segment[1].x) { + if (segment[0].x === segment[1].x) { // Vertical - return ((point.x == segment[0].x) && + return ((point.x === segment[0].x) && (point.y > Math.min(segment[0].y, segment[1].y)) && (point.y < Math.max(segment[0].y, segment[1].y))); } else { // Horizontal - return ((point.y == segment[0].y) && + return ((point.y === segment[0].y) && (point.x > Math.min(segment[0].x, segment[1].x)) && (point.x < Math.max(segment[0].x, segment[1].x))); } } } + /* jshint +W082 */ + return this; } diff --git a/app/scripts/plugins/ui/joint.ui.js b/app/scripts/plugins/ui/joint.ui.js index b8846cd28..9bac273e7 100644 --- a/app/scripts/plugins/ui/joint.ui.js +++ b/app/scripts/plugins/ui/joint.ui.js @@ -1,319 +1,283 @@ -/*! JointJS+ - Set of JointJS compatible plugins - +/* +Copyright (c) 2016-2017 FPGAwars Copyright (c) 2013 client IO +*/ -Adapted to Icestudio Project. 2016 - -This Source Code Form is subject to the terms of the JointJS+ License -, v. 1.0. If a copy of the JointJS+ License was not distributed with this -file, You can obtain one at http://jointjs.com/license/jointjs_plus_v1.txt - or from the JointJS+ archive as was distributed by client IO. See the LICENSE file.*/ - - -// SelectionView -// ============= - -// `SelectionView` implements selecting group of elements and moving the selected elements in one go. -// Typically, the selection will be bound to the `Shift` key -// and selecting/deselecting individual elements to the `Ctrl` key. - -// Example usage: - -// var graph = new joint.dia.Graph; -// var paper = new joint.dia.Paper({ model: graph }); -// var selection = new Backbone.Collection; -// var selectionView = new joint.ui.SelectionView({ paper: paper, graph: graph, model: selection }); - -// // Bulk selecting group of elements by creating a rectangular selection area. -// paper.on('blank:pointerdown', selectionView.startSelecting); -// // Selecting individual elements with click and the `Ctrl`/`Command` key. -// paper.on('cell:pointerup', function(cellView, evt) { -// if ((evt.ctrlKey || evt.metaKey) && !(cellView.model instanceof joint.dia.Link)) { -// selectionView.createSelectionBox(cellView); -// selection.add(cellView.model); -// } -// }); - -// // Deselecting previously selected elements with click and the `Ctrl`/`Command` key. -// selectionView.on('selection-box:pointerdown', function(evt) { -// if (evt.ctrlKey || evt.metaKey) { -// var cell = selection.get($(evt.target).data('model')); -// selectionView.destroySelectionBox(paper.findViewByModel(cell)); -// selection.reset(selection.without(cell)); -// } -// }); +'use strict'; joint.ui.SelectionView = Backbone.View.extend({ - className: 'selectionarea', + className: 'selectionarea', - events: { + events: { - 'mousedown .selection-box': 'startTranslatingSelection' - }, + 'mousedown .selection-box': 'startTranslatingSelection' + }, - initialize: function(options) { + initialize: function(options) { - _.bindAll(this, 'startSelecting', 'stopSelecting', 'adjustSelection'); + _.bindAll(this, 'startSelecting', 'stopSelecting', 'adjustSelection'); - $(document.body).on('mouseup touchend', this.stopSelecting); - $(document.body).on('mousemove touchmove', this.adjustSelection); + $(document.body).on('mouseup touchend', this.stopSelecting); + $(document.body).on('mousemove touchmove', this.adjustSelection); - this.options = options; + this.options = options; - this.options.paper.$el.append(this.$el); - }, + this.options.paper.$el.append(this.$el); + }, - startTranslatingSelection: function(evt) { + startTranslatingSelection: function(evt) { - this._action = 'translating'; + this._action = 'translating'; - this.options.graph.trigger('batch:start'); + this.options.graph.trigger('batch:start'); - var snappedClientCoords = this.options.paper.snapToGrid(g.point(evt.clientX, evt.clientY)); - this._snappedClientX = snappedClientCoords.x; - this._snappedClientY = snappedClientCoords.y; + var snappedClientCoords = this.options.paper.snapToGrid(g.point(evt.clientX, evt.clientY)); + this._snappedClientX = snappedClientCoords.x; + this._snappedClientY = snappedClientCoords.y; - this.trigger('selection-box:pointerdown', evt); + this.trigger('selection-box:pointerdown', evt); - evt.stopPropagation(); - }, + evt.stopPropagation(); + }, - isTranslating: function() { + isTranslating: function() { - return this._action == 'translating'; - }, + return this._action === 'translating'; + }, - startSelecting: function(evt, x, y) { + startSelecting: function(evt/*, x, y*/) { - this.$el.removeClass('selected'); - this.$el.empty(); - this.model.reset([]); + this.$el.removeClass('selected'); + this.$el.empty(); + this.model.reset([]); - this._action = 'selecting'; + this._action = 'selecting'; - this._clientX = evt.clientX; - this._clientY = evt.clientY; + this._clientX = evt.clientX; + this._clientY = evt.clientY; - // Normalize `evt.offsetX`/`evt.offsetY` for browsers that don't support it (Firefox). - var paperElement = evt.target.parentElement || evt.target.parentNode; - var paperOffset = $(paperElement).offset(); - var paperScrollLeft = paperElement.scrollLeft; - var paperScrollTop = paperElement.scrollTop; + // Normalize `evt.offsetX`/`evt.offsetY` for browsers that don't support it (Firefox). + var paperElement = evt.target.parentElement || evt.target.parentNode; + var paperOffset = $(paperElement).offset(); + var paperScrollLeft = paperElement.scrollLeft; + var paperScrollTop = paperElement.scrollTop; - this._offsetX = evt.offsetX === undefined ? evt.clientX - paperOffset.left + window.pageXOffset + paperScrollLeft : evt.offsetX; - this._offsetY = evt.offsetY === undefined ? evt.clientY - paperOffset.top + window.pageYOffset + paperScrollTop : evt.offsetY; + this._offsetX = evt.offsetX === undefined ? evt.clientX - paperOffset.left + window.pageXOffset + paperScrollLeft : evt.offsetX; + this._offsetY = evt.offsetY === undefined ? evt.clientY - paperOffset.top + window.pageYOffset + paperScrollTop : evt.offsetY; - this.$el.css({ - width: 1, - height: 1, - left: this._offsetX, - top: this._offsetY + this.$el.css({ + width: 1, + height: 1, + left: this._offsetX, + top: this._offsetY - }).show(); - }, + }).show(); + }, - adjustSelection: function(evt) { + adjustSelection: function(evt) { - var dx; - var dy; + var dx; + var dy; - switch (this._action) { + switch (this._action) { - case 'selecting': + case 'selecting': - dx = evt.clientX - this._clientX; - dy = evt.clientY - this._clientY; + dx = evt.clientX - this._clientX; + dy = evt.clientY - this._clientY; - var left = parseInt(this.$el.css('left'), 10); - var top = parseInt(this.$el.css('top'), 10); + var left = parseInt(this.$el.css('left'), 10); + var top = parseInt(this.$el.css('top'), 10); - this.$el.css({ - left: dx < 0 ? this._offsetX + dx : left, - top: dy < 0 ? this._offsetY + dy : top, - width: Math.abs(dx), - height: Math.abs(dy) - }); - break; + this.$el.css({ + left: dx < 0 ? this._offsetX + dx : left, + top: dy < 0 ? this._offsetY + dy : top, + width: Math.abs(dx), + height: Math.abs(dy) + }); + break; - case 'translating': + case 'translating': - var snappedClientCoords = this.options.paper.snapToGrid(g.point(evt.clientX, evt.clientY)); - var snappedClientX = snappedClientCoords.x; - var snappedClientY = snappedClientCoords.y; + var snappedClientCoords = this.options.paper.snapToGrid(g.point(evt.clientX, evt.clientY)); + var snappedClientX = snappedClientCoords.x; + var snappedClientY = snappedClientCoords.y; - dx = snappedClientX - this._snappedClientX; - dy = snappedClientY - this._snappedClientY; + dx = snappedClientX - this._snappedClientX; + dy = snappedClientY - this._snappedClientY; - // This hash of flags makes sure we're not adjusting vertices of one link twice. - // This could happen as one link can be an inbound link of one element in the selection - // and outbound link of another at the same time. - var processedLinks = {}; + // This hash of flags makes sure we're not adjusting vertices of one link twice. + // This could happen as one link can be an inbound link of one element in the selection + // and outbound link of another at the same time. + var processedLinks = {}; - this.model.each(function(element) { + this.model.each(function(element) { - // TODO: snap to grid. + // TODO: snap to grid. - // Translate the element itself. - element.translate(dx, dy); + // Translate the element itself. + element.translate(dx, dy); - // Translate also the `selection-box` of the element. - this.updateBox(element); + // Translate also the `selection-box` of the element. + this.updateBox(element); - // Translate link vertices as well. - var connectedLinks = this.options.graph.getConnectedLinks(element); + // Translate link vertices as well. + var connectedLinks = this.options.graph.getConnectedLinks(element); - _.each(connectedLinks, function(link) { + _.each(connectedLinks, function(link) { - if (processedLinks[link.id]) return; + if (processedLinks[link.id]) { + return; + } - var vertices = link.get('vertices'); - if (vertices && vertices.length) { + var vertices = link.get('vertices'); + if (vertices && vertices.length) { - var newVertices = []; - _.each(vertices, function(vertex) { + var newVertices = []; + _.each(vertices, function(vertex) { - newVertices.push({ x: vertex.x + dx, y: vertex.y + dy }); - }); + newVertices.push({ x: vertex.x + dx, y: vertex.y + dy }); + }); - link.set('vertices', newVertices); - } + link.set('vertices', newVertices); + } - processedLinks[link.id] = true; - }); + processedLinks[link.id] = true; + }); - }, this); + }, this); - if (dx || dy) { + if (dx || dy) { - this._snappedClientX = snappedClientX; - this._snappedClientY = snappedClientY; - } + this._snappedClientX = snappedClientX; + this._snappedClientY = snappedClientY; + } - break; - } - }, + break; + } + }, - stopSelecting: function() { + stopSelecting: function() { - switch (this._action) { + switch (this._action) { - case 'selecting': + case 'selecting': - var offset = this.$el.offset(); - var width = this.$el.width(); - var height = this.$el.height(); + var offset = this.$el.offset(); + var width = this.$el.width(); + var height = this.$el.height(); - // Convert offset coordinates to the local point of the root element. - var localPoint = V(this.options.paper.svg).toLocalPoint(offset.left, offset.top); + // Convert offset coordinates to the local point of the root element. + var localPoint = V(this.options.paper.svg).toLocalPoint(offset.left, offset.top); - // Take page scroll into consideration. - localPoint.x -= window.pageXOffset; - localPoint.y -= window.pageYOffset; + // Take page scroll into consideration. + localPoint.x -= window.pageXOffset; + localPoint.y -= window.pageYOffset; - var elementViews = this.options.paper.findViewsInArea( - g.rect( - (localPoint.x - this.options.state.pan.x) / this.options.state.zoom, - (localPoint.y - this.options.state.pan.y) / this.options.state.zoom, - width / this.options.state.zoom, - height / this.options.state.zoom - )); + var elementViews = this.options.paper.findViewsInArea( + g.rect( + (localPoint.x - this.options.state.pan.x) / this.options.state.zoom, + (localPoint.y - this.options.state.pan.y) / this.options.state.zoom, + width / this.options.state.zoom, + height / this.options.state.zoom + )); - if (elementViews.length) { + if (elementViews.length) { - // Create a `selection-box` `
    ` for each element covering its bounding box area. - _.each(elementViews, this.createSelectionBox, this); + // Create a `selection-box` `
    ` for each element covering its bounding box area. + _.each(elementViews, this.createSelectionBox, this); - // The root element of the selection switches `position` to `static` when `selected`. This - // is neccessary in order for the `selection-box` coordinates to be relative to the - // `paper` element, not the `selection` `
    `. - this.$el.addClass('selected'); + // The root element of the selection switches `position` to `static` when `selected`. This + // is neccessary in order for the `selection-box` coordinates to be relative to the + // `paper` element, not the `selection` `
    `. + this.$el.addClass('selected'); - } else { + } else { - // Hide the selection box if there was no element found in the area covered by the - // selection box. - this.$el.hide(); - } + // Hide the selection box if there was no element found in the area covered by the + // selection box. + this.$el.hide(); + } - this.model.reset(_.pluck(elementViews, 'model')); - break; + this.model.reset(_.pluck(elementViews, 'model')); + break; - case 'translating': + case 'translating': - this.options.graph.trigger('batch:stop'); - // Everything else is done during the translation. - break; + this.options.graph.trigger('batch:stop'); + // Everything else is done during the translation. + break; - case 'cherry-picking': - // noop; All is done in the `createSelectionBox()` function. - // This is here to avoid removing selection boxes as a reaction on mouseup event and - // propagating to the `default` branch in this switch. - break; + case 'cherry-picking': + // noop; All is done in the `createSelectionBox()` function. + // This is here to avoid removing selection boxes as a reaction on mouseup event and + // propagating to the `default` branch in this switch. + break; - default: - // Hide selection if the user clicked somehwere else in the document. - // this.$el.hide().empty(); - // this.model.reset([]); - break; - } + default: + // Hide selection if the user clicked somehwere else in the document. + // this.$el.hide().empty(); + // this.model.reset([]); + break; + } - delete this._action; - }, + delete this._action; + }, - cancelSelection: function() { + cancelSelection: function() { - this.$('.selection-box').remove(); - this.$el.hide().removeClass('selected'); - this.model.reset([]); - }, + this.$('.selection-box').remove(); + this.$el.hide().removeClass('selected'); + this.model.reset([]); + }, - destroySelectionBox: function(elementView) { + destroySelectionBox: function(elementView) { - this.$('[data-model="' + elementView.model.get('id') + '"]').remove(); - if (this.$('.selection-box').length === 0) { + this.$('[data-model="' + elementView.model.get('id') + '"]').remove(); + if (this.$('.selection-box').length === 0) { - this.$el.hide().removeClass('selected'); - } - }, + this.$el.hide().removeClass('selected'); + } + }, - createSelectionBox: function(elementView) { + createSelectionBox: function(elementView) { - var element = elementView.model; + var element = elementView.model; - if (!element.isLink()) { + if (!element.isLink()) { - var $selectionBox = $('
    ', { - 'class': 'selection-box', - 'data-model': element.get('id') - }); - this.$el.append($selectionBox); + var $selectionBox = $('
    ', { + 'class': 'selection-box', + 'data-model': element.get('id') + }); + this.$el.append($selectionBox); - this.updateBox(element); + this.updateBox(element); - this.$el.addClass('selected').show(); + this.$el.addClass('selected').show(); - this._action = 'cherry-picking'; - } - }, + this._action = 'cherry-picking'; + } + }, - updateBox: function(element) { + updateBox: function(element) { - var border = 12; + var margin = 4; - var bbox = element.getBBox(); - var state = this.options.state; + var bbox = element.getBBox(); + var state = this.options.state; - $("div[data-model='" + element.get('id') + "']").css({ - left: bbox.x * state.zoom + state.pan.x + - bbox.width / 2.0 * (state.zoom - 1) - border / 2, - top: bbox.y * state.zoom + state.pan.y + - bbox.height / 2.0 * (state.zoom - 1) - border / 2, - width: bbox.width + border, - height: bbox.height + border, - transform: 'scale(' + state.zoom + ')' - }); - } + $('div[data-model=\'' + element.get('id') + '\']').css({ + left: bbox.x * state.zoom + state.pan.x + + bbox.width / 2.0 * (state.zoom - 1) - margin, + top: bbox.y * state.zoom + state.pan.y + + bbox.height / 2.0 * (state.zoom - 1) - margin, + width: bbox.width + 2 * margin, + height: bbox.height + 2 * margin, + transform: 'scale(' + state.zoom + ')' + }); + } }); diff --git a/app/scripts/services/blocks.service.js b/app/scripts/services/blocks.service.js new file mode 100644 index 000000000..f24fb33a0 --- /dev/null +++ b/app/scripts/services/blocks.service.js @@ -0,0 +1,755 @@ +'use strict'; + +angular.module('icestudio') + .service('blocks', function(joint, + boards, + utils, + gettextCatalog) { + var gridsize = 8; + + this.newBasic = newBasic; + this.newGeneric = newGeneric; + + this.loadBasic = loadBasic; + this.loadGeneric = loadGeneric; + this.loadWire = loadWire; + + this.editBasic = editBasic; + + + //-- New + + function newBasic(type, addCellCallback) { + switch(type) { + case 'basic.input': + case 'basic.output': + newBasicIO(type, addCellCallback); + break; + case 'basic.constant': + newBasicConstant(addCellCallback); + break; + case 'basic.code': + newBasicCode(addCellCallback); + break; + case 'basic.info': + newBasicInfo(addCellCallback); + break; + default: + break; + } + } + + function newBasicIO(type, addCellCallback) { + var config; + if (type === 'basic.input') { + config = { type: type, _default: 'in', x: 4 }; + } + else { // 'basic.output' + config = { type: type, _default: 'out', x: 95 }; + } + var blockInstance = { + id: null, + data: {}, + type: config.type, + position: { x: config.x * gridsize, y: 4 * gridsize } + }; + utils.inputcheckboxprompt([ + gettextCatalog.getString('Enter the ports'), + gettextCatalog.getString('FPGA pin') + ], [ + config._default, + false + ], + function(evt, values) { + var labels = values[0].replace(/ /g, '').split(','); + var virtual = !values[1]; + // Validate values + var portInfo, portInfos = []; + for (var l in labels) { + if (labels[l]) { + portInfo = utils.parsePortLabel(labels[l]); + if (portInfo) { + evt.cancel = false; + portInfos.push(portInfo); + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Wrong port name {{name}}', { name: labels[l] }), 'warning', 3); + return; + } + } + else { + evt.cancel = true; + //return; + } + } + // Create blocks + for (var p in portInfos) { + portInfo = portInfos[p]; + var pins = getPins(portInfo); + blockInstance.data = { + name: portInfo.name, + range: portInfo.rangestr, + pins: pins, + virtual: virtual + }; + if (addCellCallback) { + addCellCallback(loadBasic(blockInstance)); + } + // Next block position + blockInstance.position.y += (virtual ? 10 : (6 + 4 * pins.length)) * gridsize; + } + }); + } + + function getPins(portInfo) { + var pins = []; + if (portInfo.range) { + for (var r in portInfo.range) { + pins.push({ index: portInfo.range[r].toString(), name: '', value: '0' }); + } + } + else { + pins.push({ index: '0', name: '', value: '0' }); + } + return pins; + } + + function newBasicConstant(addCellCallback) { + var blockInstance = { + id: null, + data: {}, + type: 'basic.constant', + position: { x: 20 * gridsize, y: 4 * gridsize } + }; + utils.inputcheckboxprompt([ + gettextCatalog.getString('Enter the constant blocks'), + gettextCatalog.getString('Local parameter') + ], [ + 'C', + false + ], + function(evt, values) { + var labels = values[0].replace(/ /g, '').split(','); + var local = values[1]; + // Validate values + var paramInfo, paramInfos = []; + for (var l in labels) { + if (labels[l]) { + paramInfo = utils.parseParamLabel(labels[l]); + if (paramInfo) { + evt.cancel = false; + paramInfos.push(paramInfo); + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Wrong parameter name {{name}}', { name: labels[l] }), 'warning', 3); + return; + } + } + else { + evt.cancel = true; + //return; + } + } + // Create blocks + for (var p in paramInfos) { + paramInfo = paramInfos[p]; + blockInstance.data = { + name: paramInfo.name, + value: '', + local: local + }; + if (addCellCallback) { + addCellCallback(loadBasicConstant(blockInstance)); + } + blockInstance.position.x += 15 * gridsize; + } + }); + } + + function newBasicCode(addCellCallback, block) { + var blockInstance = { + id: null, + data: { + code: '', + params: [], + ports: { in: [], out: [] } + }, + type: 'basic.code', + position: { x: 31 * gridsize, y: 24 * gridsize } + }; + var defaultValues = [ + 'a , b', + 'c , d', + '' + ]; + if (block) { + blockInstance = block; + var index, port; + if (block.data.ports) { + var inPorts = []; + for (index in block.data.ports.in) { + port = block.data.ports.in[index]; + inPorts.push(port.name + (port.range || '')); + } + defaultValues[0] = inPorts.join(' , '); + var outPorts = []; + for (index in block.data.ports.out) { + port = block.data.ports.out[index]; + outPorts.push(port.name + (port.range || '')); + } + defaultValues[1] = outPorts.join(' , '); + } + if (block.data.params) { + var params = []; + for (index in block.data.params) { + params.push(block.data.params[index].name); + } + defaultValues[2] = params.join(' , '); + } + } + utils.multiprompt( + [ gettextCatalog.getString('Enter the input ports'), + gettextCatalog.getString('Enter the output ports'), + gettextCatalog.getString('Enter the parameters') ], + defaultValues, + function(evt, values) { + var inPorts = values[0].replace(/ /g, '').split(','); + var outPorts = values[1].replace(/ /g, '').split(','); + var params = values[2].replace(/ /g, '').split(','); + var allNames = []; + // Validate values + var i, inPortInfo, inPortInfos = []; + for (i in inPorts) { + if (inPorts[i]) { + inPortInfo = utils.parsePortLabel(inPorts[i]); + if (inPortInfo && inPortInfo.name) { + evt.cancel = false; + inPortInfos.push(inPortInfo); + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Wrong port name {{name}}', { name: inPorts[i] }), 'warning', 3); + return; + } + } + } + var o, outPortInfo, outPortInfos = []; + for (o in outPorts) { + if (outPorts[o]) { + outPortInfo = utils.parsePortLabel(outPorts[o]); + if (outPortInfo && outPortInfo.name) { + evt.cancel = false; + outPortInfos.push(outPortInfo); + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Wrong port name {{name}}', { name: outPorts[o] }), 'warning', 3); + return; + } + } + } + var p, paramInfo, paramInfos = []; + for (p in params) { + if (params[p]) { + paramInfo = utils.parseParamLabel(params[p]); + if (paramInfo) { + evt.cancel = false; + paramInfos.push(paramInfo); + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Wrong parameter name {{name}}', { name: params[p] }), 'warning', 3); + return; + } + } + } + // Create ports + var pins; + blockInstance.data.ports.in = []; + for (i in inPortInfos) { + if (inPortInfos[i]) { + pins = getPins(inPortInfos[i]); + blockInstance.data.ports.in.push({ + name: inPortInfos[i].name, + range: inPortInfos[i].rangestr, + size: (pins.length > 1) ? pins.length : undefined + }); + allNames.push(inPortInfos[i].name); + } + } + blockInstance.data.ports.out = []; + for (o in outPortInfos) { + if (outPortInfos[o]) { + pins = getPins(outPortInfos[o]); + blockInstance.data.ports.out.push({ + name: outPortInfos[o].name, + range: outPortInfos[o].rangestr, + size: (pins.length > 1) ? pins.length : undefined + }); + allNames.push(outPortInfos[o].name); + } + } + blockInstance.data.params = []; + for (p in paramInfos) { + if (paramInfos[p]) { + blockInstance.data.params.push({ + name: paramInfos[p].name + }); + allNames.push(paramInfos[p].name); + } + } + // Check duplicated attributes + var numNames = allNames.length; + if (numNames === $.unique(allNames).length) { + evt.cancel = false; + // Create block + if (addCellCallback) { + addCellCallback(loadBasicCode(blockInstance)); + } + } + else { + evt.cancel = true; + alertify.notify(gettextCatalog.getString('Duplicated block attributes'), 'warning', 3); + } + }); + } + + function newBasicInfo(addCellCallback) { + var blockInstance = { + id: null, + data: { info: '' }, + type: 'basic.info', + position: { x: 4 * gridsize, y: 30 * gridsize } + }; + if (addCellCallback) { + addCellCallback(loadBasicInfo(blockInstance)); + } + } + + function newGeneric(type, block, addCellCallback) { + var blockInstance = { + id: null, + type: type, + position: { x: 6 * gridsize, y: 16 * gridsize } + }; + if (block && + block.design && + block.design.graph && + block.design.graph.blocks && + block.design.graph.wires) { + if (addCellCallback) { + addCellCallback(loadGeneric(blockInstance, block)); + } + } + else { + alertify.notify(gettextCatalog.getString('Wrong block format: {{type}}', { type: type }), 'error', 30); + } + } + + + //-- Load + + function loadBasic(instance, disabled) { + switch(instance.type) { + case 'basic.input': + return loadBasicInput(instance, disabled); + case 'basic.output': + return loadBasicOutput(instance, disabled); + case 'basic.constant': + return loadBasicConstant(instance, disabled); + case 'basic.code': + return loadBasicCode(instance, disabled); + case 'basic.info': + return loadBasicInfo(instance, disabled); + default: + break; + } + } + + function loadBasicInput(instance, disabled) { + var data = instance.data; + var rightPorts = [{ + id: 'out', + label: '', + size: data.pins ? data.pins.length : (data.size || 1), + gridUnits: 8 + }]; + + var cell = new joint.shapes.ice.Input({ + id: instance.id, + blockType: instance.type, + data: instance.data, + position: instance.position, + disabled: disabled, + rightPorts: rightPorts, + choices: boards.getPinoutHTML() + }); + return cell; + } + + function loadBasicOutput(instance, disabled) { + var data = instance.data; + var leftPorts = [{ + id: 'in', + label: '', + size: data.pins ? data.pins.length : (data.size || 1), + gridUnits: 8 + }]; + var cell = new joint.shapes.ice.Output({ + id: instance.id, + blockType: instance.type, + data: instance.data, + position: instance.position, + disabled: disabled, + leftPorts: leftPorts, + choices: boards.getPinoutHTML() + }); + return cell; + } + + function loadBasicConstant(instance, disabled) { + var bottomPorts = [{ + id: 'constant-out', + label: '', + gridUnits: 8 + }]; + var cell = new joint.shapes.ice.Constant({ + id: instance.id, + blockType: instance.type, + data: instance.data, + position: instance.position, + disabled: disabled, + bottomPorts: bottomPorts + }); + return cell; + } + + function loadBasicCode(instance, disabled) { + var port; + var leftPorts = []; + var rightPorts = []; + var topPorts = []; + + for (var i in instance.data.ports.in) { + port = instance.data.ports.in[i]; + leftPorts.push({ + id: port.name, + label: port.name + (port.range || ''), + size: port.size || 1, + gridUnits: 32 + }); + } + + for (var o in instance.data.ports.out) { + port = instance.data.ports.out[o]; + rightPorts.push({ + id: port.name, + label: port.name + (port.range || ''), + size: port.size || 1, + gridUnits: 32 + }); + } + + for (var p in instance.data.params) { + port = instance.data.params[p]; + topPorts.push({ + id: port.name, + label: port.name, + gridUnits: 48 + }); + } + + var cell = new joint.shapes.ice.Code({ + id: instance.id, + blockType: instance.type, + data: instance.data, + position: instance.position, + disabled: disabled, + leftPorts: leftPorts, + rightPorts: rightPorts, + topPorts: topPorts + }); + return cell; + } + + function loadBasicInfo(instance, disabled) { + var cell = new joint.shapes.ice.Info({ + id: instance.id, + blockType: instance.type, + data: instance.data, + position: instance.position, + disabled: disabled + }); + return cell; + } + + function loadGeneric(instance, block) { + var i; + var leftPorts = []; + var rightPorts = []; + var topPorts = []; + var bottomPorts = []; + var gridsize = 8; + + for (i in block.design.graph.blocks) { + var data; + var item = block.design.graph.blocks[i]; + if (item.type === 'basic.input') { + data = block.design.graph.blocks[i].data; + leftPorts.push({ + id: item.id, + label: item.data.name + (item.data.range || ''), + size: data.pins ? data.pins.length : (data.size || 1) + }); + } + else if (item.type === 'basic.output') { + data = block.design.graph.blocks[i].data; + rightPorts.push({ + id: item.id, + label: item.data.name + (item.data.range || ''), + size: data.pins ? data.pins.length : (data.size || 1) + }); + } + else if (item.type === 'basic.constant') { + if (!item.data.local) { + topPorts.push({ + id: item.id, + label: item.data.name + }); + } + } + } + + var numPortsHeight = Math.max(leftPorts.length, rightPorts.length); + var numPortsWidth = Math.max(topPorts.length, bottomPorts.length); + + var height = 8 * gridsize; + height = Math.max(4 * gridsize * numPortsHeight, height); + var blockLabel = block.package.name; + var width = 12 * gridsize; + + width = Math.max(4 * gridsize * numPortsWidth, width); + + var gridUnitsHeight = height / gridsize; + var gridUnitsWidth = width / gridsize; + + for (i in leftPorts) { + leftPorts[i].gridUnits = gridUnitsHeight; + } + for (i in rightPorts) { + rightPorts[i].gridUnits = gridUnitsHeight; + } + for (i in topPorts) { + topPorts[i].gridUnits = gridUnitsWidth; + } + for (i in bottomPorts) { + bottomPorts[i].gridUnits = gridUnitsWidth; + } + + var blockImage = ''; + if (block.package.image) { + width = 12 * gridsize; + if (block.package.image.startsWith('%3Csvg')) { + blockImage = block.package.image; + } + else if (block.package.image.startsWith('' + pinout[i].name + ''; + } + return code; + } - }]); + }); diff --git a/app/scripts/services/common.service.js b/app/scripts/services/common.service.js deleted file mode 100644 index b9a201263..000000000 --- a/app/scripts/services/common.service.js +++ /dev/null @@ -1,322 +0,0 @@ -'use strict'; - -angular.module('icestudio') - .service('common', ['$rootScope', 'gettextCatalog', 'window', 'graph', 'boards', 'compiler', 'utils', 'nodePath', 'nodeFs', - function($rootScope, gettextCatalog, window, graph, boards, compiler, utils, nodePath, nodeFs) { - - // Variables - - this.project = { - image: '', - state: null, - board: '', - graph: {}, - deps: {} - }; - this.projectName = ''; - this.projectPath = ''; - - // Functions - - this.setProjectPath = function(path) { - this.projectPath = path; - } - - this.newProject = function(name) { - this.project = { - image: '', - state: null, - board: '', - graph: {}, - deps: {} - }; - graph.clearAll(); - graph.setState(this.project.state); - this.updateProjectName(name); - alertify.success(gettextCatalog.getString('New project {{name}} created', { name: utils.bold(name) })); - }; - - this.openProject = function(filepath) { - var self = this; - utils.readFile(filepath, function(data) { - var project = data; - if (project) { - var name = utils.basename(filepath); - self.loadProject(name, project); - } - }); - }; - - this.loadProject = function(name, project) { - this.updateProjectName(name); - this.project = project; - boards.selectBoard(project.board); - if (graph.loadGraph(project)) { - alertify.success(gettextCatalog.getString('Project {{name}} loaded', { name: utils.bold(name) })); - } - else { - alertify.notify(gettextCatalog.getString('Wrong project format: {{name}}', { name: utils.bold(name) }), 'error', 30); - } - $rootScope.$apply(); - }; - - this.saveProject = function(filepath) { - var name = utils.basename(filepath); - this.updateProjectName(name); - this.refreshProject(); - utils.saveFile(filepath, this.project, function() { - alertify.success(gettextCatalog.getString('Project {{name}} saved', { name: utils.bold(name) })); - }, true); - }; - - this.importBlock = function(filepath) { - var self = this; - utils.readFile(filepath, function(data) { - var block = data; - if (block) { - var name = utils.basename(filepath); - var path = utils.dirname(filepath); - // 1. Parse and find included files - var code = JSON.stringify(block); - var files = utils.findIncludedFiles(code); - // Are there included files? - if (files.length > 0) { - // 2. Check project's directory - if (self.projectPath) { - // 3. Copy the included files - copyIncludedFiles(function(success) { - if (success) { - // 4. Success: import block - doImportBlock(); - } - }); - } - else { - alertify.confirm(gettextCatalog.getString('This import operation requires a project path. You need to save the current project. Do you want to continue?'), - function() { - $rootScope.$emit('saveProjectAs', function() { - setTimeout(function() { - // 3. Copy the included files - copyIncludedFiles(function(success) { - if (success) { - // 4. Success: import block - doImportBlock(); - } - }); - }, 500); - }); - }); - } - } - else { - // No included files to copy - // 4. Import block - doImportBlock(); - } - } - - function copyIncludedFiles(callback) { - var success = true; - async.eachSeries(files, function(filename, next) { - setTimeout(function() { - var origPath = nodePath.join(path, filename); - var destPath = nodePath.join(self.projectPath, filename); - if (nodeFs.existsSync(destPath)) { - alertify.confirm(gettextCatalog.getString('File {{file}} already exists in the project path. Do you want to replace it?', { file: utils.bold(filename) }), - function() { - success &= doCopySync(origPath, destPath, filename) - if (!success) { - return next(); // break - } - next(); - }, - function() { - next(); - }); - } - else { - success &= doCopySync(origPath, destPath, filename) - if (!success) { - return next(); // break - } - next(); - } - }, 0); - }, function(result) { - return callback(success); - }); - } - - function doCopySync(orig, dest, filename) { - var success = utils.copySync(orig, dest, filename); - if (success) { - alertify.notify(gettextCatalog.getString('File {{file}} imported', { file: utils.bold(filename) }), 'message', 5); - } - else { - alertify.notify(gettextCatalog.getString('Original file {{file}} does not exist', { file: utils.bold(filename) }), 'error', 30); - } - return success; - } - - function doImportBlock() { - graph.importBlock(name, block); - self.project.deps[name] = block; - alertify.success(gettextCatalog.getString('Block {{name}} imported', { name: utils.bold(name) })); - } - - }); - }; - - this.exportAsBlock = function(filepath) { - var name = utils.basename(filepath); - this.refreshProject(); - // Convert project to block - var block = angular.copy(this.project); - delete block.board; - for (var i in block.graph.blocks) { - if (block.graph.blocks[i].type == 'basic.input' || - block.graph.blocks[i].type == 'basic.output') { - delete block.graph.blocks[i].data.pin; - } - } - utils.saveFile(filepath, block, function() { - alertify.success(gettextCatalog.getString('Block exported as {{name}}', { name: utils.bold(name) })); - }, true); - }; - - this.exportVerilog = function(filepath) { - var name = utils.basename(filepath); - this.refreshProject(); - // Generate verilog code from project - var verilog = compiler.generateVerilog(this.project); - utils.saveFile(filepath, verilog, function() { - alertify.success(gettextCatalog.getString('Verilog code exported')); - }, false); - }; - - this.exportPCF = function(filepath) { - var name = utils.basename(filepath); - this.refreshProject(); - // Generate pcf code from project - var pcf = compiler.generatePCF(this.project); - utils.saveFile(filepath, pcf, function() { - alertify.success(gettextCatalog.getString('PCF file exported')); - }, false); - }; - - this.exportTestbench = function(filepath) { - var name = utils.basename(filepath); - this.refreshProject(); - // Generate testbench code from project - var testbench = compiler.generateTestbench(this.project); - utils.saveFile(filepath, testbench, function() { - alertify.success(gettextCatalog.getString('Testbench exported')); - }, false); - }; - - this.exportGTKWave = function(filepath) { - var name = utils.basename(filepath); - this.refreshProject(); - // Generate gtkwave code from project - var gtkwave = compiler.generateGTKWave(this.project); - utils.saveFile(filepath, gtkwave, function() { - alertify.success(gettextCatalog.getString('GTKWave exported')); - }, false); - }; - - this.refreshProject = function(callback) { - var graphData = graph.toJSON(); - - var blocks = []; - var wires = []; - - for (var c = 0; c < graphData.cells.length; c++) { - var cell = graphData.cells[c]; - - if (cell.type == 'ice.Generic' || - cell.type == 'ice.Input' || - cell.type == 'ice.Output' || - cell.type == 'ice.Code' || - cell.type == 'ice.Info') { - var block = {}; - block.id = cell.id; - block.type = cell.blockType; - block.data = cell.data; - block.position = cell.position; - if (cell.type == 'ice.Code') { - block.data.code = graph.getContent(cell.id); - } - else if (cell.type == 'ice.Info') { - block.data.info = graph.getContent(cell.id); - } - blocks.push(block); - } - else if (cell.type == 'ice.Wire') { - var wire = {}; - wire.source = { block: cell.source.id, port: cell.source.port }; - wire.target = { block: cell.target.id, port: cell.target.port }; - wire.vertices = cell.vertices; - wires.push(wire); - } - } - - this.project.state = graph.getState(); - - this.project.board = boards.selectedBoard.name; - - this.project.graph = { blocks: blocks, wires: wires }; - - if (callback) - callback(); - }; - - this.clearProject = function() { - this.project = { - image: '', - state: this.project.state, - board: '', - graph: {}, - deps: {} - }; - graph.clearAll(); - graph.breadcrumbs = [{ name: this.projectName }]; - if(!$rootScope.$$phase) { - $rootScope.$apply(); - } - }; - - this.cloneSelected = function() { - graph.cloneSelected(); - }; - - this.removeSelected = function() { - var self = this; - graph.removeSelected(function(type) { - delete self.project.deps[type]; - }); - }; - - this.setImagePath = function(imagePath) { - this.project.image = imagePath; - } - - this.updateProjectName = function(name) { - if (name) { - this.projectName = name - if (graph.breadcrumbs.length > 1) { - graph.breadcrumbs = [{ name: name }]; - } - graph.breadcrumbs[0].name = name; - if(!$rootScope.$$phase) { - $rootScope.$apply(); - } - window.get().title = name + ' - Icestudio'; - } - }; - - this.addBlock = function(type, block) { - this.project.deps[type] = block; - graph.createBlock(type, block); - } - - }]); diff --git a/app/scripts/services/compiler.service.js b/app/scripts/services/compiler.service.js index 9e1a4a565..a6872a477 100644 --- a/app/scripts/services/compiler.service.js +++ b/app/scripts/services/compiler.service.js @@ -1,394 +1,604 @@ 'use strict'; angular.module('icestudio') - .service('compiler', ['nodeSha1', '_package', - function(nodeSha1, _package) { - - this.generateVerilog = function(project) { - var code = header('//'); - code += '`default_nettype none\n\n'; + .service('compiler', function(nodeSha1, + _package) { + + this.generate = function(target, project) { + var code = ''; + switch(target) { + case 'verilog': + code += header('//'); + code += '`default_nettype none\n'; code += verilogCompiler('main', project); - return code; - }; - - this.generatePCF = function(project) { - var code = header('#'); + break; + case 'pcf': + code += header('#'); code += pcfCompiler(project); - return code; - }; - - this.generateTestbench = function(project) { - var code = header('//'); + break; + case 'testbench': + code += header('//'); code += testbenchCompiler(project); - return code; - }; - - this.generateGTKWave = function(project) { - var code = header('[*]'); + break; + case 'gtkwave': + code += header('[*]'); code += gtkwaveCompiler(project); - return code; - }; - - function header(comment) { - var header = ''; - var date = new Date(); - header += comment + ' Code generated by Icestudio ' + _package.version + '\n'; - header += comment + ' ' + date.toUTCString() + '\n'; - header += '\n'; - return header; - } - - function digestId(id, force) { - if (id.indexOf('-') != -1) { - return 'v' + nodeSha1(id).toString().substring(0, 6); - } - else { - return id.replace('.', '_'); + break; + default: + code += ''; + } + return code; + }; + + function header(comment) { + var header = ''; + var date = new Date(); + header += comment + ' Code generated by Icestudio ' + _package.version + '\n'; + header += comment + ' ' + date.toUTCString() + '\n'; + header += '\n'; + return header; + } + + function digestId(id) { + if (id.indexOf('-') !== -1) { + id = nodeSha1(id).toString(); + } + return 'v' + id.substring(0, 6); + } + + function module(data) { + var code = ''; + if (data && data.name && data.ports) { + + // Header + + code += '\nmodule ' + data.name; + + //-- Parameters + + var params = []; + for (var p in data.params) { + if (data.params[p] instanceof Object) { + params.push(' parameter ' + data.params[p].name + ' = ' + (data.params[p].value ? data.params[p].value : '0')); } } - function module(data) { - var code = ''; + if (params.length > 0) { + code += ' #(\n'; + code += params.join(',\n'); + code += '\n)'; + } - if (data && - data.name && - data.ports) { + //-- Ports - // Header + var ports = []; + for (var i in data.ports.in) { + var _in = data.ports.in[i]; + ports.push(' input ' + (_in.range ? (_in.range + ' ') : '') + _in.name); + } + for (var o in data.ports.out) { + var _out = data.ports.out[o]; + ports.push(' output ' + (_out.range ? (_out.range + ' ') : '') + _out.name); + } - code += 'module '; - code += data.name; - code += ' ('; + if (ports.length > 0) { + code += ' (\n'; + code += ports.join(',\n'); + code += '\n)'; + } - var params = []; - var paramsSpace = 10 + data.name.length; + code += ';\n'; - for (var i in data.ports.in) { - params.push('input ' + data.ports.in[i]); - } - for (var o in data.ports.out) { - params.push('output ' + data.ports.out[o]); - } + // Content - code += params.join(',\n' + new Array(paramsSpace).join(' ')); + if (data.content) { - code += ');\n'; + var content = data.content.split('\n'); - // Content + content.forEach(function (element, index, array) { + array[index] = ' ' + element; + }); - if (data.content) { + code += content.join('\n'); + } - var content = data.content.split('\n'); + // Footer - content.forEach(function (element, index, array) { - array[index] = ' ' + element; - }); + code += '\nendmodule\n'; + } - code += content.join('\n'); - } + return code; + } - // Footer + function getParams(project) { + var params = []; + var graph = project.design.graph; - code += '\nendmodule\n\n'; + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.constant') { + params.push({ + name: digestId(block.id), + value: block.data.value + }); + } + } + + return params; + } + + function getPorts(project) { + var ports = { + in: [], + out: [] + }; + var graph = project.design.graph; + + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.input') { + ports.in.push({ + name: digestId(block.id), + range: block.data.range ? block.data.range : '' + }); + } + else if (block.type === 'basic.output') { + ports.out.push({ + name: digestId(block.id), + range: block.data.range ? block.data.range : '' + }); + } + } + + return ports; + } + + function getContent(name, project) { + var i, j, w; + var content = []; + var graph = project.design.graph; + var connections = { + localparam: [], + wire: [], + assign: [] + }; + + for (w in graph.wires) { + var wire = graph.wires[w]; + if (wire.source.port === 'constant-out') { + // Local Parameters + var constantBlock = findBlock(wire.source.block, graph); + var paramValue = digestId(constantBlock.id); + if (paramValue) { + connections.localparam.push('localparam p' + w + ' = ' + paramValue + ';'); } - - return code; } - - function getPorts(project) { - var ports = { - in: [], - out: [] - }; - var graph = project.graph; - - for (var i in graph.blocks) { - var block = graph.blocks[i]; - if (block.type == 'basic.input') { - ports.in.push(digestId(block.id)); + else { + // Wires + var range = wire.size ? ' [0:' + (wire.size-1) +'] ' : ' '; + connections.wire.push('wire' + range + 'w' + w + ';'); + } + // Assignations + for (i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.input') { + if (wire.source.block === block.id) { + connections.assign.push('assign w' + w + ' = ' + digestId(block.id) + ';'); } - else if (block.type == 'basic.output') { - ports.out.push(digestId(block.id)); + } + else if (block.type === 'basic.output') { + if (wire.target.block === block.id) { + if (wire.source.port === 'constant-out') { + // connections.assign.push('assign ' + digestId(block.id) + ' = p' + w + ';'); + } + else { + connections.assign.push('assign ' + digestId(block.id) + ' = w' + w + ';'); + } } } - - return ports; } + } + + content = content.concat(connections.localparam); + content = content.concat(connections.wire); + content = content.concat(connections.assign); + + // Wires Connections + + var numWires = graph.wires.length; + for (i = 1; i < numWires; i++) { + for (j = 0; j < i; j++) { + var wi = graph.wires[i]; + var wj = graph.wires[j]; + if (wi.source.block === wj.source.block && + wi.source.port === wj.source.port && + wi.source.port !== 'constant-out') { + content.push('assign w' + i + ' = w' + j + ';'); + } + } + } - function getContent(name, project) { - var content = ''; - var graph = project.graph; + // Block instances - // Wires + content = content.concat(getInstances(name, project.design.graph)); - for (var w in graph.wires) { - content += 'wire w' + w + ';\n' - } + return content.join('\n'); + } - // I/O connections + function getInstances(name, graph) { + var w, wire; + var instances = []; + var blocks = graph.blocks; - for (var w in graph.wires) { - var wire = graph.wires[w]; - for (var i in graph.blocks) { - var block = graph.blocks[i]; - if (block.type == 'basic.input') { - if (wire.source.block == block.id) { - content += 'assign w' + w + ' = ' + digestId(block.id) + ';\n'; - } - } - else if (block.type == 'basic.output') { - if (wire.target.block == block.id) { - content += 'assign ' + digestId(block.id) + ' = w' + w + ';\n'; - } - } - } + for (var b in blocks) { + var block = blocks[b]; + + if (block.type !== 'basic.input' && + block.type !== 'basic.output' && + block.type !== 'basic.constant' && + block.type !== 'basic.info') { + + // Header + + var instance = ''; + if (block.type === 'basic.code') { + instance = digestId(block.id); + } + else { + instance = digestId(block.type); } - // Wires Connections + //-- Parameters - var numWires = graph.wires.length; - for (var i = 1; i < numWires; i++) { - for (var j = 0; j < i; j++) { - var wi = graph.wires[i]; - var wj = graph.wires[j]; - if (wi.source.block == wj.source.block && - wi.source.port == wj.source.port) { - content += 'assign w' + i + ' = w' + j + ';\n'; + var params = []; + for (w in graph.wires) { + wire = graph.wires[w]; + if ((block.id === wire.target.block) && + (wire.source.port === 'constant-out')) { + var paramName = wire.target.port; + if (block.type !== 'basic.code') { + paramName = digestId(paramName); } + var param = ''; + param += ' .' + paramName; + param += '(p' + w + ')'; + params.push(param); } } - // Block instances + if (params.length > 0) { + instance += ' #(\n' + params.join(',\n') + '\n)'; + } - var instances = [] - for (var b in graph.blocks) { - var block = graph.blocks[b]; - if (block.type != 'basic.input' && - block.type != 'basic.output' && - block.type != 'basic.info') { + //-- Instance name - var id = digestId(block.type, true); - if (block.type == 'basic.code') { - id += '_' + digestId(block.id); - } - instances.push(name + '_' + digestId(id) + ' ' + digestId(block.id) + ' ('); - - // Parameters - - var params = []; - var paramsNames = []; - for (var w in graph.wires) { - var param = ''; - var paramName = ''; - var wire = graph.wires[w]; - if (block.id == wire.source.block) { - paramName = digestId(wire.source.port); - } - else if (block.id == wire.target.block) { - paramName = digestId(wire.target.port); - } - if (paramName && paramsNames.indexOf(paramName) == -1) { - paramsNames.push(paramName); - param += ' .' + paramName; - param += '(w' + w + ')'; - params.push(param); - } - } + instance += ' ' + digestId(block.id); + + //-- Ports - instances.push(params.join(',\n') + '\n);'); + var ports = []; + var portsNames = []; + for (w in graph.wires) { + var portName = ''; + var isConstant = false; + wire = graph.wires[w]; + if (block.id === wire.source.block) { + portName = wire.source.port; + } + else if (block.id === wire.target.block) { + portName = wire.target.port; + isConstant = wire.source.port === 'constant-out'; + } + if (portName && block.type !== 'basic.code') { + portName = digestId(portName); + } + if (portName && !isConstant && + portsNames.indexOf(portName) === -1) { + portsNames.push(portName); + var port = ''; + port += ' .' + portName; + port += '(w' + w + ')'; + ports.push(port); } } - content += instances.join('\n'); - return content; - } + instance += ' (\n' + ports.join(',\n') + '\n);'; - function verilogCompiler(name, project) { - var code = ''; + if (instance) { + instances.push(instance); + } + } + } + return instances; + } + + function findBlock(id, graph) { + for (var b in graph.blocks) { + if (graph.blocks[b].id === id) { + return graph.blocks[b]; + } + } + return null; + } - if (project && - project.graph) { + function verilogCompiler(name, project) { + var data; + var code = ''; - // Scape dot in name + if (project && + project.design && + project.design.graph) { - name = digestId(name); + var graph = project.design.graph; + var dependencies = project.dependencies; - // Main module + // Main module - if (name) { - var data = { - name: name, - ports: getPorts(project), - content: getContent(name, project) - }; - code += module(data); - } + if (name) { + data = { + name: name, + params: getParams(project), + ports: getPorts(project), + content: getContent(name, project) + }; + code += module(data); + } - // Dependencies modules + // Dependencies modules - for (var d in project.deps) { - code += verilogCompiler(name + '_' + digestId(d, true), project.deps[d]); - } + for (var d in dependencies) { + code += verilogCompiler(digestId(d), dependencies[d]); + } - // Code modules - - for (var i in project.graph.blocks) { - var block = project.graph.blocks[i]; - if (block) { - if (block.type == 'basic.code') { - var data = { - name: name + '_' + digestId(block.type, true) + '_' + digestId(block.id), - ports: block.data.ports, - content: block.data.code - } - code += module(data); - } - } + // Code modules + + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block) { + if (block.type === 'basic.code') { + data = { + name: digestId(block.id), + params: block.data.params, + ports: block.data.ports, + content: block.data.code + }; + code += module(data); } } - - return code; } + } + + return code; + } + + function pcfCompiler(project) { + var code = ''; + var graph = project.design.graph; - function pcfCompiler(project) { - var code = ''; + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.input' || + block.type === 'basic.output') { - for (var i in project.graph.blocks) { - var block = project.graph.blocks[i]; - if (block.type == 'basic.input' || - block.type == 'basic.output') { + if (block.data.pins.length > 1) { + for (var p in block.data.pins) { + var pin = block.data.pins[p]; code += 'set_io '; code += digestId(block.id); - code += ' '; - code += block.data.pin.value; + code += '[' + pin.index + '] '; + code += block.data.virtual ? '' : pin.value; code += '\n'; } } - - return code; + else { + code += 'set_io '; + code += digestId(block.id); + code += ' '; + code += block.data.virtual ? '' : block.data.pins[0].value; + code += '\n'; + } } + } - function testbenchCompiler(project) { - var code = ''; + return code; + } - code += '// Testbench template\n\n' + function testbenchCompiler(project) { + var i, o, p; + var code = ''; - code += '`default_nettype none\n'; - code += '`define DUMPSTR(x) `"x.vcd`"\n'; - code += '`timescale 10 ns / 1 ns\n\n'; - - var ports = { in: [], out: [] }; - var content = '\n'; - - content += '// Simulation time: 100ns (10 * 10ns)\n'; - content += 'parameter DURATION = 10;\n\n'; + code += '// Testbench template\n\n'; - var io = mainIO(project); - var input = io[0]; - var output = io[1]; + code += '`default_nettype none\n'; + code += '`define DUMPSTR(x) `"x.vcd`"\n'; + code += '`timescale 10 ns / 1 ns\n\n'; - // Input/Output - content += '// Input/Output\n'; - for (var i in input) { - content += 'reg ' + input[i].label + ';\n'; - } - for (var o in output) { - content += 'wire ' + output[o].label + ';\n'; - } + var ports = { in: [], out: [] }; + var content = '\n'; - var wires = input.concat(output); + content += '// Simulation time: 100ns (10 * 10ns)\n'; + content += 'parameter DURATION = 10;\n'; - // Module instance - content += '\n// Module instance\n'; - content += 'main MAIN (\n'; - var connections = []; - for (var w in wires) { - connections.push(' .' + wires[w].id + '(' + wires[w].label + ')'); - } - content += connections.join(',\n'); - content += '\n);\n'; - - // Clock signal - var hasClk = false; - for (var i in input) { - if (input[i].label.toLowerCase() == 'input_clk') { - hasClk = true; - break; - } - } - if (hasClk) { - content += '\n// Clock signal\n'; - content += 'always #0.5 input_clk = ~input_clk;\n'; + // Parameters + var _params = []; + var params = mainParams(project); + if (params.length > 0) { + content += '\n// TODO: edit the module parameters here\n'; + content += '// e.g. localparam constant_value = 1;\n'; + for (p in params) { + content += 'localparam ' + params[p].name + ' = ' + params[p].value + ';\n'; + _params.push(' .' + params[p].id + '(' + params[p].name + ')'); + } + } + + // Input/Output + var io = mainIO(project); + var input = io.input; + var output = io.output; + content += '\n// Input/Output\n'; + var _ports = []; + for (i in input) { + content += 'reg ' + (input[i].range ? input[i].range + ' ': '') + input[i].name + ';\n'; + _ports.push(' .' + input[i].id + '(' + input[i].name + ')'); + } + for (o in output) { + content += 'wire ' + (output[o].range ? output[o].range + ' ': '') + output[o].name + ';\n'; + _ports.push(' .' + output[o].id + '(' + output[o].name + ')'); + } + + // Module instance + content += '\n// Module instance\n'; + content += 'main'; + + //-- Parameters + if (_params.length > 0) { + content += ' #(\n'; + content += _params.join(',\n'); + content += '\n)'; + } + + content += ' MAIN'; + + //-- Ports + if (_ports.length > 0) { + content += ' (\n'; + content += _ports.join(',\n'); + content += '\n)'; + } + + content += ';\n'; + + // Clock signal + var hasClk = false; + for (i in input) { + if (input[i].name.toLowerCase() === 'clk') { + hasClk = true; + break; + } + } + if (hasClk) { + content += '\n// Clock signal\n'; + content += 'always #0.5 clk = ~clk;\n'; + } + + content += '\ninitial begin\n'; + content += ' // File were to store the simulation results\n'; + content += ' $dumpfile(`DUMPSTR(`VCD_OUTPUT));\n'; + content += ' $dumpvars(0, main_tb);\n\n'; + content += ' // TODO: initialize the registers here\n'; + content += ' // e.g. value = 1;\n'; + content += ' // e.g. #2 value = 0;\n'; + for (i in input) { + content += ' ' + input[i].name + ' = 0;\n'; + } + content += '\n'; + content += ' #(DURATION) $display("End of simulation");\n'; + content += ' $finish;\n'; + content += 'end\n'; + + var data = { + name: 'main_tb', + ports: ports, + content: content + }; + code += module(data); + + return code; + } + + function gtkwaveCompiler(project) { + var code = ''; + + var io = mainIO(project); + var input = io.input; + var output = io.output; + + for (var i in input) { + code += 'main_tb.' + input[i].name + (input[i].range ? input[i].range: '') + '\n'; + } + for (var o in output) { + code += 'main_tb.' + output[o].name + (output[o].range ? output[o].range: '') + '\n'; + } + + return code; + } + + function mainIO(project) { + var input = []; + var output = []; + var inputUnnamed = 0; + var outputUnnamed = 0; + var graph = project.design.graph; + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.input') { + if (block.data.name) { + input.push({ + id: digestId(block.id), + name: block.data.name.replace(/ /g, '_'), + range: block.data.range + }); } - - content += '\ninitial begin\n'; - content += ' // File were to store the simulation results\n'; - content += ' $dumpfile(`DUMPSTR(`VCD_OUTPUT));\n'; - content += ' $dumpvars(0, main_tb);\n\n'; - content += ' // TODO: initialize the registers here\n'; - content += ' // e.g. input_value = 1;\n'; - content += ' // e.g. #2 input_value = 0;\n'; - for (var i in input) { - content += ' ' + input[i].label + ' = 0;\n'; + else { + input.push({ + id: digestId(block.id), + name: inputUnnamed.toString(), + }); + inputUnnamed += 1; } - content += '\n'; - content += ' #(DURATION) $display("End of simulation");\n'; - content += ' $finish;\n'; - content += 'end\n'; - - var data = { - name: 'main_tb', - ports: ports, - content: content - }; - code += module(data); - - return code; } - - function gtkwaveCompiler(project) { - var code = ''; - - var io = mainIO(project); - var input = io[0]; - var output = io[1]; - - var wires = input.concat(output); - for (var w in wires) { - code += 'main_tb.' + wires[w].label + '\n'; + else if (block.type === 'basic.output') { + if (block.data.name) { + output.push({ + id: digestId(block.id), + name: block.data.name.replace(/ /g, '_'), + range: block.data.range + }); + } + else { + output.push({ + id: digestId(block.id), + name: outputUnnamed.toString() + }); + outputUnnamed += 1; } - - return code; } - - function mainIO(project) { - var input = []; - var output = []; - var input_unnamed = 0; - var output_unnamed = 0; - for (var i in project.graph.blocks) { - var block = project.graph.blocks[i]; - if (block.type == 'basic.input') { - if (block.data.label) { - input.push({ id: digestId(block.id), label: 'input_' + block.data.label.replace(' ', '_') }); - } - else { - input.push({ id: digestId(block.id), label: 'input_' + input_unnamed.toString() }); - input_unnamed += 1; - } + } + + return { + input: input, + output: output + }; + } + + function mainParams(project) { + var params = []; + var paramsUnnamed = 0; + var graph = project.design.graph; + for (var i in graph.blocks) { + var block = graph.blocks[i]; + if (block.type === 'basic.constant') { + if (!block.data.local) { + if (block.data.name) { + params.push({ + id: digestId(block.id), + name: 'constant_' + block.data.name.replace(/ /g, '_'), + value: block.data.value + }); } - else if (block.type == 'basic.output') { - if (block.data.label) { - output.push({ id: digestId(block.id), label: 'output_' + block.data.label.replace(' ', '_') }); - } - else { - output.push({ id: digestId(block.id), label: 'output_' + output_unnamed.toString() }); - output_unnamed += 1; - } + else { + params.push({ + id: digestId(block.id), + name: 'constant_' + paramsUnnamed.toString(), + value: block.data.value + }); + paramsUnnamed += 1; } } - - return [input, output]; } + } + + return params; + } - }]); + }); diff --git a/app/scripts/services/graph.service.js b/app/scripts/services/graph.service.js index d643ef509..415747842 100644 --- a/app/scripts/services/graph.service.js +++ b/app/scripts/services/graph.service.js @@ -1,940 +1,738 @@ 'use strict'; angular.module('icestudio') - .service('graph', ['$rootScope', 'gettextCatalog', 'nodeFs', 'joint', 'boards', 'utils', - function($rootScope, gettextCatalog, nodeFs, joint, boards, utils) { - - // Variables - - var zIndex = 100; - var ctrlPressed = false; - - var graph = null; - var paper = null; - var selection = null; - var selectionView = null; - - var dependencies = {}; - this.breadcrumbs = [{ name: '' }]; - - var gridsize = 8; - var state = { + .service('graph', function($rootScope, + joint, + boards, + blocks, + utils, + gettextCatalog, + window) { + // Variables + + var z = { + index: 100 + }; + var ctrlPressed = false; + + var graph = null; + var paper = null; + var selection = null; + var selectionView = null; + var commandManager = null; + var clipboard = []; + var mousePosition = { x: 0, y: 0 }; + var dependencies = {}; + + this.breadcrumbs = [{ name: '', type: '' }]; + + var gridsize = 8; + var state = { + pan: { + x: 0, + y: 0 + }, + zoom: 1.0 + }; + const ZOOM_MAX = 2; + const ZOOM_MIN = 0.2; + + // Functions + + $(document).on('keydown', function(event) { + ctrlPressed = event.keyCode === 17; + }); + + this.getState = function() { + // Clone state + return utils.clone(state); + }; + + this.setState = function(_state) { + if (!_state) { + _state = { pan: { x: 0, y: 0 }, - zoom: 1 + zoom: 1.0 }; - - // Functions - - $(document).on('keydown', function(event) { - ctrlPressed = event.keyCode == 17; - }); - - this.getState = function() { - // Clone state - return JSON.parse(JSON.stringify(state)); - } - - this.setState = function(_state) { - if (!_state) { - _state = { - pan: { - x: 0, - y: 0 - }, - zoom: 1 - }; - } - this.panAndZoom.zoom(_state.zoom); - this.panAndZoom.pan(_state.pan); - setGrid(paper, gridsize*2*_state.zoom, _state.pan); + } + this.panAndZoom.zoom(_state.zoom); + this.panAndZoom.pan(_state.pan); + }; + + this.resetView = function() { + this.setState(null); + }; + + this.fitContent = function() { + if (!this.isEmpty()) { + // Target box + var margin = 40; + var menuFooterHeight = 93; + var tbox = { + x: margin, + y: margin, + width: window.get().width - 2 * margin, + height: window.get().height - menuFooterHeight - 2 * margin + }; + // Source box + var sbox = V(paper.viewport).bbox(true, paper.svg); + sbox = { + x: sbox.x * state.zoom, + y: sbox.y * state.zoom, + width: sbox.width * state.zoom, + height: sbox.height * state.zoom + }; + var scale = 1; + if (tbox.width/sbox.width > tbox.height/sbox.height) { + scale = tbox.height / sbox.height; } - - this.resetState = function() { - this.setState(null); + else { + scale = tbox.width / sbox.width; } - - function setGrid(paper, size, offset) { - - // TODO: draw grid in a SVG because 'background' truncates the parameters - - /* - // Set grid size on the JointJS paper object (joint.dia.Paper instance) - paper.options.gridsize = gridsize; - // Draw a grid into the HTML 5 canvas and convert it to a data URI image - var canvas = $('', { width: size, height: size }); - canvas[0].width = size; - canvas[0].height = size; - var context = canvas[0].getContext('2d'); - context.beginPath(); - context.rect(1, 1, 1, 1); - context.fillStyle = '#555'; - context.globalAlpha = size / gridsize / 2; - context.fill(); - // Finally, set the grid background image of the paper container element. - var gridBackgroundImage = canvas[0].toDataURL('image/png'); - $(paper.el.childNodes[0]).css( - 'background-image', 'url("' + gridBackgroundImage + '")'); - if(typeof(offset) != 'undefined'){ - $(paper.el.childNodes[0]).css( - 'background-position', offset.x + 'px ' + offset.y + 'px'); - }*/ + if (state.zoom * scale > ZOOM_MAX) { + scale = ZOOM_MAX / state.zoom; } - - this.createPaper = function(element) { - graph = new joint.dia.Graph(); - paper = new joint.dia.Paper({ - el: element, - width: 2000, - height: 1000, - model: graph, - gridSize: gridsize, - snapLinks: { radius: 15 }, - linkPinning: false, - embeddingMode: false, - //markAvailable: true, - defaultLink: new joint.shapes.ice.Wire(), - guard: function(evt, view) { - // FALSE means the event isn't guarded. - return false; - }, - validateMagnet: function(cellView, magnet) { - // Prevent to start wires from an input port - return (magnet.getAttribute('type') == 'output'); - }, - validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) { - // Prevent output-output links - if (magnetS.getAttribute('type') == 'output' && - magnetT.getAttribute('type') == 'output') { - if (magnetS !== magnetT){ - // Show warning if source and target blocks are different - warning(gettextCatalog.getString('Invalid connection')); - } - return false; - } - var links = graph.getLinks(); - for (var i in links) { - var linkIView = links[i].findView(paper); - if (linkView == linkIView) { - //Skip the wire the user is drawing - continue; - } - // Prevent multiple input links - if ((cellViewT.model.id == links[i].get('target').id) && - (magnetT.getAttribute('port') == links[i].get('target').port)) { - warning(gettextCatalog.getString('Invalid multiple input connections')); - return false; - } - // Prevent to connect a pull-up if other blocks are connected - if ((cellViewT.model.attributes.blockType == 'config.pull_up' || - cellViewT.model.attributes.blockType == 'config.pull_up_inv') && - (cellViewS.model.id == links[i].get('source').id)) { - warning(gettextCatalog.getString('Invalid Pull up connection:
    block already connected')); - return false; - } - // Prevent to connect other blocks if a pull-up is connected - if ((linkIView.targetView.model.attributes.blockType == 'config.pull_up' || - linkIView.targetView.model.attributes.blockType == 'config.pull_up_inv') && - (cellViewS.model.id == links[i].get('source').id)) { - warning(gettextCatalog.getString('Invalid block connection:
    Pull up already connected')); - return false; - } - } - // Ensure input -> pull-up connections - if (cellViewT.model.attributes.blockType == 'config.pull_up' || - cellViewT.model.attributes.blockType == 'config.pull_up_inv') { - var ret = (cellViewS.model.attributes.blockType == 'basic.input'); - if (!ret) { - warning(gettextCatalog.getString('Invalid Pull up connection:
    only Input blocks allowed')); - } - return ret; - } - // Prevent loop links - return magnetS !== magnetT; + var target = { + x: tbox.x + tbox.width / 2, + y: tbox.y + tbox.height / 2 + }; + var source = { + x: sbox.x + sbox.width / 2, + y: sbox.y + sbox.height / 2 + }; + this.setState({ + pan: { + x: target.x - source.x * scale, + y: target.y - source.y * scale + }, + zoom: state.zoom * scale + }); + } + else { + this.resetView(); + } + }; + + this.resetBreadcrumbs = function(name) { + this.breadcrumbs = [{ name: name, type: '' }]; + utils.rootScopeSafeApply(); + }; + + this.createPaper = function(element) { + graph = new joint.dia.Graph(); + paper = new joint.dia.Paper({ + el: element, + width: 2000, + height: 1000, + model: graph, + gridSize: gridsize, + snapLinks: { radius: 15 }, + linkPinning: false, + embeddingMode: false, + //markAvailable: true, + defaultLink: new joint.shapes.ice.Wire(), + /*guard: function(evt, view) { + // FALSE means the event isn't guarded. + return false; + },*/ + validateMagnet: function(cellView, magnet) { + // Prevent to start wires from an input port + return (magnet.getAttribute('type') === 'output'); + }, + validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) { + // Prevent output-output links + if (magnetS.getAttribute('type') === 'output' && + magnetT.getAttribute('type') === 'output') { + if (magnetS !== magnetT) { + // Show warning if source and target blocks are different + warning(gettextCatalog.getString('Invalid connection')); } - }); - - paper.options.enabled = true; - paper.options.warningTimer = false; - - function warning(message) { - if (!paper.options.warningTimer) { - paper.options.warningTimer = true; - alertify.notify(message, 'warning', 5); - setTimeout(function() { - paper.options.warningTimer = false; - }, 4000); + return false; + } + // Ensure right -> left connections + if (magnetS.getAttribute('pos') === 'right') { + if (magnetT.getAttribute('pos') !== 'left') { + warning(gettextCatalog.getString('Invalid connection')); + return false; } - }; - - setGrid(paper, gridsize * 2); - - var targetElement= element[0]; - - this.panAndZoom = svgPanZoom(targetElement.childNodes[0], - { - viewportSelector: targetElement.childNodes[0].childNodes[0], - fit: false, - center: false, - zoomEnabled: true, - panEnabled: false, - zoomScaleSensitivity: 0.1, - dblClickZoomEnabled: false, - minZoom: 0.2, - maxZoom: 2, - beforeZoom: function(oldzoom, newzoom) { - }, - onZoom: function(scale) { - state.zoom = scale; - setGrid(paper, gridsize*2*state.zoom); - // Already rendered in pan - }, - beforePan: function(oldpan, newpan) { - setGrid(paper, gridsize*2*state.zoom, newpan); - }, - onPan: function(newPan) { - state.pan = newPan; - selectionView.options.state = state; - - var cells = graph.getCells(); - - _.each(cells, function(cell) { - if (!cell.isLink()) { - cell.attributes.state = state; - var elementView = paper.findViewByModel(cell); - // Pan blocks - elementView.updateBox(); - // Pan selection boxes - selectionView.updateBox(elementView.model); - } - }); + } + // Ensure bottom -> top connections + if (magnetS.getAttribute('pos') === 'bottom') { + if (magnetT.getAttribute('pos') !== 'top') { + warning(gettextCatalog.getString('Invalid connection')); + return false; } - }); - - selection = new Backbone.Collection; - selectionView = new joint.ui.SelectionView({ - paper: paper, - graph: graph, - model: selection, - state: state - }); - - // Events - - var self = this; - - selectionView.on('selection-box:pointerdown', function(evt) { - // Selection to top view - if (selection) { - selection.each(function(cell) { - var cellView = paper.findViewByModel(cell); - if (cellView) { - if (!cellView.model.isLink()) { - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - } - } - }); - } - // Toggle selection - if ((evt.which == 3) && (evt.ctrlKey || evt.metaKey)) { - var cell = selection.get($(evt.target).data('model')); - selection.reset(selection.without(cell)); - selectionView.destroySelectionBox(paper.findViewByModel(cell)); - } - }); - - paper.on('cell:pointerup', - function(cellView, evt, x, y) { - if (paper.options.enabled) { - if (!cellView.model.isLink()) { - if (evt.which == 3) { - // Disable current focus - document.activeElement.blur(); - // Right button - selection.add(cellView.model); - selectionView.createSelectionBox(cellView); - cellView.$box.removeClass('highlight'); - } - // Update wires on obstacles - var cells = graph.getCells(); - for (var i in cells) { - var cell = cells[i]; - if (cell.isLink()) { - paper.findViewByModel(cell).update(); - } - } - } - } - } - ); - - paper.on('cell:pointerdown', - function(cellView, evt, x, y) { - if (paper.options.enabled) { - if (!cellView.model.isLink()) { - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - } - } + } + var i; + var links = graph.getLinks(); + for (i in links) { + var linkIView = links[i].findView(paper); + if (linkView === linkIView) { + //Skip the wire the user is drawing + continue; } - ); - - paper.on('cell:pointerdblclick', function(cellView, evt, x, y) { - var data = cellView.model.attributes; - if (data.blockType == 'basic.input' || - data.blockType == 'basic.output') { - if (paper.options.enabled) { - alertify.prompt(gettextCatalog.getString('Update the port label'), data.data.label ? ' ' + data.data.label + ' ' : '', - function(evt, label) { - label = label.replace(/ /g, ''); - if (data.data.label != label) { - data.data.label = label; - cellView.renderLabel(); - alertify.success(gettextCatalog.getString('Label updated')); - } - }); - } + // Prevent multiple input links + if ((cellViewT.model.id === links[i].get('target').id) && + (magnetT.getAttribute('port') === links[i].get('target').port)) { + warning(gettextCatalog.getString('Invalid multiple input connections')); + return false; } - else if (data.blockType == 'basic.code') { - if (paper.options.enabled) { - var block = { - data: { - code: self.getContent(cellView.model.id) - }, - position: cellView.model.attributes.position - }; - self.createBlock('basic.code', block, function() { - cellView.model.remove(); - }); - } + // Prevent to connect a pull-up if other blocks are connected + if ((cellViewT.model.attributes.pullup) && + (cellViewS.model.id === links[i].get('source').id)) { + warning(gettextCatalog.getString('Invalid Pull up connection:
    block already connected')); + return false; } - else if (data.type != 'ice.Wire' && data.type != 'ice.Info') { - self.breadcrumbs.push({ name: data.blockType }); - if(!$rootScope.$$phase) { - $rootScope.$apply(); - } - var disabled = true; - zIndex = 1; - if (self.breadcrumbs.length == 2) { - $rootScope.$broadcast('refreshProject', function() { - self.loadGraph(dependencies[data.blockType], disabled); - self.appEnable(false); - }); - } - else { - self.loadGraph(dependencies[data.blockType], disabled); - self.appEnable(false); - } + // Prevent to connect other blocks if a pull-up is connected + if ((linkIView.targetView.model.attributes.pullup) && + (cellViewS.model.id === links[i].get('source').id)) { + warning(gettextCatalog.getString('Invalid block connection:
    Pull up already connected')); + return false; } - }); - - paper.on('blank:pointerdown', function(evt, x, y) { - // Disable current focus - document.activeElement.blur(); - - if (evt.which == 3) { - // Right button - if (paper.options.enabled) { - selectionView.startSelecting(evt, x, y); - } + } + // Ensure input -> pull-up connections + if (cellViewT.model.attributes.pullup) { + var ret = (cellViewS.model.attributes.blockType === 'basic.input'); + if (!ret) { + warning(gettextCatalog.getString('Invalid Pull up connection:
    only Input blocks allowed')); } - else if (evt.which == 1) { - // Left button - self.panAndZoom.enablePan(); + return ret; + } + // Prevent different size connections + var tsize; + var lsize = linkView.model.attributes.size; + var portId = magnetT.getAttribute('port'); + var tLeftPorts = cellViewT.model.attributes.leftPorts; + for (i in tLeftPorts) { + var port = tLeftPorts[i]; + if (portId === port.id) { + tsize = port.size; + break; } - }); - - paper.on('cell:pointerup blank:pointerup', function(cellView, evt) { - self.panAndZoom.disablePan(); - }); + } + tsize = tsize || 1; + lsize = lsize || 1; + if (tsize !== lsize) { + warning(gettextCatalog.getString('Invalid connection: {{a}} → {{b}}', { a: lsize, b: tsize })); + return false; + } + // Prevent loop links + return magnetS !== magnetT; + } + }); + + paper.options.enabled = true; + paper.options.warningTimer = false; + + function warning(message) { + if (!paper.options.warningTimer) { + paper.options.warningTimer = true; + alertify.notify(message, 'warning', 5); + setTimeout(function() { + paper.options.warningTimer = false; + }, 4000); + } + } - paper.on('cell:mouseover', - function(cellView, evt) { - if (!cellView.model.isLink()) { - cellView.$box.addClass('highlight'); - } - } - ); + var targetElement= element[0]; + + this.panAndZoom = svgPanZoom(targetElement.childNodes[0], + { + viewportSelector: targetElement.childNodes[0].childNodes[0], + fit: false, + center: false, + zoomEnabled: true, + panEnabled: false, + zoomScaleSensitivity: 0.1, + dblClickZoomEnabled: false, + minZoom: ZOOM_MIN, + maxZoom: ZOOM_MAX, + /*beforeZoom: function(oldzoom, newzoom) { + },*/ + onZoom: function(scale) { + state.zoom = scale; + // Already rendered in pan + }, + /*beforePan: function(oldpan, newpan) { + },*/ + onPan: function(newPan) { + state.pan = newPan; + selectionView.options.state = state; - paper.on('cell:mouseout', - function(cellView, evt) { - if (!cellView.model.isLink()) { - cellView.$box.removeClass('highlight'); - } - } - ); + var cells = graph.getCells(); - graph.on('change:position', function(cell) { - if (!selectionView.isTranslating()) { - // Update wires on obstacles motion - /*var cells = graph.getCells(); - for (var i in cells) { - var cell = cells[i]; - if (cell.isLink()) { - paper.findViewByModel(cell).update(); - } - }*/ + _.each(cells, function(cell) { + if (!cell.isLink()) { + cell.attributes.state = state; + var elementView = paper.findViewByModel(cell); + // Pan blocks + elementView.updateBox(); + // Pan selection boxes + selectionView.updateBox(elementView.model); } }); - }; - - this.clearAll = function() { - graph.clear(); - this.appEnable(true); - selection.reset(); - selectionView.cancelSelection(); - }; - - this.appEnable = function(value) { - paper.options.enabled = value; - if (value) { - angular.element('#menu').removeClass('disable-menu'); - angular.element('#paper').removeClass('disable-paper'); - angular.element('#banner').addClass('hidden'); - } - else { - angular.element('#menu').addClass('disable-menu'); - angular.element('#paper').addClass('disable-paper'); - angular.element('#banner').removeClass('hidden'); - } - var cells = graph.getCells(); - for (var i in cells) { - var cellView = paper.findViewByModel(cells[i].id); - cellView.options.interactive = value; - if (cells[i].attributes.type != 'ice.Generic') { - if (value) { - cellView.$el.removeClass('disable-graph'); - } - else { - cellView.$el.addClass('disable-graph'); - } - } - else if (cells[i].attributes.type != 'ice.Wire') { - if (value) { - cellView.$el.find('.port-body').removeClass('disable-graph'); - } - else { - cellView.$el.find('.port-body').addClass('disable-graph'); - } - } - } - }; - - this.createBlock = function(type, block, callback) { - var blockInstance = { - id: null, - data: {}, - type: type, - position: { x: 4 * gridsize, y: 4 * gridsize } - }; - - if (type == 'basic.code') { - utils.multiprompt( - [ gettextCatalog.getString('Enter the input ports'), - gettextCatalog.getString('Enter the output ports') ], - [ ' a , b ', - ' c , d ' ], - function(evt, ports) { - if (ports && (ports[0].length || ports[1].length)) { - blockInstance.data = { - code: '', - ports: { in: [], out: [] } - }; - // Parse ports - var inPorts = []; - var outPorts = []; - if (ports.length > 0) { - inPorts = ports[0].replace(/ /g, '').split(','); - } - if (ports.length > 1) { - outPorts = ports[1].replace(/ /g, '').split(','); - } - - for (var i in inPorts) { - if (inPorts[i]) - blockInstance.data.ports.in.push(inPorts[i]); - } - for (var o in outPorts) { - if (outPorts[o]) - blockInstance.data.ports.out.push(outPorts[o]); - } - blockInstance.position.x = 31 * gridsize; - - if (block) { - blockInstance.data.code = block.data.code; - blockInstance.position = block.position; - } - var cell = addBasicCodeBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - - if (callback) - callback(); - } - }); - } - else if (type == 'basic.info') { - blockInstance.data = { - info: '' - }; - blockInstance.position.x = 31 * gridsize; - blockInstance.position.y = 26 * gridsize; - var cell = addBasicInfoBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); + } + }); + + // Command Manager + + commandManager = new joint.dia.CommandManager({ + paper: paper, + graph: graph + }); + + // Selection View + + selection = new Backbone.Collection(); + selectionView = new joint.ui.SelectionView({ + paper: paper, + graph: graph, + model: selection, + state: state + }); + + // Events + + this.mousedown = false; + + var self = this; + $('#paper').mousemove(function(event) { + mousePosition = { + x: event.offsetX, + y: event.offsetY + }; + }); + + selectionView.on('selection-box:pointerdown', function(evt) { + // Selection to top view + if (selection) { + selection.each(function(cell) { + var cellView = paper.findViewByModel(cell); + if (!cellView.model.isLink()) { + if (cellView.$box.css('z-index') < z.index) { + cellView.$box.css('z-index', ++z.index); + } + } + }); + } + // Toggle selection + if ((evt.which === 3) && (evt.ctrlKey || evt.metaKey)) { + var cell = selection.get($(evt.target).data('model')); + selection.reset(selection.without(cell)); + selectionView.destroySelectionBox(paper.findViewByModel(cell)); + } + }); + + paper.on('cell:pointerup', function(cellView, evt/*, x, y*/) { + self.mousedown = false; + if (paper.options.enabled) { + if (!cellView.model.isLink()) { + if (evt.which === 3) { + // Disable current focus + document.activeElement.blur(); + // Right button + selection.add(cellView.model); + selectionView.createSelectionBox(cellView); + cellView.$box.removeClass('highlight'); + } + // Update wires on obstacles + var cells = graph.getCells(); + for (var i in cells) { + var cell = cells[i]; + if (cell.isLink()) { + paper.findViewByModel(cell).update(); + } + } + } + } + }); + + paper.on('cell:pointerdown', function(/*cellView*/) { + self.mousedown = true; + /*if (paper.options.enabled) { + if (!cellView.model.isLink()) { + if (cellView.$box.css('z-index') < z.index) { + cellView.$box.css('z-index', ++z.index); } } - else if (type == 'basic.input') { - alertify.prompt(gettextCatalog.getString('Enter the input ports'), ' in ', - function(evt, name) { - if (name) { - var names = name.replace(/ /g, '').split(','); - for (var n in names) { - if (names[n]) { - blockInstance.data = { - label: names[n], - pin: { - name: '', - value: 0 - } - }; - var cell = addBasicInputBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - blockInstance.position.y += 10 * gridsize; - } - } - } - else { - /*blockInstance.data = { - label: '', - pin: { - name: '', - value: 0 - } - }; - var cell = addBasicInputBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - blockInstance.position.y += 10 * gridsize;*/ - } + }*/ + }); + + paper.on('cell:pointerdblclick', function(cellView/*, evt, x, y*/) { + var type = cellView.model.attributes.blockType; + if (type.indexOf('basic.') !== -1) { + if (paper.options.enabled) { + blocks.editBasic(type, cellView, function(cell) { + addCell(cell); }); } - else if (type == 'basic.output') { - alertify.prompt(gettextCatalog.getString('Enter the output ports'), ' out ', - function(evt, name) { - if (name) { - var names = name.replace(/ /g, '').split(','); - blockInstance.position.x = 95 * gridsize; - for (var n in names) { - if (names[n]) { - blockInstance.data = { - label: names[n], - pin: { - name: '', - value: 0 - } - }; - var cell = addBasicOutputBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - blockInstance.position.y += 10 * gridsize; - } - } - } - else { - /*blockInstance.position.x = 95 * gridsize; - blockInstance.data = { - label: '', - pin: { - name: '', - value: 0 - } - }; - var cell = addBasicOutputBlock(blockInstance); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - blockInstance.position.y += 10 * gridsize;*/ - } + } + else if (dependencies[type]) { + var name = dependencies[type].package.name; + var design = dependencies[type].design; + self.breadcrumbs.push({ name: name ? name : '#', type: type }); + utils.rootScopeSafeApply(); + z.index = 1; + if (self.breadcrumbs.length === 2) { + $rootScope.$broadcast('updateProject', function() { + self.loadDesign(design, true); }); } else { - if (block && - block.graph && - block.graph.blocks && - block.graph.wires && - block.deps) { - dependencies[type] = block; - blockInstance.position.x = 6 * gridsize; - blockInstance.position.y = 16 * gridsize; - var cell = addGenericBlock(blockInstance, block); - var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } - } - else { - alertify.notify(gettextCatalog.getString('Wrong block format: {{type}}', { type: type }), 'error', 30); - } + self.loadDesign(design, true); } - }; - - this.toJSON = function() { - return graph.toJSON(); } + }); - this.getContent = function(id) { - return paper.findViewByModel(id).$box.find( - '#content' + sha1(id).toString().substring(0, 6)).val(); - } + paper.on('blank:pointerdown', function(evt, x, y) { + self.mousedown = true; + // Disable current focus + document.activeElement.blur(); - this.resetIOChoices = function() { - var cells = graph.getCells(); - // Reset choices in all i/o blocks - for (var i in cells) { - var cell = cells[i]; - var type = cell.attributes.blockType; - if (type == 'basic.input' || type == 'basic.output') { - cell.attributes.choices = boards.getPinout(); - var view = paper.findViewByModel(cell.id); - view.renderChoices(); - view.clearValue(); - } + if (evt.which === 3) { + // Right button + if (paper.options.enabled) { + selectionView.startSelecting(evt, x, y); } } - - this.cloneSelected = function() { - var self = this; - if (selection) { - selection.each(function(cell) { - var newCell = cell.clone(); - var type = cell.attributes.blockType; - var content = self.getContent(cell.id); - if (type == 'basic.code') { - newCell.attributes.data.code = content; - } - else if (type == 'basic.info') { - newCell.attributes.data.info = content; - } - newCell.translate(6 * gridsize, 6 * gridsize); - addCell(newCell); - if (type.indexOf('config.') != -1) { - paper.findViewByModel(newCell).$box.addClass('config-block'); - } - var cellView = paper.findViewByModel(newCell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); + else if (evt.which === 1) { + // Left button + self.panAndZoom.enablePan(); + } + }); + + paper.on('cell:pointerup blank:pointerup', function(/*cellView, evt*/) { + self.mousedown = false; + self.panAndZoom.disablePan(); + }); + + paper.on('cell:mouseover', function(cellView/*, evt*/) { + if (!self.mousedown) { + if (!cellView.model.isLink()) { + cellView.$box.addClass('highlight'); + if (cellView && !cellView.model.isLink()) { + if (cellView.$box.css('z-index') < z.index) { + cellView.$box.css('z-index', ++z.index); } - selection.reset(selection.without(cell)); - selectionView.cancelSelection(); - }); + } } } + }); - this.hasSelection = function() { - return selection.length > 0; - } - - this.removeSelected = function(removeDep) { - if (selection) { - selection.each(function(cell) { - selection.reset(selection.without(cell)); - selectionView.cancelSelection(); - var type = cell.attributes.blockType; - cell.remove(); - if (!typeInGraph(type)) { - // Check if it is the last "type" block - if (removeDep) { - // Remove "type" dependency in the project - removeDep(type); - } - } - }); + paper.on('cell:mouseout', function(cellView/*, evt*/) { + if (!self.mousedown) { + if (!cellView.model.isLink()) { + cellView.$box.removeClass('highlight'); } } + }); - function typeInGraph(type) { + graph.on('change:position', function(/*cell*/) { + /*if (!selectionView.isTranslating()) { + // Update wires on obstacles motion var cells = graph.getCells(); for (var i in cells) { - if (cells[i].attributes.blockType == type) { - return true; + var cell = cells[i]; + if (cell.isLink()) { + paper.findViewByModel(cell).update(); } } - return false; - }; - - this.isEmpty = function() { - return (graph.getCells().length == 0); + }*/ + }); + }; + + this.undo = function() { + disableSelected(); + commandManager.undo(state); + }; + + this.redo = function() { + disableSelected(); + commandManager.redo(state); + }; + + this.clearAll = function() { + graph.clear(); + this.appEnable(true); + selectionView.cancelSelection(); + }; + + this.appEnable = function(value) { + paper.options.enabled = value; + if (value) { + angular.element('#menu').removeClass('disable-menu'); + angular.element('#paper').removeClass('disable-paper'); + angular.element('#banner').addClass('hidden'); + } + else { + angular.element('#menu').addClass('disable-menu'); + angular.element('#paper').addClass('disable-paper'); + angular.element('#banner').removeClass('hidden'); + } + var cells = graph.getCells(); + for (var i in cells) { + var cellView = paper.findViewByModel(cells[i].id); + cellView.options.interactive = value; + if (cells[i].attributes.type !== 'ice.Generic') { + if (value) { + cellView.$el.removeClass('disable-graph'); + } + else { + cellView.$el.addClass('disable-graph'); + } } - - this.isEnabled = function() { - return paper.options.enabled; + else if (cells[i].attributes.type !== 'ice.Wire') { + // TODO: also on !mousedown + if (value) { + cellView.$el.find('.port-body').removeClass('disable-graph'); + } + else { + cellView.$el.find('.port-body').addClass('disable-graph'); + } } + } + }; + + this.createBlock = function(type, block) { + blocks.newGeneric(type, block, function(cell) { + addCell(cell); + }); + }; + + this.createBasicBlock = function(type) { + blocks.newBasic(type, function(cell) { + addCell(cell); + }); + }; + + this.toJSON = function() { + return graph.toJSON(); + }; + + this.getCells = function() { + return graph.getCells(); + }; + + this.setCells = function(cells) { + graph.attributes.cells.models = cells; + }; + + this.selectBoard = function(boardName) { + graph.startBatch('change'); + // Trigger board event + var data = { + previous: boards.selectedBoard.name, + next: boardName + }; + graph.trigger('board', { data: data }); + boards.selectBoard(boardName); + var cells = graph.getCells(); + // Reset choices in all I/O blocks + for (var i in cells) { + var cell = cells[i]; + var type = cell.attributes.blockType; + if (type === 'basic.input' || + type === 'basic.output') { + var view = paper.findViewByModel(cell.id); + cell.set('choices', boards.getPinoutHTML()); + view.clearValues(); + view.applyChoices(); + } + } + graph.stopBatch('change'); + }; - this.loadGraph = function(project, disabled) { - if (project && - project.graph && - project.graph.blocks && - project.graph.wires && - project.deps) { - - var blockInstances = project.graph.blocks; - var wires = project.graph.wires; - var deps = project.deps; - - dependencies = project.deps; - - this.clearAll(); - - this.setState(project.state); - - // Blocks - for (var i in blockInstances) { - var blockInstance = blockInstances[i]; - if (blockInstance.type == 'basic.code') { - addBasicCodeBlock(blockInstance, disabled); - } - else if (blockInstance.type == 'basic.info') { - addBasicInfoBlock(blockInstance, disabled); - } - else if (blockInstance.type == 'basic.input') { - addBasicInputBlock(blockInstance, disabled); - } - else if (blockInstance.type == 'basic.output') { - addBasicOutputBlock(blockInstance, disabled); - } - else { - addGenericBlock(blockInstance, deps[blockInstance.type]); - } - } + this.resetCommandStack = function() { + commandManager.reset(); + }; - // Wires - for (var i in wires) { - addWire(wires[i]); - } + this.cutSelected = function() { + if (selection) { + clipboard = selection.clone(); + this.removeSelected(); + } + }; - return true; + this.copySelected = function() { + if (selection) { + clipboard = selection.clone(); + } + }; + + this.pasteSelected = function() { + if (clipboard && clipboard.length > 0) { + var offset = clipboard.models[0].attributes.position; + selectionView.cancelSelection(); + var newCells = []; + clipboard.each(function(cell) { + var newCell = cell.clone(); + newCell.translate( + Math.round(((mousePosition.x - state.pan.x) / state.zoom - offset.x) / gridsize) * gridsize, + Math.round(((mousePosition.y - state.pan.y) / state.zoom - offset.y) / gridsize) * gridsize + ); + newCells.push(newCell); + }); + graph.addCells(newCells); + // Select pasted cells + _.each(newCells, function(cell) { + if (!cell.isLink()) { + var cellView = paper.findViewByModel(cell); + selection.add(cell); + selectionView.createSelectionBox(cellView); + cellView.$box.removeClass('highlight'); } - } + }); + } + }; - this.importBlock = function(type, block) { - var blockInstance = { - id: null, - data: {}, - type: type, - position: { x: 6 * gridsize, y: 16 * gridsize } - } - dependencies[type] = block; - var cell = addGenericBlock(blockInstance, block); + this.selectAll = function() { + disableSelected(); + var cells = graph.getCells(); + _.each(cells, function(cell) { + if (!cell.isLink()) { var cellView = paper.findViewByModel(cell); - if (cellView.$box.css('z-index') < zIndex) { - cellView.$box.css('z-index', ++zIndex); - } + selection.add(cell); + selectionView.createSelectionBox(cellView); + cellView.$box.removeClass('highlight'); } + }); + }; - function addBasicInputBlock(blockInstances, disabled) { - var cell = new joint.shapes.ice.Input({ - id: blockInstances.id, - blockType: blockInstances.type, - data: blockInstances.data, - label: blockInstances.data.label, - position: blockInstances.position, - disabled: disabled, - choices: boards.getPinout() - }); + this.hasSelection = function() { + return selection.length > 0; + }; - addCell(cell); - return cell; - }; + this.removeSelected = function() { + if (selection) { + graph.removeCells(selection.models); + selectionView.cancelSelection(); + } + }; - function addBasicOutputBlock(blockInstances, disabled) { - var cell = new joint.shapes.ice.Output({ - id: blockInstances.id, - blockType: blockInstances.type, - data: blockInstances.data, - label: blockInstances.data.label, - position: blockInstances.position, - disabled: disabled, - choices: boards.getPinout() - }); + $(document).on('disableSelected', function() { + disableSelected(); + }); - addCell(cell); - return cell; - }; + function disableSelected() { + if (selection) { + selectionView.cancelSelection(); + } + } - function addBasicCodeBlock(blockInstances, disabled) { - var inPorts = []; - var outPorts = []; + var stepValue = 8; - for (var i in blockInstances.data.ports.in) { - inPorts.push({ - id: blockInstances.data.ports.in[i], - label: blockInstances.data.ports.in[i], - gridUnits: 32 - }); - } + this.stepLeft = function() { + step({ x: -stepValue, y: 0 }); + }; - for (var o in blockInstances.data.ports.out) { - outPorts.push({ - id: blockInstances.data.ports.out[o], - label: blockInstances.data.ports.out[o], - gridUnits: 32 - }); - } - - var cell = new joint.shapes.ice.Code({ - id: blockInstances.id, - blockType: blockInstances.type, - data: blockInstances.data, - position: blockInstances.position, - disabled: disabled, - inPorts: inPorts, - outPorts: outPorts - }); + this.stepUp = function() { + step({ x: 0, y: -stepValue }); + }; - addCell(cell); - return cell; - }; + this.stepRight = function() { + step({ x: stepValue, y: 0 }); + }; - function addBasicInfoBlock(blockInstances, disabled) { - var cell = new joint.shapes.ice.Info({ - id: blockInstances.id, - blockType: blockInstances.type, - data: blockInstances.data, - position: blockInstances.position, - disabled: disabled - }); + this.stepDown = function() { + step({ x: 0, y: stepValue }); + }; - addCell(cell); - return cell; - }; + function step(offset) { + if (selection) { + graph.startBatch('change'); + selection.each(function(cell) { + cell.translate(offset.x, offset.y); + selectionView.updateBox(cell); + }); + graph.stopBatch('change'); + } + } - function addGenericBlock(blockInstance, block) { - var inPorts = []; - var outPorts = []; - - for (var i in block.graph.blocks) { - var item = block.graph.blocks[i]; - if (item.type == 'basic.input') { - inPorts.push({ - id: item.id, - label: item.data.label - }); - } - else if (item.type == 'basic.output') { - outPorts.push({ - id: item.id, - label: item.data.label - }); - } - } + this.isEmpty = function() { + return (graph.getCells().length === 0); + }; - var numPorts = Math.max(inPorts.length, outPorts.length); - var height = Math.max(4 * gridsize * numPorts, 8 * gridsize); + this.isEnabled = function() { + return paper.options.enabled; + }; - var gridUnits = height / gridsize; + this.setDependencies = function(_dependencies) { + dependencies = _dependencies; + }; - for (var i in inPorts) { - inPorts[i].gridUnits = gridUnits; - } - for (var o in outPorts) { - outPorts[o].gridUnits = gridUnits; - } + this.loadDesign = function(design, disabled, callback) { + if (design && + design.graph && + design.graph.blocks && + design.graph.wires) { + var i; + var self = this; + var blockInstances = design.graph.blocks; + var wires = design.graph.wires; - var blockLabel = blockInstance.type.toUpperCase(); - var width = Math.min((blockLabel.length + 8) * gridsize, 24 * gridsize); - if (blockInstance.type.indexOf('.') != -1) { - blockLabel = blockInstance.type.split('.').join(' '); - } + $('body').addClass('waiting'); - var blockImage = ''; - if (block.image && - nodeFs.existsSync(block.image) && - nodeFs.lstatSync(block.image).isFile()) { - blockImage = block.image; - width = 12 * gridsize; - } + commandManager.stopListening(); - var cell = new joint.shapes.ice.Generic({ - id: blockInstance.id, - blockType: blockInstance.type, - data: {}, - image: blockImage, - label: blockLabel, - position: blockInstance.position, - inPorts: inPorts, - outPorts: outPorts, - size: { - width: width, - height: height - } - }); + this.clearAll(); + this.setState(design.state); - addCell(cell); + setTimeout(function() { + var cell; - if (blockInstance.type.indexOf('config.') != -1) { - paper.findViewByModel(cell).$box.addClass('config-block'); + // Blocks + for (i in blockInstances) { + var blockInstance = blockInstances[i]; + if (blockInstance.type.indexOf('basic.') !== -1) { + cell = blocks.loadBasic(blockInstance, disabled); + } + else { + if (blockInstance.type in dependencies) { + cell = blocks.loadGeneric(blockInstance, dependencies[blockInstance.type]); + } + } + addCell(cell); } - return cell; - } + // Wires + for (i in wires) { + var source = graph.getCell(wires[i].source.block); + var target = graph.getCell(wires[i].target.block); + cell = blocks.loadWire(wires[i], source, target); + addCell(cell); + } - function addWire(wire) { - var source = graph.getCell(wire.source.block); - var target = graph.getCell(wire.target.block); + self.appEnable(!disabled); + $('body').removeClass('waiting'); - // Find selectors - var sourceSelector, targetSelector; - for (var _out = 0; _out < source.attributes.outPorts.length; _out++) { - if (source.attributes.outPorts[_out] == wire.source.port) { - sourcePort = _out; - break; - } + if (!disabled) { + commandManager.listen(); } - for (var _in = 0; _in < source.attributes.inPorts.length; _in++) { - if (target.attributes.inPorts[_in] == wire.target.port) { - targetPort = _in; - break; - } + + if (callback) { + callback(); } - var _wire = new joint.shapes.ice.Wire({ - source: { - id: source.id, - selector: sourceSelector, - port: wire.source.port - }, - target: { - id: target.id, - selector: targetSelector, - port: wire.target.port - }, - vertices: wire.vertices - }); + }, 20); - addCell(_wire); + return true; + } + }; + + function addCell(cell) { + cell.attributes.state = state; + //cell.attributes.zindex = z.index; + graph.addCell(cell); + if (!cell.isLink()) { + var cellView = paper.findViewByModel(cell); + if (cellView.$box.css('z-index') < z.index) { + cellView.$box.css('z-index', ++z.index); } - - function addCell(cell) { - cell.attributes.state = state; - graph.addCell(cell); } + } - }]); + }); diff --git a/app/scripts/services/profile.service.js b/app/scripts/services/profile.service.js index b13f780dc..bd04bf74a 100644 --- a/app/scripts/services/profile.service.js +++ b/app/scripts/services/profile.service.js @@ -1,35 +1,35 @@ 'use strict'; angular.module('icestudio') - .service('profile', function(nodeFs, nodePath, utils) { + .service('profile', function(utils, + nodeFs) { - const BASE_DIR = process.env.HOME || process.env.USERPROFILE; - const ICESTUDIO_DIR = nodePath.join(BASE_DIR, '.icestudio'); - const PROFILE_PATH = nodePath.join(ICESTUDIO_DIR, 'profile.json'); + this.data = { + 'language': '', + 'remoterHostname': '', + 'collection': '' + }; - this.data = { - 'language': '', - 'remoterHostname': '' + this.load = function(callback) { + var self = this; + utils.readFile(utils.PROFILE_PATH, function(data) { + if (data) { + self.data = data; } - - this.load = function(callback) { - var self = this; - utils.readFile(PROFILE_PATH, function(data) { - if (data) { - self.data = data; - } - if (callback) - callback(); - // console.log('Profile loaded'); - }); + if (callback) { + callback(); } + // console.log('Profile loaded'); + }); + }; - this.save = function() { - if (!nodeFs.existsSync(ICESTUDIO_DIR)) - nodeFs.mkdirSync(ICESTUDIO_DIR); - utils.saveFile(PROFILE_PATH, this.data, function() { - console.log('Profile saved'); - }, true); - } + this.save = function() { + if (!nodeFs.existsSync(utils.ICESTUDIO_DIR)) { + nodeFs.mkdirSync(utils.ICESTUDIO_DIR); } - ); + utils.saveFile(utils.PROFILE_PATH, this.data, function() { + console.log('Profile saved'); + }, true); + }; + + }); diff --git a/app/scripts/services/project.service.js b/app/scripts/services/project.service.js new file mode 100644 index 000000000..fe234a8dc --- /dev/null +++ b/app/scripts/services/project.service.js @@ -0,0 +1,578 @@ +'use strict'; + +angular.module('icestudio') + .service('project', function($rootScope, + graph, + boards, + compiler, + utils, + gettextCatalog, + nodeFs, + nodePath) { + + this.name = ''; // Used in File dialogs + this.path = ''; // Used in Save / Save as + this.changed = false; + + const VERSION = '1.1'; + + var project = _default(); + var allDependencies = {}; + + function _default() { + return { + version: VERSION, + package: { + name: '', + version: '', + description: '', + author: '', + image: '' + }, + design: { + board: '', + graph: { blocks: [], wires: [] }, + state: { pan: { x: 0, y: 0 }, zoom: 1.0 } + }, + dependencies: {} + }; + } + + /* Dependency format + { + package: { + name: '', + version: '', + description: '', + author: '', + image: '' + }, + design: { + graph: { blocks: [], wires: [] } + state: { pan: { x: 0, y: 0 }, zoom: 1.0 } + }, + } + */ + + this.get = function(key) { + if (key in project) { + return project[key]; + } + else { + return project; + } + }; + + this.set = function(key, obj) { + if (key in project) { + project[key] = obj; + } + }; + + this.getAllDependencies = function() { + return allDependencies; + }; + + this.new = function(name) { + this.path = ''; + project = _default(); + this.updateTitle(name); + + graph.clearAll(); + graph.resetCommandStack(); + graph.setState(project.design.state); + + alertify.success(gettextCatalog.getString('New project {{name}} created', { name: utils.bold(name) })); + }; + + this.open = function(filepath, emptyPath) { + var self = this; + this.path = emptyPath ? '' : filepath; + utils.readFile(filepath, function(data) { + if (data) { + var name = utils.basename(filepath); + self.load(name, data); + } + }); + }; + + this.load = function(name, data) { + if (data.version !== VERSION) { + alertify.notify(gettextCatalog.getString('Old project format {{version}}', { version: data.version }), 'warning', 5); + } + project = _safeLoad(data); + allDependencies = project.dependencies; + graph.setDependencies(allDependencies); + var ret = graph.loadDesign(project.design, false, function() { + graph.resetCommandStack(); + alertify.success(gettextCatalog.getString('Project {{name}} loaded', { name: utils.bold(name) })); + }); + + if (ret) { + boards.selectBoard(project.design.board); + this.updateTitle(name); + } + else { + alertify.notify(gettextCatalog.getString('Wrong project format: {{name}}', { name: utils.bold(name) }), 'error', 30); + } + }; + + function _safeLoad(data) { + // Backwards compatibility + var project = {}; + switch(data.version) { + case VERSION: + project = data; + break; + case '1.0': + project = convert10To11(data); + break; + default: + project = convertTo10(data); + project = convert10To11(project); + break; + } + return project; + } + + function convert10To11(data) { + var project = _default(); + project.package = data.package; + project.design.board = data.design.board; + project.design.state = data.design.state; + project.design.graph = data.design.graph; + + var depsInfo = findSubDependencies10(data.design.deps); + replaceType10(project, depsInfo); + for (var d in depsInfo) { + var dep = depsInfo[d]; + replaceType10(dep.content, depsInfo); + project.dependencies[dep.id] = dep.content; + } + + return project; + } + + function findSubDependencies10(deps) { + var depsInfo = {}; + for (var key in deps) { + var block = utils.clone(deps[key]); + // Go recursive + var subDepsInfo = findSubDependencies10(block.design.deps); + for (var name in subDepsInfo) { + if (!(name in depsInfo)) { + depsInfo[name] = subDepsInfo[name]; + } + } + // Add current dependency + block = pruneBlock(block); + delete block.design.deps; + block.package.name = block.package.name || key; + block.package.description = block.package.description || key; + if (!(key in depsInfo)) { + depsInfo[key] = { + id: utils.dependencyID(block), + content: block + }; + } + } + return depsInfo; + } + + function replaceType10(project, depsInfo) { + for (var i in project.design.graph.blocks) { + var type = project.design.graph.blocks[i].type; + if (type.indexOf('basic.') === -1) { + project.design.graph.blocks[i].type = depsInfo[type].id; + } + } + } + + function convertTo10(data) { + var project = { + version: '1.0', + package: { + name: '', + version: '', + description: '', + author: '', + image: '' + }, + design: { + board: '', + graph: {}, + deps: {}, + state: {} + }, + }; + for (var b in data.graph.blocks) { + var block = data.graph.blocks[b]; + switch(block.type) { + case 'basic.input': + case 'basic.output': + block.data = { + name: block.data.label, + pins: [{ + index: '0', + name: block.data.pin ? block.data.pin.name : '', + value: block.data.pin? block.data.pin.value : '0' + }], + virtual: false + }; + break; + case 'basic.constant': + block.data = { + name: block.data.label, + value: block.data.value, + local: false + }; + break; + case 'basic.code': + var params = []; + for (var p in block.data.params) { + params.push({ + name: block.data.params[p] + }); + } + var inPorts = []; + for (var i in block.data.ports.in) { + inPorts.push({ + name: block.data.ports.in[i] + }); + } + + var outPorts = []; + for (var o in block.data.ports.out) { + outPorts.push({ + name: block.data.ports.out[o] + }); + } + block.data = { + code: block.data.code, + params: params, + ports: { + in: inPorts, + out: outPorts + } + }; + break; + } + } + project.design.board = data.board; + project.design.graph = data.graph; + project.design.state = data.state; + // Safe load all dependencies recursively + for (var j in data.deps) { + project.design.deps[j] = convertTo10(data.deps[j]); + } + + return project; + } + + this.save = function(filepath) { + var name = utils.basename(filepath); + this.path = filepath; + this.updateTitle(name); + + sortGraph(); + this.update(); + utils.saveFile(filepath, project, function() { + alertify.success(gettextCatalog.getString('Project {{name}} saved', { name: utils.bold(name) })); + }, true); + }; + + function sortGraph() { + var cells = graph.getCells(); + + // Sort cells by x-coordinate + cells = _.sortBy(cells, function(cell) { + if (!cell.isLink()) { + return cell.attributes.position.x; + } + }); + + // Sort cells by y-coordinate + cells = _.sortBy(cells, function(cell) { + if (!cell.isLink()) { + return cell.attributes.position.y; + } + }); + + graph.setCells(cells); + } + + this.addAsBlock = function(filepath) { + var self = this; + utils.readFile(filepath, function(data) { + if (data.version !== VERSION) { + alertify.notify(gettextCatalog.getString('Old project format {{version}}', { version: data.version }), 'warning', 5); + } + var block = _safeLoad(data); + if (block) { + var path = utils.dirname(filepath); + // 1. Parse and find included files + var code = JSON.stringify(block); + var files = utils.findIncludedFiles(code); + // Are there included files? + if (files.length > 0) { + // 2. Check project's directory + if (self.path) { + // 3. Copy the included files + copyIncludedFiles(function(success) { + if (success) { + // 4. Success: import block + doImportBlock(block); + } + }); + } + else { + alertify.confirm(gettextCatalog.getString('This import operation requires a project path. You need to save the current project. Do you want to continue?'), + function() { + $rootScope.$emit('saveProjectAs', function() { + setTimeout(function() { + // 3. Copy the included files + copyIncludedFiles(function(success) { + if (success) { + // 4. Success: import block + doImportBlock(block); + } + }); + }, 500); + }); + }); + } + } + else { + // No included files to copy + // 4. Import block + doImportBlock(block); + } + } + + function copyIncludedFiles(callback) { + var success = true; + async.eachSeries(files, function(filename, next) { + setTimeout(function() { + var origPath = nodePath.join(path, filename); + var destPath = nodePath.join(utils.dirname(self.path), filename); + if (origPath !== destPath) { + if (nodeFs.existsSync(destPath)) { + alertify.confirm(gettextCatalog.getString('File {{file}} already exists in the project path. Do you want to replace it?', { file: utils.bold(filename) }), + function() { + success = success && doCopySync(origPath, destPath, filename); + if (!success) { + return next(); // break + } + next(); + }, + function() { + next(); + }); + } + else { + success = success && doCopySync(origPath, destPath, filename); + if (!success) { + return next(); // break + } + next(); + } + } + else { + return next(); // break + } + }, 0); + }, function(/*result*/) { + return callback(success); + }); + } + + function doCopySync(orig, dest, filename) { + var success = utils.copySync(orig, dest); + if (success) { + alertify.notify(gettextCatalog.getString('File {{file}} imported', { file: utils.bold(filename) }), 'message', 5); + } + else { + alertify.notify(gettextCatalog.getString('Original file {{file}} does not exist', { file: utils.bold(filename) }), 'error', 30); + } + return success; + } + + function doImportBlock(block) { + self.addBlock(block); + alertify.success(gettextCatalog.getString('Block {{name}} imported', { name: utils.bold(block.package.name) })); + } + }); + }; + + this.update = function(callback, updateDependencies) { + var graphData = graph.toJSON(); + + var blocks = []; + var wires = []; + + for (var c = 0; c < graphData.cells.length; c++) { + var cell = graphData.cells[c]; + + if (cell.type === 'ice.Generic' || + cell.type === 'ice.Input' || + cell.type === 'ice.Output' || + cell.type === 'ice.Code' || + cell.type === 'ice.Info' || + cell.type === 'ice.Constant') { + var block = {}; + block.id = cell.id; + block.type = cell.blockType; + block.data = cell.data; + block.position = cell.position; + if (cell.type === 'ice.Code' || + cell.type === 'ice.Info') { + delete block.data.deltas; + } + blocks.push(block); + } + else if (cell.type === 'ice.Wire') { + var wire = {}; + wire.source = { block: cell.source.id, port: cell.source.port }; + wire.target = { block: cell.target.id, port: cell.target.port }; + wire.vertices = cell.vertices; + wire.size = (cell.size > 1) ? cell.size : undefined; + wires.push(wire); + } + } + + var state = graph.getState(); + project.design.board = boards.selectedBoard.name; + project.design.graph = { blocks: blocks, wires: wires }; + project.design.state = { + pan: { + x: parseFloat(state.pan.x.toFixed(4)), + y: parseFloat(state.pan.y.toFixed(4)) + }, + zoom: parseFloat(state.zoom.toFixed(4)) + }; + + // Update dependencies + if (updateDependencies !== false) { + project.dependencies = {}; + var types = findSubDependencies(project); + for (var i in types) { + project.dependencies[types[i]] = allDependencies[types[i]]; + } + } + + if (callback) { + callback(); + } + }; + + function findSubDependencies(dependency) { + var subDependencies = []; + if (dependency) { + var blocks = dependency.design.graph.blocks; + for (var i in blocks) { + var type = blocks[i].type; + if (type.indexOf('basic.') === -1) { + subDependencies.push(type); + var newSubDependencies = findSubDependencies(allDependencies[type]); + subDependencies = subDependencies.concat(newSubDependencies); + } + } + return _.unique(subDependencies); + } + return subDependencies; + } + + this.updateTitle = function(name) { + if (name) { + this.name = name; + graph.resetBreadcrumbs(name); + } + var title = (this.changed ? '●' : '') + this.name + ' ─ Icestudio'; + utils.updateWindowTitle(title); + }; + + this.export = function(target, filepath, message) { + this.update(); + var data = compiler.generate(target, project); + utils.saveFile(filepath, data, function() { + alertify.success(message); + }, false); + }; + + this.addBasicBlock = function(type) { + graph.createBasicBlock(type); + }; + + this.addBlock = function(arg) { + if (typeof arg === 'string') { + // arg is a filepath + utils.readFile(arg, function(block) { + _addBlock(block); + }); + } + else { + // arg is a block + _addBlock(arg); + } + + function _addBlock(block) { + if (block) { + block = _safeLoad(block); + block = pruneBlock(block); + var type = utils.dependencyID(block); + mergeDependencies(type, block); + graph.createBlock(type, block); + graph.setDependencies(allDependencies); + } + } + }; + + function pruneBlock(block) { + // Remove all unnecessary information for a dependency: + // - version, board, FPGA I/O pins (->size if >1), virtual flag + delete block.version; + delete block.design.board; + var i, pins; + for (i in block.design.graph.blocks) { + if (block.design.graph.blocks[i].type === 'basic.input' || + block.design.graph.blocks[i].type === 'basic.output') { + if (block.design.graph.blocks[i].data.size === undefined) { + pins = block.design.graph.blocks[i].data.pins; + block.design.graph.blocks[i].data.size = (pins && pins.length > 1) ? pins.length : undefined; + } + delete block.design.graph.blocks[i].data.pins; + delete block.design.graph.blocks[i].data.virtual; + } + } + return block; + } + + function mergeDependencies(type, block) { + if (type in allDependencies) { + return; // If the block is already in dependencies + } + // Merge the block dependencies + var deps = block.dependencies; + for (var i in deps) { + var depType = utils.dependencyID(deps[i]); + if (!(depType in allDependencies)) { + allDependencies[depType] = deps[i]; + } + } + // Add the block as a dependency + delete block.dependencies; + allDependencies[type] = block; + } + + this.removeSelected = function() { + graph.removeSelected(); + }; + + this.clear = function() { + project = _default(); + graph.clearAll(); + graph.resetBreadcrumbs(); + graph.resetCommandStack(); + }; + + }); diff --git a/app/scripts/services/resources.service.js b/app/scripts/services/resources.service.js index 62832c6a1..0b5d98ec1 100644 --- a/app/scripts/services/resources.service.js +++ b/app/scripts/services/resources.service.js @@ -1,19 +1,47 @@ 'use strict'; angular.module('icestudio') - .service('resources', ['nodePath', 'utils', - function(nodePath, utils) { + .service('resources', function(utils, + nodePath) { - this.getExamples = function() { - return utils.getFilesRecursive(nodePath.join('resources', 'examples'), '.ice'); - } + const DEFAULT = ''; - this.getTemplates = function() { - return utils.getFilesRecursive(nodePath.join('resources', 'templates'), '.ice'); - } + this.selectedCollection = null; + this.currentCollections = []; + this.currentExamples = []; + + this.loadCollections = function() { + var defaultPath = nodePath.join('resources', 'blocks'); + var collections = [{ + 'name': DEFAULT, + 'path': nodePath.resolve(defaultPath), + 'children': utils.getFilesRecursive(defaultPath, '.ice') + }]; + this.currentCollections = collections.concat(utils.getFilesRecursive(utils.COLLECTIONS_DIR, '.ice')); + }; + + this.loadExamples = function() { + this.currentExamples = utils.getFilesRecursive(nodePath.join('resources', 'examples'), '.ice'); + }; + + this.loadCollections(); + this.loadExamples(); - this.getMenuBlocks = function() { - return utils.getFilesRecursive(nodePath.join('resources', 'blocks'), '.iceb'); + this.selectCollection = function(name) { + name = name || DEFAULT; + var selectedCollection = null; + for (var i in this.currentCollections) { + if (name === this.currentCollections[i].name) { + selectedCollection = this.currentCollections[i]; + break; } + } + if (selectedCollection === null) { + // Collection not found: select default collection + selectedCollection = this.currentCollections[0]; + } + this.selectedCollection = selectedCollection; + return selectedCollection.name; + }; - }]); + }); diff --git a/app/scripts/services/tools.service.js b/app/scripts/services/tools.service.js index 8c1027b44..ffece9ce5 100644 --- a/app/scripts/services/tools.service.js +++ b/app/scripts/services/tools.service.js @@ -1,548 +1,593 @@ 'use strict'; angular.module('icestudio') - .service('tools', ['gettextCatalog', 'gettext', 'profile', 'nodeFs', 'nodeFse', 'nodeOs', 'nodePath', 'nodeProcess', 'nodeChildProcess', 'nodeSSHexec', 'nodeRSync', 'common', 'boards', 'compiler', 'utils', - function(gettextCatalog, gettext, profile, nodeFs, nodeFse, nodeOs, nodePath, nodeProcess, nodeChildProcess, nodeSSHexec, nodeRSync, common, boards, compiler, utils) { - - var currentAlert = null; - var toolchain = { apio: '-', installed: false, disabled: false }; - - this.toolchain = toolchain; - this.buildPath = '_build'; - this.currentProjectPath = ''; - - // Check if the toolchain is installed - checkToolchain(); - - // Update toolchain information - updateToolchainInfo(); - - // Remove _build directory on start - nodeFse.removeSync(this.buildPath); - - this.verifyCode = function() { - this.apio(['verify']); - }; - - this.buildCode = function() { - this.apio(['build', '--board', boards.selectedBoard.name]); - }; - - this.uploadCode = function() { - this.apio(['upload', '--board', boards.selectedBoard.name]); - }; - - this.apio = function(commands) { - var check = true; - var code = this.generateCode(); - if (code) { - if (toolchain.installed || toolchain.disabled) { - angular.element('#menu').addClass('disable-menu'); - // Annotate strings for translation - /// Start verification ... - gettext('start_verify'); - /// Start building ... - gettext('start_build'); - /// Start uploading ... - gettext('start_upload'); - var message = 'start_' + commands[0]; - currentAlert = alertify.notify(gettextCatalog.getString(message), 'message', 100000); - $('body').addClass('waiting'); - nodeProcess.chdir(this.buildPath); - check = this.syncResources(code); - try { - if (check) { - execute(commands, commands[0], currentAlert, function() { - if (currentAlert) { - setTimeout(function() { - angular.element('#menu').removeClass('disable-menu'); - currentAlert.dismiss(true); - }, 1000); - } - }); - } - else { + .service('tools', function(project, + boards, + compiler, + profile, + resources, + utils, + gettextCatalog, + gettext, + nodeFs, + nodeFse, + nodeOs, + nodePath, + nodeProcess, + nodeChildProcess, + nodeSSHexec, + nodeRSync, + nodeUnzip) { + + var currentAlert = null; + var taskRunning = false; + var toolchain = { apio: '-', installed: false, disabled: false }; + + this.toolchain = toolchain; + const buildPath = '_build'; + + // Check if the toolchain is installed + checkToolchain(); + + // Update toolchain information + updateToolchainInfo(); + + // Remove _build directory on start + nodeFse.removeSync(buildPath); + + this.verifyCode = function() { + this.apio(['verify']); + }; + + this.buildCode = function() { + this.apio(['build', '--board', boards.selectedBoard.name]); + }; + + this.uploadCode = function() { + this.apio(['upload', '--board', boards.selectedBoard.name]); + }; + + this.apio = function(commands) { + var check = true; + if (taskRunning) { + return; + } + taskRunning = true; + var code = this.generateCode(); + if (code) { + if (toolchain.installed || toolchain.disabled) { + angular.element('#menu').addClass('disable-menu'); + // Annotate strings for translation + /// Start verification ... + gettext('start_verify'); + /// Start building ... + gettext('start_build'); + /// Start uploading ... + gettext('start_upload'); + var message = 'start_' + commands[0]; + currentAlert = alertify.notify(gettextCatalog.getString(message), 'message', 100000); + $('body').addClass('waiting'); + nodeProcess.chdir(buildPath); + check = this.syncResources(code); + try { + if (check) { + execute(commands, commands[0], currentAlert, function() { + if (currentAlert) { setTimeout(function() { angular.element('#menu').removeClass('disable-menu'); currentAlert.dismiss(true); - $('body').removeClass('waiting'); - }, 2000); + taskRunning = false; + }, 1000); } - } - catch(e) { - } - finally { - nodeProcess.chdir('..'); - } + }); } else { - alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); + setTimeout(function() { + angular.element('#menu').removeClass('disable-menu'); + currentAlert.dismiss(true); + taskRunning = false; + $('body').removeClass('waiting'); + }, 2000); } } + catch(e) { + } + finally { + nodeProcess.chdir('..'); + } } - - function checkToolchain(callback) { - var apio = utils.getApioExecutable(); - toolchain.disabled = utils.toolchainDisabled; - nodeChildProcess.exec([ - 'cd', utils.SAMPLE_DIR, (process.platform === 'win32' ? '&' : ';'), - apio, 'clean'].join(' '), function(error, stdout, stderr) { - if (!toolchain.disabled) { - toolchain.installed = !error; - if (callback) { - callback(toolchain.installed); - } + else { + alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); + } + } + }; + + function checkToolchain(callback) { + var apio = utils.getApioExecutable(); + toolchain.disabled = utils.toolchainDisabled; + nodeChildProcess.exec([ + 'cd', utils.SAMPLE_DIR, (process.platform === 'win32' ? '&' : ';'), + apio, 'clean'].join(' '), function(error/*, stdout, stderr*/) { + if (!toolchain.disabled) { + toolchain.installed = !error; + if (callback) { + callback(toolchain.installed); } + } + }); + } + + function updateToolchainInfo() { + var apio = utils.getApioExecutable(); + nodeChildProcess.exec([apio, '--version'].join(' '), function(error, stdout/*, stderr*/) { + if (error) { + toolchain.apio = '-'; + } + else { + toolchain.apio = stdout.match(/apio,\sversion\s(.+)/i)[1]; + } + }); + } + + this.generateCode = function() { + if (!nodeFs.existsSync(buildPath)) { + nodeFs.mkdirSync(buildPath); + } + project.update(); + var verilog = compiler.generate('verilog', project.get()); + var pcf = compiler.generate('pcf', project.get()); + nodeFs.writeFileSync(nodePath.join(buildPath, 'main.v'), verilog, 'utf8'); + nodeFs.writeFileSync(nodePath.join(buildPath, 'main.pcf'), pcf, 'utf8'); + return verilog; + }; + + this.syncResources = function(code) { + var ret; + + // Remove resources + nodeFse.removeSync('!(main.*)'); + + // Sync included files + ret = this.syncFiles(/@include\s(.*?)(\\n|\n|\s)/g, code); + + // Sync list files + if (ret) { + ret = this.syncFiles(/\"(.*\.list?)\"/g, code); + } + + return ret; + }; + + this.syncFiles = function(pattern, code) { + var ret = true; + var match; + while (match = pattern.exec(code)) { + var file = match[1]; + var destPath = nodePath.join('.', file); + var origPath = nodePath.join(utils.dirname(project.path), file); + + // Copy included file + var copySuccess = utils.copySync(origPath, destPath); + if (!copySuccess) { + alertify.notify(gettextCatalog.getString('File {{file}} does not exist', { file: file }), 'error', 30); + ret = false; + break; + } + } + + return ret; + }; + + function execute(commands, label, currentAlert, callback) { + var remoteHostname = profile.data.remoteHostname; + + if (remoteHostname) { + currentAlert.setContent(gettextCatalog.getString('Synchronize remote files ...')); + nodeRSync({ + src: nodeProcess.cwd() + '/', + dest: remoteHostname + ':' + buildPath + '/', + ssh: true, + recursive: true, + delete: true, + include: ['*.v', '*.pcf', '*.list'], + exclude: ['.sconsign.dblite', '*.out', '*.blif', '*.asc', '*.bin'] + }, function (error, stdout, stderr/*, cmd*/) { + if (!error) { + currentAlert.setContent(gettextCatalog.getString('Execute remote {{label}} ...', { label: label })); + nodeSSHexec('cd ' + buildPath + '; ' + (['apio'].concat(commands)).join(' '), remoteHostname, + function (error, stdout, stderr) { + processExecute(label, callback, error, stdout, stderr); + }); + } + else { + processExecute(label, callback, error, stdout, stderr); + } + }); + } + else { + var apio = utils.getApioExecutable(); + toolchain.disabled = utils.toolchainDisabled; + nodeChildProcess.exec(([apio].concat(commands)).join(' '), { maxBuffer: 5000 * 1024 }, + function(error, stdout, stderr) { + // console.log(error, stdout, stderr); + processExecute(label, callback, error, stdout, stderr); }); - } - - function updateToolchainInfo() { - var apio = utils.getApioExecutable(); - nodeChildProcess.exec([apio, '--version'].join(' '), function(error, stdout, stderr) { - if (error) { - toolchain.apio = '-'; + } + } + + function processExecute(label, callback, error, stdout, stderr) { + if (callback) { + callback(); + } + if (label) { + if (error || stderr) { + if (stdout) { + if (stdout.indexOf('[upload] Error') !== -1 || + stdout.indexOf('Error: board not detected') !== -1) { + alertify.notify(gettextCatalog.getString('Board {{name}} not detected', { name: utils.bold(boards.selectedBoard.info.label) }), 'error', 30); } - else { - toolchain.apio = stdout.match(/apio,\sversion\s(.+)/i)[1]; + else if (stdout.indexOf('Error: unkown board') !== -1) { + alertify.notify(gettextCatalog.getString('Unknown board'), 'error', 30); } - }); - } - - this.generateCode = function() { - if (!nodeFs.existsSync(this.buildPath)) - nodeFs.mkdirSync(this.buildPath); - common.refreshProject(); - var verilog = compiler.generateVerilog(common.project); - var pcf = compiler.generatePCF(common.project); - nodeFs.writeFileSync(nodePath.join(this.buildPath, 'main.v'), verilog, 'utf8'); - nodeFs.writeFileSync(nodePath.join(this.buildPath, 'main.pcf'), pcf, 'utf8'); - return verilog; - } - - this.syncResources = function(code) { - var ret = true; - - // Remove resources - nodeFse.removeSync('!(main.*)'); - - // Sync included files - if (ret) ret = this.syncFiles(/@include\s(.*?)(\\n|\n|\s)/g, code); - - // Sync list files - if (ret) ret = this.syncFiles(/\"(.*\.list?)\"/g, code); - - return ret; - } - - this.syncFiles = function(pattern, code) { - var ret = true; - var match; - while (match = pattern.exec(code)) { - var file = match[1]; - var destPath = nodePath.join('.', file); - var origPath = nodePath.join(this.currentProjectPath, file); - - // Copy included file - var copySuccess = utils.copySync(origPath, destPath, file); - if (!copySuccess) { - alertify.notify(gettextCatalog.getString('File {{file}} does not exist', { file: filename }), 'error', 30); - break; + else if (stdout.indexOf('set_io: too few arguments') !== -1) { + alertify.notify(gettextCatalog.getString('FPGA I/O ports not defined'), 'error', 30); } - } - - return ret; - } - - this.setProjectPath = function(path) { - this.currentProjectPath = path; - } - - function execute(commands, label, currentAlert, callback) { - var remoteHostname = profile.data.remoteHostname; - - if (remoteHostname) { - currentAlert.setContent(gettextCatalog.getString('Synchronize remote files ...')); - nodeRSync({ - src: nodeProcess.cwd() + '/', - dest: remoteHostname + ':' + this.buildPath + '/', - ssh: true, - recursive: true, - delete: true, - include: ['*.v', '*.pcf', '*.list'], - exclude: ['.sconsign.dblite', '*.out', '*.blif', '*.asc', '*.bin'] - }, function (error, stdout, stderr, cmd) { - if (!error) { - currentAlert.setContent(gettextCatalog.getString('Execute remote {{label}} ...', { label: label })); - nodeSSHexec('cd ' + this.buildPath + '; ' + (['apio'].concat(commands)).join(' '), remoteHostname, - function (error, stdout, stderr) { - processExecute(label, callback, error, stdout, stderr); - }); + else if (stdout.indexOf('error: unknown pin') !== -1) { + alertify.notify(gettextCatalog.getString('FPGA I/O ports not defined'), 'error', 30); + } + else if (stdout.indexOf('error: duplicate pin constraints') !== -1) { + alertify.notify(gettextCatalog.getString('Duplicated FPGA I/O ports'), 'error', 30); + } + else { + var stdoutError = stdout.split('\n').filter(function (line) { + return (line.indexOf('syntax error') !== -1 || + line.indexOf('not installed') !== -1 || + line.indexOf('error: ') !== -1 || + line.indexOf('ERROR: ') !== -1 || + line.indexOf('Error: ') !== -1 || + line.indexOf('already declared') !== -1); + }); + if (stdoutError.length > 0) { + alertify.notify(stdoutError[0], 'error', 30); } else { - processExecute(label, callback, error, stdout, stderr); + alertify.notify(stdout, 'error', 30); } - }); - } - else { - var apio = utils.getApioExecutable(); - toolchain.disabled = utils.toolchainDisabled; - nodeChildProcess.exec(([apio].concat(commands)).join(' '), { maxBuffer: 5000 * 1024 }, - function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - processExecute(label, callback, error, stdout, stderr); - }); + } } - } - - function processExecute(label, callback, error, stdout, stderr) { - if (callback) - callback(); - if (label) { - if (error || stderr) { - if (stdout) { - if (stdout.indexOf('[upload] Error') != -1 || - stdout.indexOf('Error: board not detected') != -1) { - alertify.notify(gettextCatalog.getString('Board {{name}} not detected', { name: utils.bold(boards.selectedBoard.info.label) }), 'error', 30); - } - else if (stdout.indexOf('Error: unkown board') != -1) { - alertify.notify(gettextCatalog.getString('Unknown board'), 'error', 30); - } - else if (stdout.indexOf('set_io: too few arguments') != -1) { - alertify.notify(gettextCatalog.getString('FPGA I/O ports not defined'), 'error', 30); - } - else if (stdout.indexOf('error: unknown pin') != -1) { - alertify.notify(gettextCatalog.getString('FPGA I/O ports not defined'), 'error', 30); - } - else if (stdout.indexOf('error: duplicate pin constraints') != -1) { - alertify.notify(gettextCatalog.getString('Duplicated FPGA I/O ports'), 'error', 30); - } - else { - var stdoutError = stdout.split('\n').filter(isError); - function isError(line) { - return (line.indexOf('syntax error') != -1 || - line.indexOf('not installed') != -1 || - line.indexOf('error: ') != -1 || - line.indexOf('ERROR: ') != -1 || - line.indexOf('Error: ') != -1 || - line.indexOf('already declared') != -1); - } - if (stdoutError.length > 0) { - alertify.notify(stdoutError[0], 'error', 30); - } - else { - alertify.notify(stdout, 'error', 30); - } - } - } - else if (stderr) { - if (stderr.indexOf('Could not resolve hostname') != -1 || - stderr.indexOf('Connection refused') != -1) { - alertify.notify(gettextCatalog.getString('Wrong remote hostname {{name}}', { name: profile.data.remoteHostname }), 'error', 30); - } - else if (stderr.indexOf('No route to host') != -1) { - alertify.notify(gettextCatalog.getString('Remote host {{name}} not connected', { name: profile.data.remoteHostname }), 'error', 30); - } - else { - alertify.notify(stderr, 'error', 30); - } - } + else if (stderr) { + if (stderr.indexOf('Could not resolve hostname') !== -1 || + stderr.indexOf('Connection refused') !== -1) { + alertify.notify(gettextCatalog.getString('Wrong remote hostname {{name}}', { name: profile.data.remoteHostname }), 'error', 30); + } + else if (stderr.indexOf('No route to host') !== -1) { + alertify.notify(gettextCatalog.getString('Remote host {{name}} not connected', { name: profile.data.remoteHostname }), 'error', 30); } else { - // Annotate strings for translation - /// Verification done - gettext('done_verify'); - /// Build done - gettext('done_build'); - /// Upload done - gettext('done_upload'); - var message = 'done_' + label; - alertify.success(gettextCatalog.getString(message)); - if ((label == 'build') && stdout) { - // Show used resources in the FPGA - /* - PIOs 0 / 96 - PLBs 0 / 160 - BRAMs 0 / 16 - */ - var match, - fpgaResources = '', - patterns = [ - /PIOs.+/g, - /PLBs.+/g, - /BRAMs.+/g - ]; - - for (var p in patterns) { - match = patterns[p].exec(stdout); - fpgaResources += (match && match.length > 0) ? match[0] + '\n' : ''; - } - if (fpgaResources) { - alertify.notify('
    ' + fpgaResources + '
    ', 'message', 5); - } - } + alertify.notify(stderr, 'error', 30); } - $('body').removeClass('waiting'); - } - } - - this.installToolchain = function() { - if (utils.checkDefaultToolchain()) { - utils.removeToolchain(); - installDefaultToolchain(); - } - else { - alertify.confirm(gettextCatalog.getString('Default toolchain not found. Toolchain will be downloaded. This operation requires Internet connection. Do you want to continue?'), - function() { - installOnlineToolchain(); - }); } } - - this.updateToolchain = function() { - alertify.confirm(gettextCatalog.getString('The toolchain will be updated. This operation requires Internet connection. Do you want to continue?'), - function() { - installOnlineToolchain(); - }); - } - - this.resetToolchain = function() { - if (utils.checkDefaultToolchain()) { - alertify.confirm(gettextCatalog.getString('The toolchain will be restored to default. Do you want to continue?'), - function() { - utils.removeToolchain(); - installDefaultToolchain(); - }); - } - else { - alertify.alert(gettextCatalog.getString('Error: default toolchain not found in \'{{dir}}\'', { dir: utils.TOOLCHAIN_DIR})); - } - } - - this.removeToolchain = function() { - alertify.confirm(gettextCatalog.getString('The toolchain will be removed. Do you want to continue?'), - function() { - utils.removeToolchain(); - toolchain.installed = false; - alertify.success(gettextCatalog.getString('Toolchain removed')); - }); - } - - this.enableDrivers = function() { - utils.enableDrivers(); - } - - this.disableDrivers = function() { - utils.disableDrivers(); - } - - function installDefaultToolchain() { - // Configure alert - alertify.defaults.closable = false; - - utils.disableClickEvent(); - - var content = [ - '
    ', - '

    ' + gettextCatalog.getString('Installing toolchain') + '

    ', - '
    ', - '
    ', - '
    ', - '
    ', - '
    ', - '
    '].join('\n'); - alertify.alert(content, function() { - setTimeout(function() { - initProgress(); - }, 200); - }); - - // Reset toolchain - async.series([ - ensurePythonIsAvailable, - extractVirtualEnv, - makeVenvDirectory, - extractDefaultApio, - installDefaultApio, - extractDefaultApioPackages, - installationCompleted - ]); - - // Restore alert - alertify.defaults.closable = true; - } - - function installOnlineToolchain() { - // Configure alert - alertify.defaults.closable = false; - - utils.disableClickEvent(); - - var content = [ - '
    ', - '

    ' + gettextCatalog.getString('Installing toolchain') + '

    ', - '
    ', - '
    ', - '
    ', - '
    ', - '
    ', - '
    '].join('\n'); - alertify.alert(content, function() { - setTimeout(function() { - initProgress(); - }, 200); - }); - - // Install toolchain - async.series([ - checkInternetConnection, - ensurePythonIsAvailable, - extractVirtualEnv, - makeVenvDirectory, - installOnlineApio, - apioInstallSystem, - apioInstallIcestorm, - apioInstallIverilog, - apioInstallDrivers, - apioInstallScons, - installationCompleted - ]); - - // Restore alert - alertify.defaults.closable = true; - } - - function checkInternetConnection(callback) { - updateProgress(gettextCatalog.getString('Check Internet connection...'), 0); - utils.isOnline(callback, function() { - errorProgress(gettextCatalog.getString('Internet connection required')); - utils.enableClickEvent(); - }); - } - - function ensurePythonIsAvailable(callback) { - updateProgress(gettextCatalog.getString('Check Python...'), 0); - if (utils.getPythonExecutable()) { - callback(); - } - else { - errorProgress(gettextCatalog.getString('Python 2.7 is required')); - utils.enableClickEvent(); - callback(true); - } - } - - function extractVirtualEnv(callback) { - updateProgress(gettextCatalog.getString('Extract virtual env files...'), 5); - utils.extractVirtualEnv(callback); - } - - function makeVenvDirectory(callback) { - updateProgress(gettextCatalog.getString('Make virtual env...'), 10); - utils.makeVenvDirectory(callback); - } - - // Local installation - - function extractDefaultApio(callback) { - updateProgress(gettextCatalog.getString('Extract default apio files...'), 20); - utils.extractDefaultApio(callback); - } - - function installDefaultApio(callback) { - updateProgress(gettextCatalog.getString('Install default apio...'), 40); - utils.installDefaultApio(callback); - } - - function extractDefaultApioPackages(callback) { - updateProgress(gettextCatalog.getString('Extract default apio packages...'), 70); - utils.extractDefaultApioPackages(callback); - } - - // Remote installation - - function installOnlineApio(callback) { - updateProgress('pip install -U apio', 30); - utils.installOnlineApio(callback); - } - - function apioInstallSystem(callback) { - updateProgress('apio install system', 40); - utils.apioInstall('system', callback); - } - - function apioInstallIcestorm(callback) { - updateProgress('apio install icestorm', 50); - utils.apioInstall('icestorm', callback); - } - - function apioInstallIverilog(callback) { - updateProgress('apio install iverilog', 70); - utils.apioInstall('iverilog', callback); - } - - function apioInstallDrivers(callback) { - if (nodeOs.platform().indexOf('win32') > -1) { - updateProgress('apio install drivers', 80); - utils.apioInstall('drivers', callback); - } - else { - callback(); - } - } - - function apioInstallScons(callback) { - updateProgress('apio install scons', 90); - utils.apioInstall('scons', callback); - } - - function installationCompleted(callback) { - checkToolchain(function(installed) { - if (installed) { - updateProgress(gettextCatalog.getString('Installation completed'), 100); - alertify.success(gettextCatalog.getString('Toolchain installed')); - updateToolchainInfo(); + else { + // Annotate strings for translation + /// Verification done + gettext('done_verify'); + /// Build done + gettext('done_build'); + /// Upload done + gettext('done_upload'); + var message = 'done_' + label; + alertify.success(gettextCatalog.getString(message)); + if ((label === 'build') && stdout) { + // Show used resources in the FPGA + /* + PIOs 0 / 96 + PLBs 0 / 160 + BRAMs 0 / 16 + */ + var match, + fpgaResources = '', + patterns = [ + /PIOs.+/g, + /PLBs.+/g, + /BRAMs.+/g + ]; + + for (var p in patterns) { + match = patterns[p].exec(stdout); + fpgaResources += (match && match.length > 0) ? match[0] + '\n' : ''; } - else { - errorProgress(gettextCatalog.getString('Toolchain not installed')); + if (fpgaResources) { + alertify.notify('
    ' + fpgaResources + '
    ', 'message', 5); } - utils.enableClickEvent(); - callback(); - }); - } - - function updateProgress(message, value) { - angular.element('#progress-message') - .text(message); - var bar = angular.element('#progress-bar') - if (value == 100) - bar.removeClass('progress-bar-striped active'); - bar.text(value + '%') - bar.attr('aria-valuenow', value) - bar.css('width', value + '%'); - } - - function initProgress() { - angular.element('#progress-bar') - .addClass('notransition progress-bar-info progress-bar-striped active') - .removeClass('progress-bar-danger') - .text('0%') - .attr('aria-valuenow', 0) - .css('width', '0%') - .removeClass('notransition'); - - } - - function errorProgress(message) { - angular.element('#progress-message') - .text(message); - angular.element('#progress-bar') - .addClass('notransition progress-bar-danger') - .removeClass('progress-bar-info progress-bar-striped active') - .text('Error') - .attr('aria-valuenow', 100) - .css('width', '100%'); + } } - - }]); + $('body').removeClass('waiting'); + } + } + + this.installToolchain = function() { + if (utils.checkDefaultToolchain()) { + utils.removeToolchain(); + installDefaultToolchain(); + } + else { + alertify.confirm(gettextCatalog.getString('Default toolchain not found. Toolchain will be downloaded. This operation requires Internet connection. Do you want to continue?'), + function() { + installOnlineToolchain(); + }); + } + }; + + this.updateToolchain = function() { + alertify.confirm(gettextCatalog.getString('The toolchain will be updated. This operation requires Internet connection. Do you want to continue?'), + function() { + installOnlineToolchain(); + }); + }; + + this.resetToolchain = function() { + if (utils.checkDefaultToolchain()) { + alertify.confirm(gettextCatalog.getString('The toolchain will be restored to default. Do you want to continue?'), + function() { + utils.removeToolchain(); + installDefaultToolchain(); + }); + } + else { + alertify.alert(gettextCatalog.getString('Error: default toolchain not found in \'{{dir}}\'', { dir: utils.TOOLCHAIN_DIR})); + } + }; + + this.removeToolchain = function() { + alertify.confirm(gettextCatalog.getString('The toolchain will be removed. Do you want to continue?'), + function() { + utils.removeToolchain(); + toolchain.installed = false; + alertify.success(gettextCatalog.getString('Toolchain removed')); + }); + }; + + this.enableDrivers = function() { + utils.enableDrivers(); + }; + + this.disableDrivers = function() { + utils.disableDrivers(); + }; + + function installDefaultToolchain() { + // Configure alert + alertify.defaults.closable = false; + + utils.disableClickEvent(); + + var content = [ + '
    ', + '

    ' + gettextCatalog.getString('Installing toolchain') + '

    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    '].join('\n'); + alertify.alert(content, function() { + setTimeout(function() { + initProgress(); + }, 200); + }); + + // Reset toolchain + async.series([ + ensurePythonIsAvailable, + extractVirtualEnv, + makeVenvDirectory, + extractDefaultApio, + installDefaultApio, + extractDefaultApioPackages, + installationCompleted + ]); + + // Restore alert + alertify.defaults.closable = true; + } + + function installOnlineToolchain() { + // Configure alert + alertify.defaults.closable = false; + + utils.disableClickEvent(); + + var content = [ + '
    ', + '

    ' + gettextCatalog.getString('Installing toolchain') + '

    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    ', + '
    '].join('\n'); + alertify.alert(content, function() { + setTimeout(function() { + initProgress(); + }, 200); + }); + + // Install toolchain + async.series([ + checkInternetConnection, + ensurePythonIsAvailable, + extractVirtualEnv, + makeVenvDirectory, + installOnlineApio, + apioInstallSystem, + apioInstallIcestorm, + apioInstallIverilog, + apioInstallDrivers, + apioInstallScons, + installationCompleted + ]); + + // Restore alert + alertify.defaults.closable = true; + } + + function checkInternetConnection(callback) { + updateProgress(gettextCatalog.getString('Check Internet connection...'), 0); + utils.isOnline(callback, function() { + errorProgress(gettextCatalog.getString('Internet connection required')); + utils.enableClickEvent(); + }); + } + + function ensurePythonIsAvailable(callback) { + updateProgress(gettextCatalog.getString('Check Python...'), 0); + if (utils.getPythonExecutable()) { + callback(); + } + else { + errorProgress(gettextCatalog.getString('Python 2.7 is required')); + utils.enableClickEvent(); + callback(true); + } + } + + function extractVirtualEnv(callback) { + updateProgress(gettextCatalog.getString('Extract virtual env files...'), 5); + utils.extractVirtualEnv(callback); + } + + function makeVenvDirectory(callback) { + updateProgress(gettextCatalog.getString('Make virtual env...'), 10); + utils.makeVenvDirectory(callback); + } + + // Local installation + + function extractDefaultApio(callback) { + updateProgress(gettextCatalog.getString('Extract default apio files...'), 20); + utils.extractDefaultApio(callback); + } + + function installDefaultApio(callback) { + updateProgress(gettextCatalog.getString('Install default apio...'), 40); + utils.installDefaultApio(callback); + } + + function extractDefaultApioPackages(callback) { + updateProgress(gettextCatalog.getString('Extract default apio packages...'), 70); + utils.extractDefaultApioPackages(callback); + } + + // Remote installation + + function installOnlineApio(callback) { + updateProgress('pip install -U apio', 30); + utils.installOnlineApio(callback); + } + + function apioInstallSystem(callback) { + updateProgress('apio install system', 40); + utils.apioInstall('system', callback); + } + + function apioInstallIcestorm(callback) { + updateProgress('apio install icestorm', 50); + utils.apioInstall('icestorm', callback); + } + + function apioInstallIverilog(callback) { + updateProgress('apio install iverilog', 70); + utils.apioInstall('iverilog', callback); + } + + function apioInstallDrivers(callback) { + if (nodeOs.platform().indexOf('win32') > -1) { + updateProgress('apio install drivers', 80); + utils.apioInstall('drivers', callback); + } + else { + callback(); + } + } + + function apioInstallScons(callback) { + updateProgress('apio install scons', 90); + utils.apioInstall('scons', callback); + } + + function installationCompleted(callback) { + checkToolchain(function(installed) { + if (installed) { + updateProgress(gettextCatalog.getString('Installation completed'), 100); + alertify.success(gettextCatalog.getString('Toolchain installed')); + updateToolchainInfo(); + } + else { + errorProgress(gettextCatalog.getString('Toolchain not installed')); + } + utils.enableClickEvent(); + callback(); + }); + } + + function updateProgress(message, value) { + angular.element('#progress-message') + .text(message); + var bar = angular.element('#progress-bar'); + if (value === 100) { + bar.removeClass('progress-bar-striped active'); + } + bar.text(value + '%'); + bar.attr('aria-valuenow', value); + bar.css('width', value + '%'); + } + + function initProgress() { + angular.element('#progress-bar') + .addClass('notransition progress-bar-info progress-bar-striped active') + .removeClass('progress-bar-danger') + .text('0%') + .attr('aria-valuenow', 0) + .css('width', '0%') + .removeClass('notransition'); + } + + function errorProgress(message) { + angular.element('#progress-message') + .text(message); + angular.element('#progress-bar') + .addClass('notransition progress-bar-danger') + .removeClass('progress-bar-info progress-bar-striped active') + .text('Error') + .attr('aria-valuenow', 100) + .css('width', '100%'); + } + + // Collections management + + this.addCollection = function(filepath) { + var name = utils.basename(filepath); + nodeFs.createReadStream(filepath) + .pipe(nodeUnzip.Extract({ path: utils.COLLECTIONS_DIR })) + .on('close', function() { + resources.loadCollections(); + alertify.success(gettextCatalog.getString('Collection file {{name}} added', { name: utils.bold(name) })); + }); + }; + + this.removeCollection = function(collection) { + utils.deleteFolderRecursive(collection.path); + resources.loadCollections(); + alertify.success(gettextCatalog.getString('Collection {{name}} removed', { name: utils.bold(collection.name) })); + }; + + this.removeAllCollections = function() { + utils.removeCollections(); + resources.loadCollections(); + alertify.success(gettextCatalog.getString('All collections removed')); + }; + + }); diff --git a/app/scripts/services/utils.service.js b/app/scripts/services/utils.service.js index 4b83d2ca3..e08240df3 100644 --- a/app/scripts/services/utils.service.js +++ b/app/scripts/services/utils.service.js @@ -2,651 +2,947 @@ 'use strict'; angular.module('icestudio') - .service('utils', ['gettextCatalog', 'nodeFs', 'nodeFse', 'nodeOs', 'nodePath', 'nodeChildProcess', 'nodeTarball', 'nodeZlib', 'nodeSudo', 'nodeOnline', 'nodeGlob', '_package', - function(gettextCatalog, nodeFs, nodeFse, nodeOs, nodePath, nodeChildProcess, nodeTarball, nodeZlib, nodeSudo, nodeOnline, nodeGlob, _package) { - - const WIN32 = Boolean(process.platform.indexOf('win32') > -1); - const DARWIN = Boolean(process.platform.indexOf('darwin') > -1); - const LINUX = Boolean(process.platform.indexOf('linux') > -1); - - const CACHE = '_cache'; - - const VENV = 'virtualenv-15.0.1'; - const VENV_DIR = nodePath.join(CACHE, VENV); - const VENV_TARGZ = nodePath.join('resources', 'virtualenv', VENV + '.tar.gz'); - - const SAMPLE_DIR = nodePath.join('resources', 'sample'); - this.SAMPLE_DIR = SAMPLE_DIR; - - const LOCALE_DIR = nodePath.join('resources', 'locale'); - - const APP_DIR = nodePath.dirname(process.execPath); - const TOOLCHAIN_DIR = nodePath.join(APP_DIR, 'toolchain'); - this.TOOLCHAIN_DIR = TOOLCHAIN_DIR; - - const DEFAULT_APIO = 'default-apio'; - const DEFAULT_APIO_DIR = nodePath.join(CACHE, DEFAULT_APIO); - const DEFAULT_APIO_TARGZ = nodePath.join(TOOLCHAIN_DIR, DEFAULT_APIO + '.tar.gz'); - - const DEFAULT_APIO_PACKAGES = 'default-apio-packages'; - const DEFAULT_APIO_PACKAGES_TARGZ = nodePath.join(TOOLCHAIN_DIR, DEFAULT_APIO_PACKAGES + '.tar.gz'); - - const BASE_DIR = process.env.HOME || process.env.USERPROFILE; - const ICESTUDIO_DIR = nodePath.join(BASE_DIR, '.icestudio'); - const APIO_HOME_DIR = nodePath.join(ICESTUDIO_DIR, 'apio'); - - const ENV_DIR = _get_env_dir(nodePath.join(ICESTUDIO_DIR, 'venv')); - const ENV_BIN_DIR = nodePath.join(ENV_DIR, WIN32 ? 'Scripts' : 'bin'); - const ENV_PIP = nodePath.join(ENV_BIN_DIR, 'pip'); - const ENV_APIO = nodePath.join(ENV_BIN_DIR, WIN32 ? 'apio.exe' : 'apio'); - const APIO_CMD = (WIN32 ? 'set' : 'export') + ' APIO_HOME_DIR=' + APIO_HOME_DIR + (WIN32 ? '& ' : '; ') + ENV_APIO; - const SYSTEM_APIO = '/usr/bin/apio'; - - function _get_env_dir(defaultEnvDir) { - if (WIN32) { - // Put the env directory to the root of the current local disk when - // default path contains non-ASCII characters. Virtualenv will fail to - for (var i in defaultEnvDir) { - var char = defaultEnvDir[i]; - if (char.charCodeAt(0) > 127) { - var defaultEnvDirFormat = nodeOs.parse(defaultEnvDir); - return nodeOs.format({ - root: defaultEnvDirFormat.root, - dir: defaultEnvDirFormat.root, - base: '.icestudiovenv', - name: '.icestudiovenv', - }); - } - } + .service('utils', function($rootScope, + gettextCatalog, + _package, + window, + nodeFs, + nodeFse, + nodeOs, + nodePath, + nodeChildProcess, + nodeTarball, + nodeZlib, + nodeSudo, + nodeOnline, + nodeGlob, + nodeSha1, + SVGO) { + + const WIN32 = Boolean(process.platform.indexOf('win32') > -1); + const DARWIN = Boolean(process.platform.indexOf('darwin') > -1); + + const CACHE = '_cache'; + + const VENV = 'virtualenv-15.0.1'; + const VENV_DIR = nodePath.join(CACHE, VENV); + const VENV_TARGZ = nodePath.join('resources', 'virtualenv', VENV + '.tar.gz'); + + const SAMPLE_DIR = nodePath.join('resources', 'sample'); + this.SAMPLE_DIR = SAMPLE_DIR; + + const LOCALE_DIR = nodePath.join('resources', 'locale'); + + const APP_DIR = nodePath.dirname(process.execPath); + const TOOLCHAIN_DIR = nodePath.join(APP_DIR, 'toolchain'); + this.TOOLCHAIN_DIR = TOOLCHAIN_DIR; + + const DEFAULT_APIO = 'default-apio'; + const DEFAULT_APIO_DIR = nodePath.join(CACHE, DEFAULT_APIO); + const DEFAULT_APIO_TARGZ = nodePath.join(TOOLCHAIN_DIR, DEFAULT_APIO + '.tar.gz'); + + const DEFAULT_APIO_PACKAGES = 'default-apio-packages'; + const DEFAULT_APIO_PACKAGES_TARGZ = nodePath.join(TOOLCHAIN_DIR, DEFAULT_APIO_PACKAGES + '.tar.gz'); + + const BASE_DIR = process.env.HOME || process.env.USERPROFILE; + const ICESTUDIO_DIR = nodePath.join(BASE_DIR, '.icestudio'); + this.ICESTUDIO_DIR = ICESTUDIO_DIR; + const COLLECTIONS_DIR = nodePath.join(ICESTUDIO_DIR, 'collections'); + this.COLLECTIONS_DIR = COLLECTIONS_DIR; + const APIO_HOME_DIR = nodePath.join(ICESTUDIO_DIR, 'apio'); + const PROFILE_PATH = nodePath.join(ICESTUDIO_DIR, 'profile.json'); + this.PROFILE_PATH = PROFILE_PATH; + + const ENV_DIR = _getEnvDir(nodePath.join(ICESTUDIO_DIR, 'venv')); + const ENV_BIN_DIR = nodePath.join(ENV_DIR, WIN32 ? 'Scripts' : 'bin'); + const ENV_PIP = nodePath.join(ENV_BIN_DIR, 'pip'); + const ENV_APIO = nodePath.join(ENV_BIN_DIR, WIN32 ? 'apio.exe' : 'apio'); + const APIO_CMD = (WIN32 ? 'set' : 'export') + ' APIO_HOME_DIR=' + APIO_HOME_DIR + (WIN32 ? '& ' : '; ') + ENV_APIO; + const SYSTEM_APIO = '/usr/bin/apio'; + + function _getEnvDir(defaultEnvDir) { + if (WIN32) { + // Put the env directory to the root of the current local disk when + // default path contains non-ASCII characters. Virtualenv will fail to + for (var i in defaultEnvDir) { + var char = defaultEnvDir[i]; + if (char.charCodeAt(0) > 127) { + var defaultEnvDirFormat = nodeOs.parse(defaultEnvDir); + return nodeOs.format({ + root: defaultEnvDirFormat.root, + dir: defaultEnvDirFormat.root, + base: '.icestudiovenv', + name: '.icestudiovenv', + }); } - - return defaultEnvDir; } + } - var _pythonExecutableCached = null; - // Get the system executable - this.getPythonExecutable = function() { - if (!_pythonExecutableCached) { - const possibleExecutables = []; + return defaultEnvDir; + } - if (WIN32) { - possibleExecutables.push('python.exe'); - possibleExecutables.push('C:\\Python27\\python.exe'); - } else { - possibleExecutables.push('python2.7'); - possibleExecutables.push('python'); - } + var _pythonExecutableCached = null; + // Get the system executable + this.getPythonExecutable = function() { + if (!_pythonExecutableCached) { + const possibleExecutables = []; - for (var i in possibleExecutables) { - var executable = possibleExecutables[i]; - if (isPython2(executable)) { - _pythonExecutableCached = executable; - break; - } - } - } - return _pythonExecutableCached; + if (WIN32) { + possibleExecutables.push('python.exe'); + possibleExecutables.push('C:\\Python27\\python.exe'); + } else { + possibleExecutables.push('python2.7'); + possibleExecutables.push('python'); } - function isPython2(executable) { - const args = ['-c', 'import sys; print \'.\'.join(str(v) for v in sys.version_info[:2])']; - try { - const result = nodeChildProcess.spawnSync(executable, args); - return 0 === result.status && result.stdout.toString().startsWith('2.7'); - } catch(e) { - return false; + for (var i in possibleExecutables) { + var executable = possibleExecutables[i]; + if (isPython2(executable)) { + _pythonExecutableCached = executable; + break; } } - - this.extractTargz = function(source, destination, callback) { - nodeTarball.extractTarball(source, destination, function(err) { - if(err) { - //console.log(err); - callback(true); - } - else { - callback(); - } - }); - } - - this.extractVirtualEnv = function(callback) { - this.extractTargz(VENV_TARGZ, CACHE, callback); - } - - function disableClick(e) { - e.stopPropagation(); - e.preventDefault(); - } - - function enableClickEvent() { - document.removeEventListener('click', disableClick, true); - } - - function disableClickEvent() { - document.addEventListener('click', disableClick, true); - } - - this.enableClickEvent = enableClickEvent; - this.disableClickEvent = disableClickEvent; - - this.executeCommand = function(command, callback) { - nodeChildProcess.exec(command.join(' '), - function (error, stdout, stderr) { - // console.log(error, stdout, stderr); - if (error) { - enableClickEvent(); - callback(true); - angular.element('#progress-message') - .text(stderr); - angular.element('#progress-bar') - .addClass('notransition progress-bar-danger') - .removeClass('progress-bar-info progress-bar-striped active') - .text('Error') - .attr('aria-valuenow', 100) - .css('width', '100%'); - } - else { - callback(); - } - } - ); - } - - this.makeVenvDirectory = function(callback) { - if (!nodeFs.existsSync(ICESTUDIO_DIR)) { - nodeFs.mkdirSync(ICESTUDIO_DIR); - } - if (!nodeFs.existsSync(ENV_DIR)) { - nodeFs.mkdirSync(ENV_DIR); - this.executeCommand( - [this.getPythonExecutable(), nodePath.join(VENV_DIR, 'virtualenv.py'), ENV_DIR], callback) + } + return _pythonExecutableCached; + }; + + function isPython2(executable) { + const args = ['-c', 'import sys; print \'.\'.join(str(v) for v in sys.version_info[:2])']; + try { + const result = nodeChildProcess.spawnSync(executable, args); + return 0 === result.status && result.stdout.toString().startsWith('2.7'); + } catch(e) { + return false; + } + } + + this.extractTargz = function(source, destination, callback) { + nodeTarball.extractTarball(source, destination, function(err) { + if(err) { + //console.log(err); + callback(true); + } + else { + callback(); + } + }); + }; + + this.extractVirtualEnv = function(callback) { + this.extractTargz(VENV_TARGZ, CACHE, callback); + }; + + function disableClick(e) { + e.stopPropagation(); + e.preventDefault(); + } + + function enableClickEvent() { + document.removeEventListener('click', disableClick, true); + } + + function disableClickEvent() { + document.addEventListener('click', disableClick, true); + } + + this.enableClickEvent = enableClickEvent; + this.disableClickEvent = disableClickEvent; + + this.executeCommand = function(command, callback) { + nodeChildProcess.exec(command.join(' '), + function (error, stdout, stderr) { + // console.log(error, stdout, stderr); + if (error) { + enableClickEvent(); + callback(true); + angular.element('#progress-message') + .text(stderr); + angular.element('#progress-bar') + .addClass('notransition progress-bar-danger') + .removeClass('progress-bar-info progress-bar-striped active') + .text('Error') + .attr('aria-valuenow', 100) + .css('width', '100%'); } else { callback(); } } - - this.checkDefaultToolchain = function() { - try { - // TODO: use tar.gz with sha1 - return nodeFs.statSync(TOOLCHAIN_DIR).isDirectory(); + ); + }; + + this.makeVenvDirectory = function(callback) { + if (!nodeFs.existsSync(ICESTUDIO_DIR)) { + nodeFs.mkdirSync(ICESTUDIO_DIR); + } + if (!nodeFs.existsSync(ENV_DIR)) { + nodeFs.mkdirSync(ENV_DIR); + this.executeCommand( + [this.getPythonExecutable(), nodePath.join(VENV_DIR, 'virtualenv.py'), ENV_DIR], callback); + } + else { + callback(); + } + }; + + this.checkDefaultToolchain = function() { + try { + // TODO: use tar.gz with sha1 + return nodeFs.statSync(TOOLCHAIN_DIR).isDirectory(); + } + catch (err) { + return false; + } + }; + + this.extractDefaultApio = function(callback) { + this.extractTargz(DEFAULT_APIO_TARGZ, DEFAULT_APIO_DIR, callback); + }; + + this.installDefaultApio = function(callback) { + var self = this; + nodeGlob(nodePath.join(DEFAULT_APIO_DIR, '*.*'), {}, function (error, files) { + if (!error) { + self.executeCommand([ENV_PIP, 'install', '-U', '--no-deps'].concat(files), callback); + } + }); + }; + + this.extractDefaultApioPackages = function(callback) { + this.extractTargz(DEFAULT_APIO_PACKAGES_TARGZ, APIO_HOME_DIR, callback); + }; + + this.isOnline = function(callback, error) { + nodeOnline({ + timeout: 5000 + }, function(err, online) { + if (online) { + callback(); + } + else { + error(); + callback(true); + } + }); + }; + + this.installOnlineApio = function(callback) { + this.executeCommand([ENV_PIP, 'install', '-U', 'apio">=' + _package.apio.min + ',<' + _package.apio.max + '"'], callback); + }; + + this.apioInstall = function(_package, callback) { + this.executeCommand([APIO_CMD, 'install', _package], callback); + }; + + this.toolchainDisabled = false; + + this.getApioExecutable = function() { + var candidateApio = process.env.ICESTUDIO_APIO ? process.env.ICESTUDIO_APIO : SYSTEM_APIO; + if (nodeFs.existsSync(candidateApio)) { + if (!this.toolchainDisabled) { + // Show message only on start + alertify.notify('Using system wide apio', 'message', 5); + } + this.toolchainDisabled = true; + return candidateApio; + } + this.toolchainDisabled = false; + return APIO_CMD; + }; + + this.removeToolchain = function() { + deleteFolderRecursive(ENV_DIR); + deleteFolderRecursive(APIO_HOME_DIR); + }; + + this.removeCollections = function() { + deleteFolderRecursive(COLLECTIONS_DIR); + }; + + this.deleteFolderRecursive = deleteFolderRecursive; + + function deleteFolderRecursive(path) { + if (nodeFs.existsSync(path)) { + nodeFs.readdirSync(path).forEach(function(file/*, index*/) { + var curPath = nodePath.join(path, file); + if (nodeFs.lstatSync(curPath).isDirectory()) { // recursive + deleteFolderRecursive(curPath); } - catch (err) { - return false; + else { // delete file + nodeFs.unlinkSync(curPath); } - } - - this.extractDefaultApio = function(callback) { - this.extractTargz(DEFAULT_APIO_TARGZ, DEFAULT_APIO_DIR, callback); - } - - this.installDefaultApio = function(callback) { - var self = this; - nodeGlob(nodePath.join(DEFAULT_APIO_DIR, '*.*'), {}, function (error, files) { - if (!error) { - self.executeCommand([ENV_PIP, 'install', '-U', '--no-deps'].concat(files), callback); - } - }); - } - - this.extractDefaultApioPackages = function(callback) { - this.extractTargz(DEFAULT_APIO_PACKAGES_TARGZ, APIO_HOME_DIR, callback); - } - - this.isOnline = function(callback, error) { - nodeOnline({ - timeout: 5000 - }, function(err, online) { - if (online) { + }); + nodeFs.rmdirSync(path); + } + } + + this.sep = nodePath.sep; + + this.basename = basename; + function basename(filepath) { + return nodePath.basename(filepath).split('.')[0]; + } + + this.dirname = function(filepath) { + return nodePath.dirname(filepath); + }; + + this.readFile = function(filepath, callback) { + nodeFs.readFile(filepath, + function(err, data) { + if (!err) { + decompressJSON(data, callback); + } + else { + if (callback) { callback(); } - else { - error(); - callback(true); - } - }); - } - - this.installOnlineApio = function(callback) { - this.executeCommand([ENV_PIP, 'install', '-U', 'apio">=' + _package.apio.min + ',<' + _package.apio.max + '"'], callback); - } - - this.apioInstall = function(_package, callback) { - this.executeCommand([APIO_CMD, 'install', _package], callback); - } - - this.toolchainDisabled = false; - - this.getApioExecutable = function() { - var candidate_apio = process.env.ICESTUDIO_APIO ? process.env.ICESTUDIO_APIO : SYSTEM_APIO; - if (nodeFs.existsSync(candidate_apio)) { - if (!this.toolchainDisabled) { - // Show message only on start - alertify.notify('Using system wide apio', 'message', 5); - } - this.toolchainDisabled = true; - return candidate_apio; - } - this.toolchainDisabled = false; - return APIO_CMD; - } - - this.removeToolchain = function() { - deleteFolderRecursive(ENV_DIR); - deleteFolderRecursive(APIO_HOME_DIR); - } - - var deleteFolderRecursive = function(path) { - if (nodeFs.existsSync(path)) { - nodeFs.readdirSync(path).forEach(function(file, index) { - var curPath = nodePath.join(path, file); - if (nodeFs.lstatSync(curPath).isDirectory()) { // recursive - deleteFolderRecursive(curPath); - } - else { // delete file - nodeFs.unlinkSync(curPath); - } - }); - nodeFs.rmdirSync(path); } - } - - this.sep = nodePath.sep; + }); + }; - this.basename = basename; - function basename(filepath) { - return nodePath.basename(filepath).split('.')[0]; - } - - this.dirname = function(filepath) { - return nodePath.dirname(filepath); - } + var saveBin = false; - this.readFile = function(filepath, callback) { - nodeFs.readFile(filepath, - function(err, data) { - if (!err) { - decompressJSON(data, callback); - } - else { - if (callback) - callback(); - } + this.saveFile = function(filepath, content, callback, compress) { + if (compress) { + compressJSON(content, function(compressed) { + nodeFs.writeFile(filepath, compressed, saveBin ? 'binary' : null, + function(err) { + if (!err && callback) { + callback(); + } }); - } - - var saveBin = false; - - this.saveFile = function(filepath, content, callback, compress) { - if (compress) { - compressJSON(content, function(compressed) { - nodeFs.writeFile(filepath, compressed, saveBin ? 'binary' : null, - function(err) { - if (!err && callback) { - callback(); - } - }); - }); - } - else { - nodeFs.writeFile(filepath, content, function(err) { - if (!err && callback) { - callback(); - } - }); + }); + } + else { + nodeFs.writeFile(filepath, content, function(err) { + if (!err && callback) { + callback(); } - } - - function compressJSON(json, callback) { - if (!saveBin) { - if (callback) - callback(JSON.stringify(json, null, 2)); + }); + } + }; + + function compressJSON(json, callback) { + if (!saveBin) { + if (callback) { + callback(JSON.stringify(json, null, 2)); + } + } + else { + var data = JSON.stringify(json); + nodeZlib.gzip(data, function (_, result) { + if (callback) { + callback(result); } - else { - var data = JSON.stringify(json); - nodeZlib.gzip(data, function (_, result) { - if (callback) - callback(result); - }); + }); + } + } + + function decompressJSON(json, callback) { + var data = isJSON(json); + if (data) { + if (callback) { + callback(data); + } + } + else { + nodeZlib.gunzip(json, function(_, uncompressed) { + var result = JSON.parse(uncompressed); + if (callback) { + callback(result); } - } - - function decompressJSON(json, callback) { - var data = isJSON(json); - if (data) { - if (callback) - callback(data); - } - else { - nodeZlib.gunzip(json, function(_, uncompressed) { - var result = JSON.parse(uncompressed); - if (callback) - callback(result); + }); + } + } + + function isJSON(str) { + var result = false; + try { + result = JSON.parse(str); + } catch (e) { + return false; + } + return result; + } + + this.getFilesRecursive = getFilesRecursive; + + function getFilesRecursive(folder, extension) { + var fileTree = []; + if (nodeFs.existsSync(folder)) { + var fileContents = nodeFs.readdirSync(folder); + var stats; + + fileContents.forEach(function (fileName) { + var filePath = nodePath.join(folder, fileName); + stats = nodeFs.lstatSync(filePath); + + if (stats.isDirectory()) { + fileTree.push({ + name: fileName, + path: filePath, + children: getFilesRecursive(filePath, extension) }); - } - } - - function isJSON(str) { - var result = false; - try { - result = JSON.parse(str); - } catch (e) { - return false; - } - return result; - } - - this.getFilesRecursive = getFilesRecursive; - - function getFilesRecursive(folder, extension) { - var fileContents = nodeFs.readdirSync(folder), - fileTree = [], - stats; - - fileContents.forEach(function (fileName) { - var filePath = nodePath.join(folder, fileName); - stats = nodeFs.lstatSync(filePath); - - if (stats.isDirectory()) { + } else { + if (fileName.endsWith(extension)) { fileTree.push({ - name: fileName, - children: getFilesRecursive(filePath, extension) + name: basename(fileName), + path: filePath }); - } else { - if (fileName.endsWith(extension)) { - var content = JSON.parse(nodeFs.readFileSync(filePath).toString()); - fileTree.push({ - name: basename(fileName), - content: content - }); - } } - }); - - return fileTree; - } - - this.enableDrivers = function() { - if (WIN32) { - enableWindowsDrivers(); } - else if (DARWIN) { - enableDarwinDrivers(); - } - else { - linuxDrivers(true); - } - } - - this.disableDrivers = function() { - if (WIN32) { - disableWindowsDrivers(); - } - else if (DARWIN) { - disableDarwinDrivers(); - } - else { - linuxDrivers(false); - } - } - - function linuxDrivers(enable) { + }); + } + return fileTree; + } + + this.enableDrivers = function() { + if (WIN32) { + enableWindowsDrivers(); + } + else if (DARWIN) { + enableDarwinDrivers(); + } + else { + linuxDrivers(true); + } + }; + + this.disableDrivers = function() { + if (WIN32) { + disableWindowsDrivers(); + } + else if (DARWIN) { + disableDarwinDrivers(); + } + else { + linuxDrivers(false); + } + }; + + function linuxDrivers(enable) { + var commands; + if (enable) { + commands = [ + 'cp ' + nodePath.resolve('resources/config/80-icestick.rules') + ' /etc/udev/rules.d/80-icestick.rules', + 'service udev restart' + ]; + } + else { + commands = [ + 'rm /etc/udev/rules.d/80-icestick.rules', + 'service udev restart' + ]; + } + var command = 'sh -c "' + commands.join('; ') + '"'; + + beginLazyProcess(); + nodeSudo.exec(command, {name: 'Icestudio'}, function(error/*, stdout, stderr*/) { + // console.log(error, stdout, stderr); + endLazyProcess(); + if (!error) { if (enable) { - var commands = [ - 'cp ' + nodePath.resolve('resources/config/80-icestick.rules') + ' /etc/udev/rules.d/80-icestick.rules', - 'service udev restart' - ]; + alertify.success(gettextCatalog.getString('Drivers enabled')); } else { - var commands = [ - 'rm /etc/udev/rules.d/80-icestick.rules', - 'service udev restart' - ]; + alertify.warning(gettextCatalog.getString('Drivers disabled')); } - var command = 'sh -c "' + commands.join('; ') + '"'; - - beginLazyProcess(); - nodeSudo.exec(command, {name: 'Icestudio'}, function(error, stdout, stderr) { + setTimeout(function() { + alertify.notify(gettextCatalog.getString('Unplug and reconnect the board'), 'message', 5); + }, 1000); + } + }); + } + + function enableDarwinDrivers() { + var commands = [ + 'kextunload -b com.FTDI.driver.FTDIUSBSerialDriver -q || true', + 'kextunload -b com.apple.driver.AppleUSBFTDI -q || true' + ]; + var command = 'sh -c "' + commands.join('; ') + '"'; + + beginLazyProcess(); + nodeSudo.exec(command, {name: 'Icestudio'}, function(error/*, stdout, stderr*/) { + // console.log(error, stdout, stderr); + if (error) { + endLazyProcess(); + } + else { + var brewCommands = [ + '/usr/local/bin/brew update', + '/usr/local/bin/brew install --force libftdi', + '/usr/local/bin/brew unlink libftdi', + '/usr/local/bin/brew link --force libftdi', + '/usr/local/bin/brew install --force libffi', + '/usr/local/bin/brew unlink libffi', + '/usr/local/bin/brew link --force libffi' + ]; + nodeChildProcess.exec(brewCommands.join('; '), function(error, stdout, stderr) { // console.log(error, stdout, stderr); endLazyProcess(); - if (!error) { - if (enable) { - alertify.success(gettextCatalog.getString('Drivers enabled')); + if (error) { + if ((stderr.indexOf('brew: command not found') !== -1) || + (stderr.indexOf('brew: No such file or directory') !== -1)) { + alertify.notify(gettextCatalog.getString('Homebrew is required'), 'error', 30); + // TODO: open web browser with Homebrew website on click + } + else if (stderr.indexOf('Error: Failed to download') !== -1) { + alertify.notify(gettextCatalog.getString('Internet connection required'), 'error', 30); } else { - alertify.warning(gettextCatalog.getString('Drivers disabled')); + alertify.notify(stderr, 'error', 30); } - setTimeout(function() { - alertify.notify(gettextCatalog.getString('Unplug and reconnect the board'), 'message', 5); - }, 1000); - } - }); - } - - function enableDarwinDrivers() { - var commands = [ - 'kextunload -b com.FTDI.driver.FTDIUSBSerialDriver -q || true', - 'kextunload -b com.apple.driver.AppleUSBFTDI -q || true' - ]; - var command = 'sh -c "' + commands.join('; ') + '"'; - - beginLazyProcess(); - nodeSudo.exec(command, {name: 'Icestudio'}, function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - if (error) { - endLazyProcess(); } else { - var brewCommands = [ - '/usr/local/bin/brew update', - '/usr/local/bin/brew install libftdi', - '/usr/local/bin/brew link --overwrite libftdi' - ]; - nodeChildProcess.exec(brewCommands.join('; '), function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - endLazyProcess(); - if (error) { - if ((stderr.indexOf('brew: command not found') != -1) || - (stderr.indexOf('brew: No such file or directory') != -1)) { - alertify.notify(gettextCatalog.getString('Homebrew is required'), 'error', 30); - } - else if (stderr.indexOf('Error: Failed to download') != -1) { - alertify.notify(gettextCatalog.getString('Internet connection required'), 'error', 30); - } - else { - alertify.notify(stderr, 'error', 30); - } - } - else { - alertify.success(gettextCatalog.getString('Drivers enabled')); - } - }); + alertify.success(gettextCatalog.getString('Drivers enabled')); } }); } - - function disableDarwinDrivers() { - var commands = [ - 'kextload -b com.FTDI.driver.FTDIUSBSerialDriver -q || true', - 'kextload -b com.apple.driver.AppleUSBFTDI -q || true' - ]; - var command = 'sh -c "' + commands.join('; ') + '"' - - beginLazyProcess(); - nodeSudo.exec(command, {name: 'Icestudio'}, function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - endLazyProcess(); - if (!error) { - alertify.warning(gettextCatalog.getString('Drivers disabled')); - } - }); + }); + } + + function disableDarwinDrivers() { + var commands = [ + 'kextload -b com.FTDI.driver.FTDIUSBSerialDriver -q || true', + 'kextload -b com.apple.driver.AppleUSBFTDI -q || true' + ]; + var command = 'sh -c "' + commands.join('; ') + '"'; + + beginLazyProcess(); + nodeSudo.exec(command, {name: 'Icestudio'}, function(error/*, stdout, stderr*/) { + // console.log(error, stdout, stderr); + endLazyProcess(); + if (!error) { + alertify.warning(gettextCatalog.getString('Drivers disabled')); + } + }); + } + + function enableWindowsDrivers() { + alertify.confirm(gettextCatalog.getString('

    FTDI driver installation instructions

    1. Connect the FPGA board
    2. Replace the (Interface 0) driver of the board by libusbK
    3. Unplug and reconnect the board
    '), function() { + beginLazyProcess(); + nodeChildProcess.exec([APIO_CMD, 'drivers', '--enable'].join(' '), function(error, stdout, stderr) { + // console.log(error, stdout, stderr); + endLazyProcess(); + if (stderr) { + alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); + } + if (!error) { + alertify.notify(gettextCatalog.getString('Unplug and reconnect the board'), 'message', 5); + } + }); + }); + } + + function disableWindowsDrivers() { + alertify.confirm(gettextCatalog.getString('

    FTDI driver uninstallation instructions

    1. Find the FPGA USB Device
    2. Select the board interface and uninstall the driver
    '), function() { + beginLazyProcess(); + nodeChildProcess.exec([APIO_CMD, 'drivers', '--disable'].join(' '), function(error, stdout, stderr) { + // console.log(error, stdout, stderr); + endLazyProcess(); + if (stderr) { + alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); + } + }); + }); + } + + function beginLazyProcess() { + $('body').addClass('waiting'); + angular.element('#menu').addClass('disable-menu'); + } + + function endLazyProcess() { + $('body').removeClass('waiting'); + angular.element('#menu').removeClass('disable-menu'); + } + + this.setLocale = function(locale) { + // Update current locale format + locale = splitLocale(locale); + // Load supported languages + var supported = getSupportedLanguages(); + // Set the best matching language + var bestLang = bestLocale(locale, supported); + gettextCatalog.setCurrentLanguage(bestLang); + gettextCatalog.loadRemote(nodePath.join(LOCALE_DIR, bestLang, bestLang + '.json')); + return bestLang; + }; + + function splitLocale(locale) { + var ret = {}; + var list = locale.split('_'); + if (list.length > 0) { + ret.lang = list[0]; + } + if (list.length > 1) { + ret.country = list[1]; + } + return ret; + } + + function getSupportedLanguages() { + var supported = []; + nodeFs.readdirSync(LOCALE_DIR).forEach(function(element/*, index*/) { + var curPath = nodePath.join(LOCALE_DIR, element); + if (nodeFs.lstatSync(curPath).isDirectory()) { + supported.push(splitLocale(element)); + } + }); + return supported; + } + + function bestLocale(locale, supported) { + var i; + // 1. Try complete match + if (locale.country) { + for (i = 0; i < supported.length; i++) { + if (locale.lang === supported[i].lang && + locale.country === supported[i].country) { + return supported[i].lang + '_' + supported[i].country; + } } - - function enableWindowsDrivers() { - alertify.confirm(gettextCatalog.getString('

    FTDI driver installation instructions

    1. Connect the FPGA board
    2. Replace the (Interface 0) driver of the board by libusbK
    3. Unplug and reconnect the board
    '), function() { - beginLazyProcess(); - nodeChildProcess.exec([APIO_CMD, 'drivers', '--enable'].join(' '), function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - endLazyProcess(); - if (stderr) { - alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); - } - if (!error) { - alertify.notify(gettextCatalog.getString('Unplug and reconnect the board'), 'message', 5); - } + } + // 2. Try lang match + for (i = 0; i < supported.length; i++) { + if (locale.lang === supported[i].lang) { + return supported[i].lang + (supported[i].country ? '_' + supported[i].country : ''); + } + } + // 3. Return default lang + return 'en'; + } + + this.multiprompt = function(messages, values, callback) { + var i; + var content = []; + var n = messages.length; + content.push('
    '); + for (i in messages) { + if (i > 0) { + content.push('
    '); + } + content.push('

    ' + messages[i] + '

    '); + content.push(' '); + } + content.push('
    '); + // Restore values + for (i = 0; i < n; i++) { + $('#input' + i.toString()).val(values[i]); + } + + alertify.confirm(content.join('\n')) + .set('onok', function(evt) { + var values = []; + for (var i = 0; i < n; i++) { + values.push($('#input' + i.toString()).val()); + } + if (callback) { + callback(evt, values); + } + }) + .set('oncancel', function(/*evt*/) { + }); + }; + + this.inputcheckboxprompt = function(messages, values, callback) { + var content = []; + content.push('
    '); + content.push('

    ' + messages[0] + '

    '); + content.push(' '); + content.push('
    '); + content.push('
    '); + content.push('
    '); + // Restore values + $('#label').val(values[0]); + $('#local').prop('checked', values[1]); + + alertify.confirm(content.join('\n')) + .set('onok', function(evt) { + var values = []; + values.push($('#label').val()); + values.push($('#local').prop('checked')); + if (callback) { + callback(evt, values); + } + }) + .set('oncancel', function(/*evt*/) { + }); + }; + + this.projectinfoprompt = function(values, callback) { + var i; + var content = []; + var messages = [ + gettextCatalog.getString('Name'), + gettextCatalog.getString('Version'), + gettextCatalog.getString('Description'), + gettextCatalog.getString('Author') + ]; + var n = messages.length; + var image = values[4]; + var blankImage = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + content.push('
    '); + for (i in messages) { + if (i > 0) { + //content.push('
    '); + } + content.push('

    ' + messages[i] + '

    '); + content.push(' '); + } + content.push('

    ' + gettextCatalog.getString('Image') + '

    '); + content.push(' '); + content.push(' '); + content.push('
    '); + content.push(' '); + content.push('
    '); + content.push('
    '); + content.push(' '); + content.push(' '); + content.push(' '); + content.push('
    '); + content.push('
    '); + // Restore values + for (i = 0; i < n; i++) { + $('#input' + i.toString()).val(values[i]); + } + if (image) { + $('#preview-svg').attr('src', 'data:image/svg+xml,' + image); + } + else { + $('#preview-svg').attr('src', blankImage); + } + + alertify.confirm() + .set('onshow', function() { + registerOpen(); + registerSave(); + registerReset(); + }); + + function registerOpen() { + // Open SVG + var chooserOpen = $('#input-open-svg'); + chooserOpen.unbind('change'); + chooserOpen.change(function(/*evt*/) { + var filepath = $(this).val(); + var svgo = new SVGO(); + nodeFs.readFile(filepath, 'utf8', function(err, data) { + if (err) { + throw err; + } + svgo.optimize(data, function(result) { + image = encodeURI(result.data); + registerSave(); + $('#preview-svg').attr('src', 'data:image/svg+xml,' + image); }); }); - } - - function disableWindowsDrivers() { - alertify.confirm(gettextCatalog.getString('

    FTDI driver uninstallation instructions

    1. Find the FPGA USB Device
    2. Select the board interface and uninstall the driver
    '), function() { - beginLazyProcess(); - nodeChildProcess.exec([APIO_CMD, 'drivers', '--disable'].join(' '), function(error, stdout, stderr) { - // console.log(error, stdout, stderr); - endLazyProcess(); - if (stderr) { - alertify.notify(gettextCatalog.getString('Toolchain not installed. Please, install the toolchain'), 'error', 30); + $(this).val(''); + }); + } + + function registerSave() { + // Save SVG + var label = $('#save-svg'); + if (image) { + label.removeClass('disabled'); + label.attr('for', 'input-save-svg'); + var chooserSave = $('#input-save-svg'); + chooserSave.unbind('change'); + chooserSave.change(function(/*evt*/) { + if (image) { + var filepath = $(this).val(); + if (!filepath.endsWith('.svg')) { + filepath += '.svg'; } - }); - }); - } - - function beginLazyProcess() { - $('body').addClass('waiting'); - angular.element('#menu').addClass('disable-menu'); - } - - function endLazyProcess() { - $('body').removeClass('waiting'); - angular.element('#menu').removeClass('disable-menu'); - } - - this.setLocale = function(locale) { - // Update current locale format - locale = splitLocale(locale); - // Load supported languages - var supported = getSupportedLanguages(); - // Set the best matching language - var bestLang = bestLocale(locale, supported); - gettextCatalog.setCurrentLanguage(bestLang); - gettextCatalog.loadRemote(nodePath.join(LOCALE_DIR, bestLang, bestLang + '.json')); - return bestLang; - } - - function splitLocale(locale) { - var ret = {}; - var list = locale.split('_'); - if (list.length > 0) ret.lang = list[0]; - if (list.length > 1) ret.country = list[1]; - return ret; - } - - function getSupportedLanguages() { - var supported = []; - nodeFs.readdirSync(LOCALE_DIR).forEach(function(element, index) { - var curPath = nodePath.join(LOCALE_DIR, element); - if (nodeFs.lstatSync(curPath).isDirectory()) { - supported.push(splitLocale(element)); + nodeFs.writeFile(filepath, decodeURI(image), function(err) { + if (err) { + throw err; + } + }); + $(this).val(''); } }); - return supported; } - - function bestLocale(locale, supported) { - var ret = 'en'; - // 1. Try complete match - if (locale.country) { - for (var i = 0; i < supported.length; i++) { - if (locale.lang === supported[i].lang && - locale.country === supported[i].country) { - return supported[i].lang + '_' + supported[i].country; - } - } - } - // 2. Try lang match - for (var i = 0; i < supported.length; i++) { - if (locale.lang === supported[i].lang) { - return supported[i].lang + (supported[i].country ? '_' + supported[i].country : ''); - } + else { + label.addClass('disabled'); + label.attr('for', ''); + } + } + + function registerReset() { + // Reset SVG + var reset = $('#reset-svg'); + reset.click(function(/*evt*/) { + image = ''; + registerSave(); + $('#preview-svg').attr('src', blankImage); + }); + } + + alertify.confirm(content.join('\n')) + .set('onok', function(evt) { + var values = []; + for (var i = 0; i < n; i++) { + values.push($('#input' + i.toString()).val()); + } + values.push(image); + if (callback) { + callback(evt, values); + } + alertify.confirm().set('onshow', function() {}); + }) + .set('oncancel', function(/*evt*/) { + alertify.confirm().set('onshow', function() {}); + }); + }; + + this.copySync = function(orig, dest) { + var ret = true; + try { + if (nodeFs.existsSync(orig)) { + nodeFse.copySync(orig, dest); + } + else { + // Error: file does not exist + ret = false; + } + } + catch (e) { + alertify.notify(gettextCatalog.getString('Error: {{error}}', { error: e.toString() }), 'error', 30); + ret = false; + } + return ret; + }; + + this.findIncludedFiles = function(code) { + var ret = []; + var patterns = [ + /@include\s(.*?)(\\n|\n|\s)/g, + /\\"(.*\.list?)\\"/g + ]; + for (var p in patterns) { + var match; + while (match = patterns[p].exec(code)) { + var file = match[1].replace(/ /g, ''); + if (ret.indexOf(file) === -1) { + ret.push(file); } - // 3. Return default lang - return 'en'; - } - - this.multiprompt = function(messages, values, callback) { - var content = []; - var n = messages.length; - content.push('
    '); - for (var i in messages) { - if (i > 0) content.push('
    '); - content.push('

    ' + messages[i] + '

    '); - content.push(' '); - } - content.push('
    '); - - alertify.confirm(content.join('\n')).set('onok', function(evt) { - var values = []; - for (var i = 0; i < n; i++) { - values.push($('#input' + i.toString()).val()); - } - if (callback) - callback(evt, values); - }); } - - this.copySync = function(orig, dest, filename) { - var ret = true; - try { - if (nodeFs.existsSync(orig)) { - nodeFse.copySync(orig, dest); - } - else { - // Error: file does not exist - ret = false; - } + } + return ret; + }; + + this.bold = function(text) { + return '' + text + ''; + }; + + this.openDialog = function(inputID, ext, callback) { + var chooser = $(inputID); + chooser.unbind('change'); + chooser.change(function(/*evt*/) { + var filepath = $(this).val(); + //if (filepath.endsWith(ext)) { + if (callback) { + callback(filepath); } - catch (e) { - alertify.notify(gettextCatalog.getString('Error: {{error}}', { error: e.toString() }), 'error', 30); - ret = false; + //} + $(this).val(''); + }); + chooser.trigger('click'); + }; + + this.saveDialog = function(inputID, ext, callback) { + var chooser = $(inputID); + chooser.unbind('change'); + chooser.change(function(/*evt*/) { + var filepath = $(this).val(); + if (!filepath.endsWith(ext)) { + filepath += ext; + } + if (callback) { + callback(filepath); + } + $(this).val(''); + }); + chooser.trigger('click'); + }; + + this.updateWindowTitle = function(title) { + window.get().title = title; + }; + + this.rootScopeSafeApply = function() { + if(!$rootScope.$$phase) { + $rootScope.$apply(); + } + }; + + this.parsePortLabel = function(data) { + // e.g: name[x:y] + var match, ret = {}; + var pattern = /([A-Za-z_]+[A-Za-z_0-9]*){0,1}(\[([0-9]+):([0-9]+)\]){0,1}/g; + match = pattern.exec(data); + if (match && (match[0] === match.input)) { + ret.name = match[1] ? match[1] : ''; + ret.rangestr = match[2]; + if (match[2]) { + if (match[3] > match[4]) { + ret.range = _.range(match[3], parseInt(match[4])-1, -1); } - return ret; - } - - this.findIncludedFiles = function(code) { - var ret = []; - var patterns = [ - /@include\s(.*?)(\\n|\n|\s)/g, - /\\"(.*\.list?)\\"/g - ]; - for (var p in patterns) { - var match; - while (match = patterns[p].exec(code)) { - var file = match[1].replace(/ /g, ''); - if (ret.indexOf(file) == -1) { - ret.push(file); - } - } + else { + ret.range = _.range(match[3], parseInt(match[4])+1, +1); } - return ret; } - - this.bold = function(text) { - return '' + text + ''; - } - - this.saveDialog = function(inputID, ext, callback) { - var chooser = $(inputID); - chooser.unbind('change'); - chooser.change(function(evt) { - var filepath = $(this).val(); - if (!filepath.endsWith(ext)) - filepath += ext; - if (callback) - callback(filepath); - $(this).val(''); - }); - chooser.trigger('click'); - } - - }]); + return ret; + } + return null; + }; + + this.parseParamLabel = function(data) { + // e.g: name + var match, ret = {}; + var pattern = /([A-Za-z_]+[A-Za-z_0-9]*){0,1}/g; + match = pattern.exec(data); + if (match && (match[0] === match.input)) { + ret.name = match[1] ? match[1] : ''; + return ret; + } + return null; + }; + + this.clone = function(data) { + return JSON.parse(JSON.stringify(data)); + }; + + this.dependencyID = function(dependency) { + if (dependency.package && dependency.design) { + return nodeSha1(JSON.stringify(dependency.package) + + JSON.stringify(dependency.design)); + } + }; + + this.newWindow = function(filepath) { + var execPath = process.execPath; + var command = [ '"' + execPath + '"' ]; + if (execPath.endsWith('nw') || execPath.endsWith('nw.exe') || execPath.endsWith('nwjs Helper')) { + command.push('"' + nodePath.dirname(process.mainModule.filename) + '"'); + } + if (filepath) { + command.push('"' + filepath + '"'); + } + /*var win = window.get(); + var position = { + x: win.x + 30, + y: win.y + 30 + }; + command.push(position.x + 'x' + position.y);*/ + nodeChildProcess.exec(command.join(' '), [], function(error/*, stdout/*, stderr*/) { + if (error) { + throw error; + } + }); + }; + + }); diff --git a/app/styles/project.css b/app/styles/design.css similarity index 64% rename from app/styles/project.css rename to app/styles/design.css index 8b1986549..0751fe757 100644 --- a/app/styles/project.css +++ b/app/styles/design.css @@ -78,11 +78,44 @@ border: 2px solid #888; pointer-events: none; -webkit-user-select: none; + user-select: none; z-index: 0; } +.generic-block .tooltiptext { + visibility: hidden; + width: 120px; + color: #333; + background-color: white; + border: 1px solid #888; + text-align: center; + border-radius: 5px; + padding: 5px 5px; + position: absolute; + bottom: 100%; + margin-bottom: 20px; + left: 50%; + margin-left: -60px; +} + +.generic-block .tooltiptext::after { + content: ''; + position: absolute; + top: 100%; + left: 50%; + margin-left: -6px; + border-width: 6px; + border-style: solid; + border-color: #888 transparent transparent transparent; +} + +.generic-block .tooltip-large { + width: 240px; + margin-left: -120px; +} + .config-block { - background: #FAFAD2; + background: #fafacd; } .generic-block img { @@ -97,35 +130,117 @@ .generic-block label { display: block; - margin-top: 10px; + margin-top: 20px; text-align: center; - font-size: 1em; + font-size: 14px; color: #444; + text-overflow: ellipsis; + overflow: hidden; } -.io-block { +.virtual-port { position: absolute; - background: #FAFAD2; + background: #E2FBC9; border-radius: 5px; border: 2px solid #888; pointer-events: none; -webkit-user-select: none; + user-select: none; z-index: 0; } -.io-block label { +.virtual-port label { + display: block; + margin-top: 20px; + text-align: center; + font-size: 0.9em; + color: #444; + text-overflow: ellipsis; + overflow: hidden; +} + +.fpga-port { + position: absolute; + background: #FBFBC9; + border-radius: 5px; + border: 2px solid #888; + pointer-events: none; + -webkit-user-select: none; + user-select: none; + z-index: 0; +} + +.fpga-port label { display: block; margin-top: 4px; + margin-bottom: 5px; + text-align: center; + font-size: 13px; + color: #444; + text-overflow: ellipsis; + overflow: hidden; +} + +.fpga-port div p { + position: relative; + top: 0px; + left: -20px; + float: left; +} + +.fpga-port div .select2 { + position: relative; + width: 82px; + left: 5px; + margin-bottom: 4px; + pointer-events: auto; +} + +.select2-selection__rendered { + font-size: 13px; +} + +.bigdrop { + width: 92px !important; + font-size: 13px; +} + +.constant-block { + position: absolute; + background: #FBF0C9; + border-radius: 5px; + border: 2px solid #888; + pointer-events: none; + -webkit-user-select: none; + user-select: none; + z-index: 0; +} + +.constant-block p { + position: absolute; + top: 0; + right: 5px; + font-size: 1.5em; + color: #444; +} + +.constant-block label { + display: block; + margin-top: 8px; text-align: center; - font-size: 1em; + font-size: 13px; color: #444; + text-overflow: ellipsis; + overflow: hidden; } -.io-block .select2 { +.constant-block input { position: absolute; + text-align: center; left: 5px; bottom: 5px; width: 82px; + font-size: 13px; pointer-events: auto; } @@ -136,6 +251,7 @@ border: 2px solid #888; pointer-events: none; -webkit-user-select: none; + user-select: none; z-index: 0; } @@ -160,6 +276,7 @@ border: 2px solid #888; pointer-events: none; -webkit-user-select: none; + user-select: none; z-index: 0; } @@ -182,13 +299,13 @@ } .highlight { - box-shadow: 0px 0px 30px 0px rgba(200,200,200,1); + box-shadow: 0 0 30px 0 rgba(200,200,200,1); } .selectionarea { position: absolute; - border: 2px solid #EB2222; - opacity: .7; + border: 1px solid rgba(42, 118, 198, 1); + background-color: rgba(42, 118, 198, 0.2); overflow: visible; z-index: 1500; } @@ -207,8 +324,8 @@ .selection-box { position: absolute; - border: 2px dashed #EB2222; - opacity: .7; + border: 1px dotted rgba(42, 118, 198, 1); + background-color: rgba(42, 118, 198, 0.2); border-radius: 5px; z-index: 1500; } diff --git a/app/styles/main.css b/app/styles/main.css index b6d47b7c4..dd51c137c 100644 --- a/app/styles/main.css +++ b/app/styles/main.css @@ -9,11 +9,11 @@ } .notransition { - -webkit-transition: none !important; - -moz-transition: none !important; - -o-transition: none !important; - -ms-transition: none !important; - transition: none !important; + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + -ms-transition: none; + transition: none; } body { @@ -22,7 +22,7 @@ body { height: 100%; } -body.waiting * { +.waiting * { cursor: progress; } diff --git a/app/styles/menu.css b/app/styles/menu.css index c379857b5..429e6addf 100644 --- a/app/styles/menu.css +++ b/app/styles/menu.css @@ -12,7 +12,13 @@ } .navbar-right { - margin-right: 0px; + margin-right: 0; +} + +.shortcut { + display: inline; + float: right; + color: #999; } .dropdown-submenu { @@ -23,7 +29,7 @@ top: 0; left: 100%; margin-top: -6px; - margin-left: 0px; + margin-left: 0; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; diff --git a/app/views/project.html b/app/views/design.html similarity index 69% rename from app/views/project.html rename to app/views/design.html index d47b4f66f..a065467ba 100644 --- a/app/views/project.html +++ b/app/views/design.html @@ -1,7 +1,8 @@ -
    + +
    diff --git a/app/views/main.html b/app/views/main.html index 4cf38b88f..a845bbc1f 100644 --- a/app/views/main.html +++ b/app/views/main.html @@ -1,4 +1,5 @@ +
    -
    +
    diff --git a/app/views/menu.html b/app/views/menu.html index a9c61b2f4..dd448c97b 100644 --- a/app/views/menu.html +++ b/app/views/menu.html @@ -1,18 +1,20 @@ +