diff --git a/package.json b/package.json index 15ecb298625adb8830ea8c736a51e876e43913ab..913652d8888a35824cac67ad824bb9b4c76d8486 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "FlexBE App", - "version": "2.0.3", + "version": "2.0.5", "main": "src/main.js", "window": { "icon": "src/img/icon-128.png", diff --git a/package.xml b/package.xml index ba76a44dda651dac3ef170b91b94ed85649d8827..225c4fa8eda16c35dc2e4bc7b741a09b43abc4ab 100644 --- a/package.xml +++ b/package.xml @@ -1,6 +1,6 @@ <package> <name>flexbe_app</name> - <version>2.0.3</version> + <version>2.0.5</version> <description> flexbe_app provides a user interface (editor + runtime control) for the FlexBE behavior engine. </description> diff --git a/src/_helper/tools.js b/src/_helper/tools.js index 11d4b0c265bae47616c83dbd0868454b72a51691..2bf4c245dbebbfffc777a2a91ff247671ff71d57 100644 --- a/src/_helper/tools.js +++ b/src/_helper/tools.js @@ -8,8 +8,8 @@ Tools = new (function() { if (s instanceof Statemachine) { var state_def = new WS.StateMachineDefinition(s.getOutcomes(), s.getInputKeys(), s.getOutputKeys()); new_state = new Statemachine(s.getStateName(), state_def); - new_state.setConcurrent(s.isConcurrent()); new_state.setPriority(s.isPriority()); + new_state.setConcurrent(s.isConcurrent()); s.getStates().forEach(function (element) { pasteStateInto(element, new_state); }); @@ -17,16 +17,20 @@ Tools = new (function() { if (element.getOutcome() == "" && element.getFrom().getStateName() == "INIT") return; var new_from = new_state.getStateByName(element.getFrom().getStateName()); var new_to = new_state.getStateByName(element.getTo().getStateName()); - if (new_to == undefined) { + var is_outcome = new_to == undefined; + if (is_outcome) { new_to = new_state.getSMOutcomeByName(element.getTo().getStateName()); } new_state.addTransition(new Transition(new_from, new_to, element.getOutcome(), element.getAutonomy())); + if (new_state.isConcurrent() && is_outcome) { + new_state.tryDuplicateOutcome(element.getTo().getStateName().split('#')[0]); + } }); if (s.getInitialState() != undefined) { new_state.setInitialState(new_state.getStateByName(s.getInitialState().getStateName())); } } else if (s instanceof BehaviorState) { - new_state = new BehaviorState(s.getBehaviorName(), WS.Behaviorlib.getByName(s.getBehaviorName())); + new_state = new BehaviorState(s.getBehaviorName(), WS.Behaviorlib.getByName(s.getBehaviorName()), s.getDefaultKeys().clone()); new_state.setStateName(s.getStateName()); } else if (s instanceof State) { var state_def = WS.Statelib.getFromLib(s.getStateClass()); @@ -47,6 +51,8 @@ Tools = new (function() { elements.filter(function(s) { return (s instanceof State) || (s instanceof Statemachine) || (s instanceof BehaviorState); }).forEach(function(s) { + if (UI.Panels.StateProperties.isCurrentState(s)) + UI.Panels.StateProperties.hide(); s.getContainer().removeState(s); }); UI.Statemachine.refreshView(); @@ -299,7 +305,7 @@ Tools = new (function() { ActivityTracer.addActivity(ActivityTracer.ACT_COMPLEX_OPERATION, "Grouped " + state_list.length + " states", - function() { + function() { // undo var container = (container_path == "")? Behavior.getStatemachine() : Behavior.getStatemachine().getStateByPath(container_path); var sm = container.getStateByName(sm_name); if (UI.Statemachine.getDisplayedSM().getStatePath() == sm.getStatePath()) { @@ -334,7 +340,7 @@ Tools = new (function() { UI.Statemachine.refreshView(); }, - function() { + function() { // redo var container = (container_path == "")? Behavior.getStatemachine() : Behavior.getStatemachine().getStateByPath(container_path); var sm_def = new WS.StateMachineDefinition(sm_outcomes, sm_input_keys, sm_output_keys); var sm = new Statemachine(sm_name, sm_def); @@ -350,6 +356,7 @@ Tools = new (function() { sm_outcomes.forEach(function(oc) { var transition = transitions_out.findElement(t => t.getOutcome() == oc); var t_to = container.getStateByName(transition.getTo().getStateName()); + if (t_to == undefined) t_to = container.getSMOutcomeByName(transition.getTo().getStateName()); container.addTransition(new Transition(sm, t_to, oc, -1)); }); transitions_in.forEach(function(transition) { diff --git a/src/_model/behaviorstate.js b/src/_model/behaviorstate.js index c39c6279d061e38ba8f6fd8ed0adcad109ad2b70..33da5af02c37ff58a866f8f2b2c4e9f6d487f081 100644 --- a/src/_model/behaviorstate.js +++ b/src/_model/behaviorstate.js @@ -1,4 +1,4 @@ -BehaviorState = function(be_name, be_definition) { +BehaviorState = function(be_name, be_definition, be_defkeys) { State.apply(this, [be_name, be_definition]); var that = this; @@ -6,6 +6,7 @@ BehaviorState = function(be_name, be_definition) { var behavior_manifest = be_definition.getBehaviorManifest(); var behavior_statemachine = be_definition.cloneBehaviorStatemachine(); behavior_statemachine.setBehavior(that); + var default_keys = be_defkeys; this.getBehaviorName = function() { return behavior_name; @@ -18,6 +19,27 @@ BehaviorState = function(be_name, be_definition) { this.getBehaviorManifest = function() { return behavior_manifest; } + + this.getDefaultKeys = function() { + return default_keys; + } + + this.addDefaultKey = function(new_key) { + if (default_keys.contains(new_key)) return; + default_keys.push(new_key); + } + + this.removeDefaultKey = function(key) { + if (!default_keys.contains(key)) return; + default_keys.remove(key); + } + + this.getDefaultValue = function(key) { + var element = be_definition.getDefaultUserdata().findElement(function(el) { + return el.key == key; + }); + return (element != undefined)? element.value : ""; + } }; BehaviorState.prototype = Object.create(State.prototype); \ No newline at end of file diff --git a/src/_model/statemachine.js b/src/_model/statemachine.js index 2d1e0d550c9261975df7cf38979358637d814eb3..ceaf522275d62fc8c4eb14626c5c44552b4ec5bb 100644 --- a/src/_model/statemachine.js +++ b/src/_model/statemachine.js @@ -161,8 +161,9 @@ Statemachine = function(sm_name, sm_definition) { dataflow = []; states.forEach(function(state) { var added_keys = [] - state.getInputMapping().forEach(function(key) { + state.getInputMapping().forEach(function(key, i) { if (added_keys.contains(key)) return; + if (state instanceof BehaviorState && state.getDefaultKeys().contains(state.getInputKeys()[i])) return; added_keys.push(key); addDataEdgeForPredecessors(state, state, key, []); }); @@ -175,19 +176,25 @@ Statemachine = function(sm_name, sm_definition) { } var addDataEdgeForPredecessors = function(state, target, key, checked) { - transitions.forEach(function(trans) { - if (trans.getTo() == undefined || trans.getTo().getStateName() != state.getStateName()) return; - if (trans.getFrom().getStateName() == "INIT") { - dataflow.push(new Transition(trans.getFrom(), target, key, 0)); - } else if (!checked.contains(trans.getFrom().getStateName())) { - checked.push(trans.getFrom().getStateName()); - if (trans.getFrom().getOutputMapping().contains(key)) { + if (concurrent) { + var init = that.getInitialTransition().getFrom(); + // in concurrency, userdata always needs to be given from container keys + dataflow.push(new Transition(init, target, key, 0)); + } else { + transitions.forEach(function(trans) { + if (trans.getTo() == undefined || trans.getTo().getStateName() != state.getStateName()) return; + if (trans.getFrom().getStateName() == "INIT") { dataflow.push(new Transition(trans.getFrom(), target, key, 0)); - } else { - addDataEdgeForPredecessors(trans.getFrom(), target, key, checked); + } else if (!checked.contains(trans.getFrom().getStateName())) { + checked.push(trans.getFrom().getStateName()); + if (trans.getFrom().getOutputMapping().contains(key)) { + dataflow.push(new Transition(trans.getFrom(), target, key, 0)); + } else { + addDataEdgeForPredecessors(trans.getFrom(), target, key, checked); + } } - } - }); + }); + } } diff --git a/src/_testing/scripts.js b/src/_testing/scripts.js index 9bae8af7d3dfd01bd2276460196b9aa6a6c7edf2..99a34499eb76fc289a54fa899c4c6fc84dcde999 100644 --- a/src/_testing/scripts.js +++ b/src/_testing/scripts.js @@ -30,17 +30,20 @@ Scripts = new (function() { T.clearLog(); T.show(); var total = 0; - Behaviorlib.getBehaviorList().forEach(function (bn) { - var bsm = Behaviorlib.getByName(bn).cloneBehaviorStatemachine(); + WS.Behaviorlib.getBehaviorList().forEach(function (bn) { + var bsm = WS.Behaviorlib.getByName(bn).cloneBehaviorStatemachine(); var states = searchFunction(bsm, function(s) { return s.getStateClass() == class_name; }); if (states.length > 0) { + if (total == 0) { + T.logInfo("Found the following uses of state class " + class_name + ":"); + } T.logInfo(bn + " (" + states.length + "x)"); states.forEach(function(s) { T.logInfo(" " + s.getStatePath()); }); } total += states.length; }); if (total == 0) { - T.logInfo("Did not find any usage of state class " + class_name); + T.logInfo("Did not find any usage of state class " + class_name + "."); } } diff --git a/src/events.js b/src/events.js index f8dcad27433a6803b49a9cf73caf66112c5842fb..7374fa07a579775de317392d9aeb68b0b58712c4 100644 --- a/src/events.js +++ b/src/events.js @@ -140,13 +140,27 @@ document.addEventListener('DOMContentLoaded', function() { Mousetrap.bind("ctrl+c", Tools.copy); Mousetrap.bind("ctrl+x", Tools.cut); - Mousetrap.bind("ctrl+v", Tools.paste); + Mousetrap.bind("ctrl+v", Tools.paste); + + Mousetrap.bind("f1", UI.Menu.toDashboardClicked ); + Mousetrap.bind("f2", UI.Menu.toStatemachineClicked ); + Mousetrap.bind("f3", UI.Menu.toControlClicked ); + Mousetrap.bind("f4", UI.Menu.toSettingsClicked ); + + Mousetrap.bind("ctrl+t", UI.Panels.Terminal.toggle ); Mousetrap.bind("esc", function() { UI.Statemachine.abortTransition(); UI.Statemachine.removeSelection(); }); + UI.Menu.configureKeybindings(); + + Mousetrap(document.getElementById("input_note_editor_text")).bind("shift+enter", function() { + var evt = new CustomEvent("click", { "detail": "shift+enter" }); + document.getElementById("button_note_editor_save").dispatchEvent(evt); + }); + //////////////////////////////////////////////////////////////////////////////////////////////// nw.Window.get().on('new-win-policy', function(frame, url, policy) { diff --git a/src/ext/mousetrap.min.js b/src/ext/mousetrap.min.js index 114a22235c52122891cb29f342e64c6e1f0e05dd..8459cef9d36ff002ac499684f0dbd0111ea0e742 100644 --- a/src/ext/mousetrap.min.js +++ b/src/ext/mousetrap.min.js @@ -1,9 +1,12 @@ -/* mousetrap v1.4.6 craig.is/killing/mice */ -(function(J,r,f){function s(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,d;for(d in n)a[d]?b=!0:n[d]=0;b||(u=!1)}function C(a,b,d,c,e,v){var g,k,f=[],h=d.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;g<l[a].length;++g)if(k= -l[a][g],!(!c&&k.seq&&n[k.seq]!=k.level||h!=k.action||("keypress"!=h||d.metaKey||d.ctrlKey)&&b.sort().join(",")!==k.modifiers.sort().join(","))){var m=c&&k.seq==c&&k.level==v;(!c&&k.combo==e||m)&&l[a].splice(g,1);f.push(k)}return f}function K(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function x(a,b,d,c){m.stopCallback(b,b.target||b.srcElement,d,c)||!1!==a(b,d)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation? -b.stopPropagation():b.cancelBubble=!0)}function y(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=A(a);b&&("keyup"==a.type&&z===b?z=!1:m.handleKey(b,K(a),a))}function w(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function L(a,b,d,c){function e(b){return function(){u=b;++n[a];clearTimeout(D);D=setTimeout(t,1E3)}}function v(b){x(d,b,a);"keyup"!==c&&(z=A(b));setTimeout(t,10)}for(var g=n[a]=0;g<b.length;++g){var f=g+1===b.length?v:e(c||E(b[g+1]).action);F(b[g],f,c,a,g)}}function E(a,b){var d, -c,e,f=[];d="+"===a?["+"]:a.split("+");for(e=0;e<d.length;++e)c=d[e],G[c]&&(c=G[c]),b&&"keypress"!=b&&H[c]&&(c=H[c],f.push("shift")),w(c)&&f.push(c);d=c;e=b;if(!e){if(!p){p={};for(var g in h)95<g&&112>g||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1<f.length?L(a,f,b,d):(d=E(a,d),l[d.key]=l[d.key]||[],C(d.key,d.modifiers,{type:d.action}, -c,a,e),l[d.key][c?"unshift":"push"]({callback:b,modifiers:d.modifiers,action:d.action,seq:c,level:e,combo:a}))}var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},B={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},H={"~":"`","!":"1", -"@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;c<a.length;++c)F(a[c],b,d);return this}, -unbind:function(a,b){return m.bind(a,function(){},b)},trigger:function(a,b){if(q[a+":"+b])q[a+":"+b]({},a);return this},reset:function(){l={};q={};return this},stopCallback:function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable},handleKey:function(a,b,d){var c=C(a,b,d),e;b={};var f=0,g=!1;for(e=0;e<c.length;++e)c[e].seq&&(f=Math.max(f,c[e].level));for(e=0;e<c.length;++e)c[e].seq?c[e].level==f&&(g=!0, -b[c[e].seq]=1,x(c[e].callback,d,c[e].combo,c[e].seq)):g||x(c[e].callback,d,c[e].combo);c="keypress"==d.type&&I;d.type!=u||w(a)||c||t(b);I=g&&"keydown"==d.type}};J.Mousetrap=m;"function"===typeof define&&define.amd&&define(m)})(window,document); +/* mousetrap v1.6.1 craig.is/killing/mice */ +(function(r,v,f){function w(a,b,g){a.addEventListener?a.addEventListener(b,g,!1):a.attachEvent("on"+b,g)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return p[a.which]?p[a.which]:t[a.which]?t[a.which]:String.fromCharCode(a.which).toLowerCase()}function F(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function x(a){return"shift"==a||"ctrl"==a||"alt"==a|| +"meta"==a}function B(a,b){var g,c,d,f=[];g=a;"+"===g?g=["+"]:(g=g.replace(/\+{2}/g,"+plus"),g=g.split("+"));for(d=0;d<g.length;++d)c=g[d],C[c]&&(c=C[c]),b&&"keypress"!=b&&D[c]&&(c=D[c],f.push("shift")),x(c)&&f.push(c);g=c;d=b;if(!d){if(!n){n={};for(var q in p)95<q&&112>q||p.hasOwnProperty(q)&&(n[p[q]]=q)}d=n[g]?"keydown":"keypress"}"keypress"==d&&f.length&&(d="keydown");return{key:c,modifiers:f,action:d}}function E(a,b){return null===a||a===v?!1:a===b?!0:E(a.parentNode,b)}function c(a){function b(a){a= +a||{};var b=!1,l;for(l in n)a[l]?b=!0:n[l]=0;b||(y=!1)}function g(a,b,u,e,c,g){var l,m,k=[],f=u.type;if(!h._callbacks[a])return[];"keyup"==f&&x(a)&&(b=[a]);for(l=0;l<h._callbacks[a].length;++l)if(m=h._callbacks[a][l],(e||!m.seq||n[m.seq]==m.level)&&f==m.action){var d;(d="keypress"==f&&!u.metaKey&&!u.ctrlKey)||(d=m.modifiers,d=b.sort().join(",")===d.sort().join(","));d&&(d=e&&m.seq==e&&m.level==g,(!e&&m.combo==c||d)&&h._callbacks[a].splice(l,1),k.push(m))}return k}function f(a,b,c,e){h.stopCallback(b, +b.target||b.srcElement,c,e)||!1!==a(b,c)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function d(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=A(a);b&&("keyup"==a.type&&z===b?z=!1:h.handleKey(b,F(a),a))}function p(a,c,u,e){function l(c){return function(){y=c;++n[a];clearTimeout(r);r=setTimeout(b,1E3)}}function g(c){f(u,c,a);"keyup"!==e&&(z=A(c));setTimeout(b,10)}for(var d=n[a]=0;d<c.length;++d){var m=d+1===c.length?g:l(e|| +B(c[d+1]).action);q(c[d],m,e,a,d)}}function q(a,b,c,e,d){h._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1<f.length?p(a,f,b,c):(c=B(a,c),h._callbacks[c.key]=h._callbacks[c.key]||[],g(c.key,c.modifiers,{type:c.action},e,a,d),h._callbacks[c.key][e?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:e,level:d,combo:a}))}var h=this;a=a||v;if(!(h instanceof c))return new c(a);h.target=a;h._callbacks={};h._directMap={};var n={},r,z=!1,t=!1,y=!1;h._handleKey=function(a, +c,d){var e=g(a,c,d),k;c={};var h=0,l=!1;for(k=0;k<e.length;++k)e[k].seq&&(h=Math.max(h,e[k].level));for(k=0;k<e.length;++k)e[k].seq?e[k].level==h&&(l=!0,c[e[k].seq]=1,f(e[k].callback,d,e[k].combo,e[k].seq)):l||f(e[k].callback,d,e[k].combo);e="keypress"==d.type&&t;d.type!=y||x(a)||e||b(c);t=l&&"keydown"==d.type};h._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)q(a[d],b,c)};w(a,"keypress",d);w(a,"keydown",d);w(a,"keyup",d)}if(r){var p={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl", +18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},t={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},D={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},C={option:"alt",command:"meta","return":"enter", +escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},n;for(f=1;20>f;++f)p[111+f]="f"+f;for(f=0;9>=f;++f)p[f+96]=f.toString();c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={}; +this._directMap={};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||E(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.addKeycodes=function(a){for(var b in a)a.hasOwnProperty(b)&&(p[b]=a[b]);n=null};c.init=function(){var a=c(v),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a, +arguments)}}(b))};c.init();r.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=c);"function"===typeof define&&define.amd&&define(function(){return c})}})("undefined"!==typeof window?window:null,"undefined"!==typeof window?document:null); + diff --git a/src/io/io_behaviorloader.js b/src/io/io_behaviorloader.js index 2ba3ee5092210d121cacfb85847238020ff6bfdd..f5ca06ffc04a4d8e9ebef8407fdad0b60e018183 100644 --- a/src/io/io_behaviorloader.js +++ b/src/io/io_behaviorloader.js @@ -134,7 +134,8 @@ IO.BehaviorLoader = new (function() { container_name: "", container_sm_var_name: parsingResult.root_sm_name, sm_defs: parsingResult.sm_defs, - sm_states: parsingResult.sm_states + sm_states: parsingResult.sm_states, + default_userdata: parsingResult.default_userdata }); }); }); diff --git a/src/io/io_codegenerator.js b/src/io/io_codegenerator.js index a957da01ba870df14bb98773f37b5e321389d5b2..32483b43e9cb9c1e59ef6d60fb6167351c148e33 100644 --- a/src/io/io_codegenerator.js +++ b/src/io/io_codegenerator.js @@ -290,7 +290,16 @@ IO.CodeGenerator = new (function() { code += ws+ws+ws+ws+ws+ws+ws+ws+ws+ws+ sm_name + ",\n"; } else if (s instanceof BehaviorState) { - code += ws+ws+ws+ws+ws+ws+ws+ws+ws+ws+"self.use_behavior(" + s.getStateClass() + ", '" + s.getStatePath().substr(1) + "'),\n"; + var defkeys_str = ""; + var be_defkeys = s.getDefaultKeys(); + if (be_defkeys.length > 0) { + var be_defkeys_str = [] + for (var j = 0; j < be_defkeys.length; j++) { + be_defkeys_str.push("'"+be_defkeys[j]+"'"); + } + defkeys_str = ", default_keys=[" + be_defkeys_str.join(',') + "]"; + } + code += ws+ws+ws+ws+ws+ws+ws+ws+ws+ws+"self.use_behavior(" + s.getStateClass() + ", '" + s.getStatePath().substr(1) + "'" + defkeys_str + "),\n"; } else { code += ws+ws+ws+ws+ws+ws+ws+ws+ws+ws+ s.getStateClass() + "("; diff --git a/src/io/io_codeparser.js b/src/io/io_codeparser.js index d3b3b4db64475ed490940178bb90bf38f99b1ab5..980600dc669ad133172b5eca1682f1cfb286e190 100644 --- a/src/io/io_codeparser.js +++ b/src/io/io_codeparser.js @@ -86,8 +86,8 @@ IO.CodeParser = new (function() { var string_quotes_pattern = /^["'](.*)["']/; // [1] - name of the state class var state_class_pattern = /^\s*(\w+)\(/; - // [1] - name of the behavior class - var state_behavior_pattern = /^\s*self\.use_behavior\((\w+)(?:, ['"](?:[^'"]*)['"])?\)/; + // [1] - name of the behavior class , [2] - (optional) list of default keys + var state_behavior_pattern = /^\s*self\.use_behavior\((\w+)(?:, ?['"](?:[^'"]*)['"])?(?:, ?default_keys ?= ?\[([^\]]*)\])?\)/; // [1] - kind of data (transitions/autonomy/remapping), [2] - comma separated list of values including surrounding braces var state_interface_pattern = /(transitions|autonomy|remapping)\s*=\s*(\{[^}]*\})/; @@ -479,7 +479,11 @@ IO.CodeParser = new (function() { if (behavior_use_result != null) { state_class = behavior_use_result[1]; state_type = "behavior"; - parameter_values = []; + if (behavior_use_result[2] != undefined) { + parameter_values = behavior_use_result[2].replace(/["'\s]/g, '').split(','); + } else { + parameter_values = []; + } } else { state_class = params[1]; parameter_values = undefined; diff --git a/src/io/io_modelgenerator.js b/src/io/io_modelgenerator.js index 41a27acc5dec9e237517fa728fe9c466b01df2c6..9ff95f72af590bcc78b2894b206d288bfd19488b 100644 --- a/src/io/io_modelgenerator.js +++ b/src/io/io_modelgenerator.js @@ -86,7 +86,7 @@ IO.ModelGenerator = new (function() { T.logInfo("Please check your workspace settings."); continue; } - s = new BehaviorState(s_def.state_name, state_def); + s = new BehaviorState(s_def.state_name, state_def, s_def.parameter_values); } else { var state_def = WS.Statelib.getFromLib(s_def.state_class); if (state_def == undefined) { diff --git a/src/io/io_stateparser.js b/src/io/io_stateparser.js index 04c62d4292aad737aa89291e6f53934ac97944a1..7621216e96c54cb26a7918a9215eaa650ad365fa 100644 --- a/src/io/io_stateparser.js +++ b/src/io/io_stateparser.js @@ -6,7 +6,7 @@ IO.StateParser = new (function() { // Inherits from EventState, state description is directly below class definition. var name_desc_pattern = /class (\w+)\(EventState\):(?:\n\r?\s+(?:'''|""")\n?\r?((?:\s*(?:.*?)\n?\r?\s*)*?)(?:'''|"""))?/i; // Returns all params as list - var param_pattern = /def __init__\(self, ([^)]+)\):/i; + var param_pattern = /def __init__\(self, ?([^)]+)\):/i; // Extracts parameters of super class call, such as outcomes. var super_pattern = /super\(.*\)\.__init__\(((?:.|\s)*?)\)\n/i; // Has two matches: 1) key 2) list diff --git a/src/ui/panels/ui_panels_addstate.js b/src/ui/panels/ui_panels_addstate.js index 81c167e209f6cb95b8ad0a0aa7d98cc2af87e42e..04d1ce9ada355d597079ec4c86fcf48e57e0e0ea 100644 --- a/src/ui/panels/ui_panels_addstate.js +++ b/src/ui/panels/ui_panels_addstate.js @@ -125,6 +125,7 @@ UI.Panels.AddState = new (function() { this.show = function() { + panel_class_select.innerHTML = ""; statelib = WS.Statelib.getClassList(); displayStateClasses(statelib); UI.Panels.setActivePanel(UI.Panels.ADD_STATE_PANEL); diff --git a/src/ui/panels/ui_panels_stateproperties.js b/src/ui/panels/ui_panels_stateproperties.js index 3fb466b19ce79279c07c954e65ec7437be7dc32c..a17dd54199cc945566e4ea109805d355f5c77d43 100644 --- a/src/ui/panels/ui_panels_stateproperties.js +++ b/src/ui/panels/ui_panels_stateproperties.js @@ -465,6 +465,11 @@ UI.Panels.StateProperties = new (function() { input_field.setAttribute("type", "text"); input_field.setAttribute("value", input_mapping[i]); input_field.setAttribute("input_key", input_keys[i]); + if (state.getDefaultKeys().contains(input_keys[i])) { + input_field.setAttribute("style", "text-decoration: line-through; color: rgba(0,0,0,.4);"); + input_field.setAttribute("disabled", "disabled"); + input_field.setAttribute("title", "Value: " + state.getDefaultValue(input_keys[i])); + } input_field.addEventListener("blur", function() { if (RC.Controller.isReadonly() || UI.Statemachine.getDisplayedSM().isInsideDifferentBehavior() @@ -479,9 +484,43 @@ UI.Panels.StateProperties = new (function() { input_field_td.appendChild(input_field); addAutocomplete(input_field, undefined, "input", state); + var default_button = document.createElement("input"); + default_button.setAttribute("type", "checkbox"); + default_button.setAttribute("input_key", input_keys[i]); + if (state.getDefaultKeys().contains(input_keys[i])) { + default_button.setAttribute("checked", "checked"); + } + default_button.addEventListener("change", function() { + if (RC.Controller.isReadonly() + || UI.Statemachine.getDisplayedSM().isInsideDifferentBehavior() + || RC.Controller.isLocked() && RC.Controller.isStateLocked(current_prop_state.getStatePath()) + || RC.Controller.isOnLockedPath(current_prop_state.getStatePath()) + ) return; + var input_field = this.parentNode.parentNode.childNodes[1].firstChild; + if(this.checked) { + input_field.setAttribute("style", "text-decoration: line-through; color: rgba(0,0,0,.4);"); + input_field.setAttribute("disabled", "disabled"); + state.addDefaultKey(this.getAttribute("input_key")); + input_field.setAttribute("title", "Value: " + state.getDefaultValue(this.getAttribute("input_key"))); + } else { + input_field.removeAttribute("style"); + input_field.removeAttribute("disabled"); + input_field.removeAttribute("title"); + state.removeDefaultKey(this.getAttribute("input_key")); + } + if (UI.Statemachine.isDataflow()) UI.Statemachine.refreshView(); + }); + var default_button_txt = document.createElement("label"); + default_button_txt.innerText = "default"; + var default_button_td = document.createElement("td"); + default_button_td.setAttribute("title", "Use the default value as defined by the behavior."); + default_button_td.appendChild(default_button); + default_button_td.appendChild(default_button_txt); + var row = document.createElement("tr"); row.appendChild(label); row.appendChild(input_field_td); + row.appendChild(default_button_td); document.getElementById("panel_prop_be_input_keys_content").appendChild(row); } } else { @@ -631,7 +670,7 @@ UI.Panels.StateProperties = new (function() { var command = UI.Settings.getEditorCommand(file_path).split(' '); var proc = spawn(command[0], command.slice(1)); proc.stderr.on('data', (data) => { - T.logError(data); + T.logWarn(data); }); } catch (err) { T.logError("Unable to open state in editor: " + err); diff --git a/src/ui/panels/ui_panels_terminal.js b/src/ui/panels/ui_panels_terminal.js index ef49216bad265f777d2939157c488b9725171ffd..7924e5faaf19196b56da5c71e98c7f3751959c4a 100644 --- a/src/ui/panels/ui_panels_terminal.js +++ b/src/ui/panels/ui_panels_terminal.js @@ -1,6 +1,7 @@ UI.Panels.Terminal = new (function() { var that = this; var debug_mode = false; + var is_active = false; var logTerminal = function (msg, color) { document.getElementById("terminal").innerHTML += "<font style='color: " + color + ";'>" + msg + "</font><br />"; @@ -54,10 +55,17 @@ UI.Panels.Terminal = new (function() { this.show = function() { UI.Panels.setActivePanel(UI.Panels.TERMINAL_PANEL); + is_active = true; } this.hide = function() { UI.Panels.hidePanelIfActive(UI.Panels.TERMINAL_PANEL); + is_active = false; + } + + this.toggle = function() { + if (is_active) that.hide(); + else that.show(); } }) (); diff --git a/src/ui/ui_dashboard.js b/src/ui/ui_dashboard.js index 13e2ff9a7512d590e484c3c8c9baa5d3333d474b..a3a112ae814e003ee2ee65043d829b2f28dd430e 100644 --- a/src/ui/ui_dashboard.js +++ b/src/ui/ui_dashboard.js @@ -338,7 +338,7 @@ UI.Dashboard = new (function() { name_input_field.setAttribute("readonly", "readonly"); var params_input_field = document.createElement("input"); - params_input_field.setAttribute("value", new_params); + params_input_field.setAttribute("value", new_params != undefined ? new_params : ""); params_input_field.setAttribute("name", new_name); params_input_field.setAttribute("class", "inline_text_edit_readonly"); params_input_field.setAttribute("type", "text"); @@ -716,10 +716,10 @@ UI.Dashboard = new (function() { if (this.value.match(/^-?[0-9]+(\.[0-9]+)?$/i) == undefined) { this.value = entry.default; } - if (parseInt(this.value) < parseInt(entry.additional.min)) { + if (parseFloat(this.value) < parseFloat(entry.additional.min)) { this.value = entry.additional.min; } - if (parseInt(this.value) > parseInt(entry.additional.max)) { + if (parseFloat(this.value) > parseFloat(entry.additional.max)) { this.value = entry.additional.max; } } else if (entry.type == "enum") { @@ -895,13 +895,13 @@ UI.Dashboard = new (function() { var additional = Behavior.getBehaviorParameters().findElement(function(element) { return element.name == name; }).additional; - if (parseInt(this.value) > parseInt(additional.max)) this.value = additional.max; + if (parseFloat(this.value) > parseFloat(additional.max)) this.value = additional.max; additional.min = this.value; Behavior.updateBehaviorParameter(name, additional, "additional"); // update default value var default_field = this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.children[3].children[2].children[0]; - if (parseInt(default_field.value) < parseInt(this.value)) { + if (parseFloat(default_field.value) < parseFloat(this.value)) { default_field.value = this.value; Behavior.updateBehaviorParameter(name, this.value, "default"); } @@ -917,13 +917,13 @@ UI.Dashboard = new (function() { var additional = Behavior.getBehaviorParameters().findElement(function(element) { return element.name == name; }).additional; - if (parseInt(this.value) < parseInt(additional.min)) this.value = additional.min; + if (parseFloat(this.value) < parseFloat(additional.min)) this.value = additional.min; additional.max = this.value; Behavior.updateBehaviorParameter(name, additional, "additional"); // update default value var default_field = this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.children[3].children[2].children[0]; - if (parseInt(default_field.value) > parseInt(this.value)) { + if (parseFloat(default_field.value) > parseFloat(this.value)) { default_field.value = this.value; Behavior.updateBehaviorParameter(name, this.value, "default"); } diff --git a/src/ui/ui_menu.js b/src/ui/ui_menu.js index bbccec22936a92f21dfe997c762d4475f7f77c69..4fae0c90e4d47eb1c1f3701b670b6f6c6cda641f 100644 --- a/src/ui/ui_menu.js +++ b/src/ui/ui_menu.js @@ -27,7 +27,7 @@ UI.Menu = new (function() { ["Save Behavior", "file_save", function() { UI.Menu.saveBehaviorClicked(); }] ], [ - ["Edit Code", "page_edit", function() { UI.Menu.scEditClicked(); }] + ["Edit Code", "page_edit", function() { UI.Menu.scEditClicked(); }, "ctrl+e"] ], [ ["Check Behavior", "check", function() { UI.Menu.checkBehaviorClicked(); }] @@ -35,38 +35,38 @@ UI.Menu = new (function() { ]; var button_config_sm = [ [ - ["Add State", "add", function() { UI.Menu.addStateClicked(); }], - ["Add Behavior", "add", function() { UI.Menu.addBehaviorClicked(); }], - ["Add Container", "add", function() { UI.Menu.addStatemachineClicked(); }] + ["Add State", "add", function() { UI.Menu.addStateClicked(); }, "ctrl+1"], + ["Add Behavior", "add", function() { UI.Menu.addBehaviorClicked(); }, "ctrl+2"], + ["Add Container", "add", function() { UI.Menu.addStatemachineClicked(); }, "ctrl+3"] ], [ - ["Data Flow Graph", "dataflow", function() { UI.Statemachine.toggleDataflow(); }], + ["Data Flow Graph", "dataflow", function() { UI.Statemachine.toggleDataflow(); }, "ctrl+d"], ["Check Behavior", "check", function() { UI.Menu.checkBehaviorClicked(); }], ["Save Behavior", "file_save", function() { UI.Menu.saveBehaviorClicked(); }] ], [ - ["Undo", "undo", function() { ActivityTracer.undo(); }], - ["Redo", "redo", function() { ActivityTracer.redo(); }], + ["Undo", "undo", function() { ActivityTracer.undo(); }, undefined], + ["Redo", "redo", function() { ActivityTracer.redo(); }, undefined], ["Reset", "cross", function() { ActivityTracer.resetToSave(); }] ], [ - ["Hide Comments", "note", function() { UI.Statemachine.toggleComments(); }], - ["Write Comment", "note_add", function() { UI.Menu.addCommentClicked(); }] + ["Hide Comments", "note", function() { UI.Statemachine.toggleComments(); }, "ctrl+h"], + ["Write Comment", "note_add", function() { UI.Menu.addCommentClicked(); }, "ctrl+4"] ], [ - ["Fade Outcomes", "outcome", function() { UI.Statemachine.toggleOutcomes(); }], - ["Auto-Connect", "autoconnect", function() { Tools.autoconnect(); }], - ["Group Selection", "group_selection", function() { Tools.groupSelection(); }] + ["Fade Outcomes", "outcome", function() { UI.Statemachine.toggleOutcomes(); }, "ctrl+f"], + ["Auto-Connect", "autoconnect", function() { Tools.autoconnect(); }, "ctrl+a"], + ["Group Selection", "group_selection", function() { Tools.groupSelection(); }, "ctrl+g"] ] ]; var button_config_rc = [ [ - ["Show Terminal", "title_terminal", function() { UI.Menu.terminalClicked(); }] + ["Show Terminal", "title_terminal", function() { UI.Menu.terminalClicked(); }, undefined] ] ]; var button_config_se = [ [ - ["Show Terminal", "title_terminal", function() { UI.Menu.terminalClicked(); }] + ["Show Terminal", "title_terminal", function() { UI.Menu.terminalClicked(); }, undefined] ], [ ["Import Configuration", "settings_import", function() { UI.Settings.importConfiguration(); }], @@ -74,7 +74,6 @@ UI.Menu = new (function() { ] ]; - var setMenuButtons = function(config) { panel = document.getElementById("title_button_panel"); panel.innerHTML = ""; @@ -110,6 +109,20 @@ UI.Menu = new (function() { this.isPageControl = function() { return current_page == "rc"; } this.isPageSettings = function() { return current_page == "se"; } + this.configureKeybindings = function() { + [[button_config_db, that.isPageDashboard], + [button_config_sm, that.isPageStatemachine], + [button_config_rc, that.isPageControl], + [button_config_se, that.isPageSettings] + ].forEach(function(element) { + element[0].forEach(function(column) { + column.forEach(function(button) { + if (button[3] == undefined) return; + Mousetrap.bind(button[3], function() { + if (!element[1]()) return; + button[2](); + }); }); }); }); + } this.toDashboardClicked = function() { document.getElementById("dashboard").style.left = "0px"; @@ -175,7 +188,7 @@ UI.Menu = new (function() { var command = UI.Settings.getEditorCommand(file_path).split(' '); var proc = spawn(command[0], command.slice(1)); proc.stderr.on('data', (data) => { - T.logError(data); + T.logWarn(data); }); } catch (err) { T.logError("Unable to open editor. Make sure you already saved the behavior to generate code files."); @@ -196,7 +209,7 @@ UI.Menu = new (function() { IO.BehaviorLoader.loadBehaviorInterface(manifest, function(smi) { if (smi.class_name != manifest.class_name) T.logWarn("Class names of behavior " + manifest.name + " do not match!"); var be_def = WS.Behaviorlib.getByName(manifest.name); - var be = new BehaviorState(manifest.name, be_def); + var be = new BehaviorState(manifest.name, be_def, []); be.setStateName(Tools.getUniqueName(UI.Statemachine.getDisplayedSM(), be.getStateName())); UI.Statemachine.getDisplayedSM().addState(be); UI.Statemachine.refreshView(); @@ -218,7 +231,7 @@ UI.Menu = new (function() { }, function() { var container = (container_path == "")? Behavior.getStatemachine() : Behavior.getStatemachine().getStateByPath(container_path); - var redo_state = new BehaviorState(be_name, WS.Behaviorlib.getByName(be_name)); + var redo_state = new BehaviorState(be_name, WS.Behaviorlib.getByName(be_name), []); container.addState(redo_state); UI.Statemachine.refreshView(); } @@ -334,6 +347,7 @@ UI.Menu = new (function() { this.addCommentClicked = function() { if (UI.Statemachine.isReadonly()) return; + if (Behavior.getCommentNotes().findElement(function(n) { return n.getContent() == ""; }) != undefined) return; var note = new Note(""); note.setContainerPath(UI.Statemachine.getDisplayedSM().getStatePath()); diff --git a/src/ui/ui_statemachine.js b/src/ui/ui_statemachine.js index fe69d3a8974635dee81377601f5a09c432ef5aea..e3b08ca555851369c67cdf0145f165cbc1d92dc6 100644 --- a/src/ui/ui_statemachine.js +++ b/src/ui/ui_statemachine.js @@ -542,6 +542,8 @@ UI.Statemachine = new (function() { if (drag_transition == displayed_sm.getInitialTransition()) { displayed_sm.setInitialState(displayed_sm.getStateByName(previous_transition_end)); + } else if (previous_transition_end != undefined) { + drag_transition.setTo(displayed_sm.getStateByName(previous_transition_end)); } connecting = false; diff --git a/src/ws/ws_behaviorstatedefinition.js b/src/ws/ws_behaviorstatedefinition.js index 3e0986ae734f26b9888b3615d9d9d40471ccab47..f8d6c568e77bed4c58bc1df5d06d00c47bccb0e2 100644 --- a/src/ws/ws_behaviorstatedefinition.js +++ b/src/ws/ws_behaviorstatedefinition.js @@ -23,6 +23,7 @@ WS.BehaviorStateDefinition = function(manifest, outcomes, input_keys, output_key this.getBehaviorManifest = function() { return behavior_manifest; } this.getBehaviorDesc = function() { return behavior_manifest.description; } this.getBehaviorTagList = function() { return behavior_tag_list; } + this.getDefaultUserdata = function() { return bsm_parsing_result.default_userdata; } this.cloneBehaviorStatemachine = function() { return IO.ModelGenerator.buildStateMachine(bsm_parsing_result.container_name, bsm_parsing_result.container_sm_var_name, bsm_parsing_result.sm_defs, bsm_parsing_result.sm_states, true);