From 9c811d92ca724165862c63708b8e5ebaf290c7d8 Mon Sep 17 00:00:00 2001 From: mgesteiro Date: Thu, 2 Feb 2023 12:09:23 +0100 Subject: [PATCH] New edit-duplicate action with shortcut --- .gitignore | 2 +- app/index.html | 8 ++-- app/scripts/app.js | 30 +++++++------- app/scripts/controllers/menu.js | 66 +++++++++++++++---------------- app/scripts/services/graph.js | 25 ++++++++---- app/scripts/services/project.js | 4 -- app/scripts/services/shortcuts.js | 21 +++++----- app/scripts/services/utils.js | 30 ++++++++------ app/views/menu.html | 19 ++++++--- 9 files changed, 115 insertions(+), 90 deletions(-) diff --git a/.gitignore b/.gitignore index e597a47ce..47e1145d6 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,4 @@ app/resources/locale/**/*.json ice-build/ # WebStorm IDE project folder -.idea \ No newline at end of file +.idea diff --git a/app/index.html b/app/index.html index fe0deda70..9074dd031 100644 --- a/app/index.html +++ b/app/index.html @@ -23,7 +23,7 @@ - + @@ -78,9 +78,9 @@ position:absolute; top:0;left:0; overflow:hidden; - z-index:0; - background-color:#7ccff4; - opacity:0.4; + z-index:0; + background-color:#7ccff4; + opacity:0.4; } .spinner-wrapper--container{ position:absolute; diff --git a/app/scripts/app.js b/app/scripts/app.js index 74ddc5266..f2e98e4b5 100644 --- a/app/scripts/app.js +++ b/app/scripts/app.js @@ -13,9 +13,9 @@ //-- Global Icestudio //-- this is the core system with services, api and communications. -//-- Group inside different object for eficiency model by V8 engine. +//-- Group inside different object for efficiency model by V8 engine. //-- The global variable should be declared as "var" and not "let" -//-- because is accesible from popups windows +//-- because it is accessible from popups windows var iceStudio = new Icestudio(); //-- Global CONSOLE. Used for Debugging @@ -26,7 +26,7 @@ var iceConsole = new IceLogger(); angular .module("icestudio", ["ui.bootstrap", "ngRoute", "gettext"]) .run(function ( - profile, //-- Icestudio profile file managment + profile, //-- Icestudio profile file management project, common, tools, @@ -156,7 +156,7 @@ angular "common.APIO_HOME_DIR: APIO folder: " + common.APIO_HOME_DIR ); iceConsole.log( - "common.ENV_DIR: PYthon virtual environment: " + common.ENV_DIR + "common.ENV_DIR: Python virtual environment: " + common.ENV_DIR ); iceConsole.log( "common.ENV_BIN_DIR: Executable files: " + common.ENV_BIN_DIR @@ -187,14 +187,17 @@ angular ) ); - tools.checkToolchain( () => {}, //-- No callback - false); //-- No error notifications - + tools.checkToolchain( + () => {}, //-- No callback + false //-- No error notifications + ); }); } else { profile.set("board", boards.selectBoard(profile.get("board")).name); - tools.checkToolchain( () => {}, //-- No callback - false); //-- No error notifications + tools.checkToolchain( + () => {}, //-- No callback + false //-- No error notifications + ); } $("html").attr("lang", profile.get("language")); @@ -205,10 +208,10 @@ angular ); project.updateTitle(gettextCatalog.getString("Untitled")); }); - // setTimeout(function () { - $("#main-icestudio-wrapper").addClass("loaded"); - $("#main-icestudio-load-wrapper").addClass("fade-loaded"); - setTimeout(function () { + // setTimeout(function () { + $("#main-icestudio-wrapper").addClass("loaded"); + $("#main-icestudio-load-wrapper").addClass("fade-loaded"); + setTimeout(function () { $("#main-icestudio-load-wrapper").addClass("loaded"); $("#main-icestudio-load-wrapper").removeClass("fade-loaded"); }, 1000); @@ -217,4 +220,3 @@ angular console.log("->DEBUG: app.js: END"); }); - diff --git a/app/scripts/controllers/menu.js b/app/scripts/controllers/menu.js index 9af90914c..42a1da82d 100644 --- a/app/scripts/controllers/menu.js +++ b/app/scripts/controllers/menu.js @@ -32,7 +32,7 @@ angular shortcuts, gettextCatalog, - //-- Accesing _package object + //-- Accessing _package object //-- Defined in module app/scripts/factories/window.js _package ) @@ -73,7 +73,7 @@ angular //----------------------------------- //-- Get the Window object - //-- The nw object is globaly available. It contains all the + //-- The nw object is globally available. It contains all the //-- NWjs APIs //-- More information: //-- https://nwjs.readthedocs.io/en/latest/ @@ -144,7 +144,7 @@ angular //------------------------------------------------------------------------- //-- Read the arguments passed to the app //-- If no arguments, nothing is done (just a blank project) - //-- Currenty there is only one argument to pass: The filename of the + //-- Currently, there is only one argument to pass: The filename of the //-- icestudio design to open //------------------------------------------------------------------------- @@ -179,9 +179,9 @@ angular filepath = params["filepath"]; } //-- No argument through url - //-- Check if there was an argument comming from the command line - //-- If there are arguments is because it has been start by doble - //-- cliking on an .ice file + //-- Check if there was an argument coming from the command line + //-- If there are arguments is because it has been start by double + //-- clicking on an .ice file else { //-- Read the arguments from nw API @@ -224,7 +224,7 @@ angular let hasNewVersion = lastversionReview === false || lastversionReview < _package.version; - //-- Display the version notes, if the option is enable or + //-- Display the version notes, if the option is enabled or //-- if this is a newer version if (versionW === "yes" || hasNewVersion) { $scope.openVersionInfoWindow(); @@ -288,9 +288,9 @@ angular $scope.newProject = () => { //-- Create a new blank icestudio window - //-- A non-existant file is passed as a parameters - //-- It let us distinguis if the new window was created because of - //-- a new file or it was the first window opened + //-- A non-existent file is passed as a parameters + //-- It let us distinguish if the new window was created because of + //-- a new file, or it was the first window opened utils.newWindow("Untitled.ice"); }; @@ -303,7 +303,7 @@ angular $scope.openProjectDialog = function () { //-- Open the file Dialog - //-- The selecter is passed as a parameter + //-- The selector is passed as a parameter //-- The html element is located in the menu.html file utils.openDialog("#input-open-project", function (filepath) { @@ -347,7 +347,7 @@ angular alertify.alert( gettextCatalog.getString("Save submodule"), gettextCatalog.getString( - 'To save your design you need to lock the keylock and \ + 'To save your design you need to lock the padlock and \ go to top level design.

If you want to export \ this submodule to a file, execute "Save as" command to do it.' ), @@ -407,9 +407,9 @@ angular alertify.confirm( gettextCatalog.getString("Export submodule"), gettextCatalog.getString( - 'You are editing a submodule, if you save it, you save only \ + 'You are editing a submodule, if you save it, you\'ll save only \ the submodule (in this situation "save as" works like \ - "export module"), Do you like to continue?' + "export module"). Do you want to continue?' ), function () { $scope.doSaveProjectAs(localCallback); @@ -617,7 +617,7 @@ angular } //--------------------------------------------------------------------- - //-- CALLBACK FUNCIONTS for the EDIT MENU + //-- CALLBACK FUNCTIONS for the EDIT MENU //--------------------------------------------------------------------- $scope.undoGraph = function () { graph.undo(); @@ -657,6 +657,10 @@ angular } }; + $scope.duplicateSelected = function () { + graph.duplicateSelected(); + }; + $scope.removeSelected = function () { graph.removeSelected(); }; @@ -677,12 +681,6 @@ angular showToolBox(); }; - /* redundant: patched via $scope - @mgesteiro - function removeSelected() { - project.removeSelected(); // <- this is justa a wrapper of graph.removeSelected() - } - */ - $scope.fitContent = function () { graph.fitContent(); }; @@ -711,7 +709,7 @@ angular form.process(evt); //-- If there were errors, the form is not closed - //-- Return without clossing + //-- Return without closing if (evt.cancel) { return; } @@ -733,7 +731,7 @@ angular newLogfile.lastIndexOf(separator) + 1 ); - //-- If the file is valid.. + //-- If the file is valid ... if (newLogfile === "" || hd.isValidPath(dirLFile)) { //-- Set the new file @@ -844,7 +842,7 @@ angular let newPythonPath = form.values[0]; let newPipPath = form.values[1]; - //-- If there where no changes.. return + //-- If there where no changes ... return if ( newPythonPath === pythonEnv.python && newPipPath === pythonEnv.pip) { return; @@ -907,7 +905,7 @@ angular //-- Read the new path let newExternalCollections = form.values[0]; - //-- If there where no changes.. return + //-- If there where no changes ... return if (newExternalCollections === externalCollections) { return; } @@ -1156,7 +1154,7 @@ angular // View/System Info Window //-- $scope.showSystemInfo = function () { - //-- Write the iformation to the log file: + //-- Write the information to the log file: iceConsole.log("---------------------"); iceConsole.log(" VIEW/System Info"); iceConsole.log("--------------------"); @@ -1173,8 +1171,8 @@ angular iceConsole.log("\n\n"); //-- Build the URL with all the parameters to pass to the window - //-- The encodeURIComponent() function the characteres so that the spaces and - //-- other special characteres can be place on the original URL + //-- The encodeURIComponent() function the characters so that the spaces and + //-- other special characters can be place on the original URL let URL = `resources/viewers/system/system.html?version=${common.ICESTUDIO_VERSION}` + `&base_dir=${encodeURIComponent(common.BASE_DIR)}---` + @@ -1347,7 +1345,7 @@ angular alertify.alert( gettextCatalog.getString("Build"), gettextCatalog.getString( - "You can only build at top-level design. Inside submodules you only can Verify" + "You can only build at the top-level design. Inside submodules, you can only Verify" ), function () { } ); @@ -1372,7 +1370,7 @@ angular alertify.alert( gettextCatalog.getString("Upload"), gettextCatalog.getString( - "You can only upload your design at top-level design. Inside submodules you only can Verify" + "You can only upload at the top-level design. Inside submodules, you can only Verify" ), function () { } ); @@ -1521,7 +1519,7 @@ angular 'who start this project and was the main developer from 2016/Jan/28 to 2019/Oct', "

", '

Thanks to the rest of contributors

', - '

© FPGAwars 2016-2022

', + '

© FPGAwars 2016-2022

', '', " ", "", @@ -1589,6 +1587,7 @@ angular shortcuts.method("copySelected", $scope.copySelected); shortcuts.method("pasteAndCloneSelected", $scope.pasteAndCloneSelected); shortcuts.method("pasteSelected", $scope.pasteSelected); + shortcuts.method("duplicateSelected", $scope.duplicateSelected); shortcuts.method("removeSelected", $scope.removeSelected); shortcuts.method("selectAll", $scope.selectAll); shortcuts.method("fitContent", $scope.fitContent); @@ -1610,7 +1609,6 @@ angular // -- Show Floating toolbox shortcuts.method("showToolBox", $scope.showToolBox); - //shortcuts.method("removeSelected", removeSelected); // moved alongside other EDIT menu options shortcuts.method("back", function () { if (graph.isEnabled()) { graph.removeSelected(); @@ -1821,7 +1819,7 @@ angular reName = new RegExp(parsedSearch.name, 'i'); // contains + case insensitive (less restrictive) if (optionCase === true && optionExact === false) { // contains + case sensitive reName = new RegExp (parsedSearch.name); - } else if (optionCase === false && optionExact === true) { // exact + case insensitive + } else if (optionCase === false && optionExact === true) { // exact + case-insensitive reName = new RegExp ("\\b"+parsedSearch.name+"\\b", 'i'); } else if (optionCase === true && optionExact === true) { // exact + case sensitive (most restrictive) reName = new RegExp ("\\b"+parsedSearch.name+"\\b"); @@ -1944,7 +1942,7 @@ angular showToolBox(); // close toolbox }); - //-- dragabble toolbox + //-- draggable toolbox $(document).on("mousedown", "#iceToolbox .title-bar", function () { mouseDownTB = true; }); diff --git a/app/scripts/services/graph.js b/app/scripts/services/graph.js index e75dd1044..7b616f9ef 100644 --- a/app/scripts/services/graph.js +++ b/app/scripts/services/graph.js @@ -1320,6 +1320,23 @@ angular.module('icestudio') } }; + this.duplicateSelected = function() { + if (hasSelection()) { + utils.duplicateSelected(selection, graph, function (object) { + if (object.version === common.VERSION) { + self.appendDesign(object.design, object.dependencies); + } + }); + } + }; + + this.removeSelected = function () { + if (hasSelection()) { + graph.removeCells(selection.models); + selectionView.cancelSelection(); + updateWiresOnObstacles(); + } + }; this.selectAll = function () { disableSelected(); @@ -1336,14 +1353,6 @@ angular.module('icestudio') return selection && selection.length > 0; } - this.removeSelected = function () { - if (hasSelection()) { - graph.removeCells(selection.models); - selectionView.cancelSelection(); - updateWiresOnObstacles(); - } - }; - function disableSelected() { if (hasSelection()) { selectionView.cancelSelection(); diff --git a/app/scripts/services/project.js b/app/scripts/services/project.js index aa45290df..5fae127b7 100644 --- a/app/scripts/services/project.js +++ b/app/scripts/services/project.js @@ -688,10 +688,6 @@ angular.module('icestudio') return block; } - this.removeSelected = function () { - graph.removeSelected(); - }; - this.clear = function () { project = _default(); graph.clearAll(); diff --git a/app/scripts/services/shortcuts.js b/app/scripts/services/shortcuts.js index 4da843a73..564966269 100644 --- a/app/scripts/services/shortcuts.js +++ b/app/scripts/services/shortcuts.js @@ -88,7 +88,7 @@ angular.module('icestudio') }, saveProjectAs: { linux: { label: 'Ctrl+Shift+S', ctrl: true, shift: true, key: 83 }, - mac: { label: 'Shift+⌘+S', meta: true, shift: true, key: 83 }, + mac: { label: '⌘+⇧+S', meta: true, shift: true, key: 83 }, opt: { prompt: true } }, quit: { @@ -107,7 +107,7 @@ angular.module('icestudio') }, redoGraph2: { linux: { label: 'Ctrl+Shift+Z', ctrl: true, shift: true, key: 90 }, - mac: { label: 'Shift+⌘+Z', meta: true, shift: true, key: 90 }, + mac: { label: '⌘+⇧+Z', meta: true, shift: true, key: 90 }, opt: { preventDefault: true } }, cutSelected: { @@ -124,9 +124,16 @@ angular.module('icestudio') }, pasteAndCloneSelected: { linux: { label: 'Ctrl+Shift+V', ctrl: true, shift: true, key: 86 }, - mac: { label: 'Shit+⌘+V', meta: true, shift: true, key: 86 } + mac: { label: '⌘+⇧+V', meta: true, shift: true, key: 86 } + }, + duplicateSelected: { + linux: { label: 'Ctrl+D', ctrl: true, key: 68 }, + mac: { label: '⌘+D', meta: true, key: 68 } + }, + removeSelected: { + linux: { label: 'Del', key: 46 }, + mac: { label: 'Fn+⌫', key: 46 }, }, - selectAll: { linux: { label: 'Ctrl+A', ctrl: true, key: 65 }, mac: { label: '⌘+A', meta: true, key: 65 } @@ -164,13 +171,9 @@ angular.module('icestudio') linux: { label: 'Arrow right', key: 39 }, mac: { label: 'Arrow right', key: 39 } }, - removeSelected: { - linux: { label: 'Supr', key: 46 }, - mac: { label: 'Fn+Delete', key: 46 }, - }, back: { linux: { label: 'Back', key: 8 }, - mac: { label: 'Delete', key: 8 }, + mac: { label: '⌫', key: 8 }, opt: { disabled: true } }, takeSnapshot: { diff --git a/app/scripts/services/utils.js b/app/scripts/services/utils.js index 7f2b4b1fa..a53e8d3b7 100644 --- a/app/scripts/services/utils.js +++ b/app/scripts/services/utils.js @@ -231,14 +231,14 @@ angular.module('icestudio') //-- Error executing the command //-- Show the error notification if (notifyerror) { - alertify.error('Error executting command ' + command, 30); + alertify.error('Error executing command ' + command, 30); } //-- Comand finished with errors. Call the callback function callback(true, output); } else { - //-- Command finished with NO errors. Cal lthe callback function + //-- Command finished with NO errors. Call the callback function callback(false, output); } }); @@ -343,7 +343,7 @@ angular.module('icestudio') const executable = coverPath(pipExec); //-- Get the pip parameters needed for installing apio - //-- The needed apio vesion is also added + //-- The needed apio version is also added const params = this.getApioParameters(); console.log(pipExec, executable, params); //-- Run the pip command! @@ -392,7 +392,7 @@ angular.module('icestudio') const params = "install -U " + apio + extraPackagesString + versionString; - console.log("--> DEBUG: Params paased to pip: " + params); + console.log("--> DEBUG: Params passed to pip: " + params); return params; }; @@ -422,7 +422,7 @@ angular.module('icestudio') process.env.ICESTUDIO_APIO : _package.apio.external; - //-- The is an alternative apio toolchain ready + //-- There is an alternative apio toolchain ready if (nodeFs.existsSync(candidateApio)) { if (!this.toolchainDisabled) { @@ -867,7 +867,7 @@ angular.module('icestudio') //----------------------------------------------------------------------- //-- Return a text in bold HTML //-- Input: - //-- * text: String to converto to Bold + //-- * text: String to convert to Bold //-- Returns: //-- * The HTML text in bold //----------------------------------------------------------------------- @@ -886,13 +886,13 @@ angular.module('icestudio') //----------------------------------------------------------------------- this.openDialog = function (inputID, callback) { - //-- Get the filechooser element (from the DOM) + //-- Get the file chooser element (from the DOM) let chooser = $(inputID); - //-- Reove any previously event attached + //-- Remove any previously event attached chooser.unbind('change'); - //-- Atach a new callback function + //-- Attach a new callback function chooser.change(function () { //-- It is executed when the user has selected the file @@ -909,7 +909,7 @@ angular.module('icestudio') }); //-- Activate the File chooser! (The element is shown, it waits for - //-- the user to enter the file and the calblack is executed + //-- the user to enter the file, and the callback is executed) chooser.trigger('click'); }; @@ -1139,7 +1139,7 @@ angular.module('icestudio') }); } } - alertify.warning(message, 30); + alertify.warning(message, "30"); }); } } else { @@ -1152,6 +1152,14 @@ angular.module('icestudio') }); }; + this.duplicateSelected = function (selection, graph, callback) { + let cells = selectionToCells(selection, graph); + let content = this.cellsToProject(cells, graph); + if (callback && content) { + callback(content); + } + }; + function selectionToCells(selection, graph) { var cells = []; var blocksMap = {}; diff --git a/app/views/menu.html b/app/views/menu.html index 04cd204e1..a2ed55044 100644 --- a/app/views/menu.html +++ b/app/views/menu.html @@ -16,8 +16,8 @@