diff --git a/js/top/.rcs/sejam2.js,v b/js/top/.rcs/sejam2.js,v new file mode 100644 index 0000000..4ba4610 --- /dev/null +++ b/js/top/.rcs/sejam2.js,v @@ -0,0 +1,3264 @@ +head 1.5; +access; +symbols; +locks + sbosse:1.5; strict; +comment @# @; + + +1.5 +date 2020.02.03.09.45.01; author sbosse; state Exp; +branches; +next 1.4; + +1.4 +date 2017.06.19.17.18.39; author sbosse; state Exp; +branches; +next 1.3; + +1.3 +date 2017.06.06.14.53.57; author sbosse; state Exp; +branches; +next 1.2; + +1.2 +date 2017.05.27.18.20.44; author sbosse; state Exp; +branches; +next 1.1; + +1.1 +date 2017.05.23.07.00.54; author sbosse; state Exp; +branches; +next ; + + +desc +@@ + + +1.5 +log +@. +@ +text +@/** + ** ============================== + ** O O O OOOO + ** O O O O O O + ** O O O O O O + ** OOOO OOOO O OOO OOOO + ** O O O O O O O + ** O O O O O O O + ** OOOO OOOO O O OOOO + ** ============================== + ** Dr. Stefan Bosse http://www.bsslab.de + ** + ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED + ** BY THE AUTHOR(S). + ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, + ** MODIFIED, OR OTHERWISE USED IN A CONTEXT + ** OUTSIDE OF THE SOFTWARE SYSTEM. + ** + ** $AUTHORS: Stefan Bosse + ** $INITIAL: (C) 2006-2020 bLAB + ** $CREATED: 01-02-17 by sbosse. + ** $VERSION: 1.16.3 + ** + ** $INFO: + ** + ** SEJAM2: Simulation Environment for JAM, GUI Webix+, Anychart Graphics, Cannon Phy Simu, NW edition + ** + ** $ENDOFINFO + */ + +global.config={ + simulation:'simu/simuWEB', + dos:false, + nonetwork:false, + wine:false, + os:null, +}; +sejamVersion = '1.9.1' + +Require('os/polyfill'); + +var Io = Require('com/io'); +var Comp = Require('com/compat'); +var Name = Require('com/pwgen'); +var Aios = Require('jam/aios'); +var Fs = Require('fs'); +var Path = Require('com/path'); +var Esprima = Require('parser/esprima'); +var util = Require('util'); +var simuPhy = Require('simu/simuPHY'); +var simuSens = Require('simu/simuSENS'); +var Base64 = Require('os/base64'); +var Marked = Require('doc/marked'); + +Require('os/polyfill') + +if (typeof process != 'undefined') global.config.os=process.platform; +if (global.config.os=='win32') global.config.wine=Io.getenv('WINE',''); + +function sq(x) {return x*x} +function equal(a,b) { + if (a==undefined || b==undefined) return false; + if (Comp.obj.isArray(a) && Comp.obj.isArray(b)) + return Comp.array.equal(a,b); +}; + + +var physicalAttributeSet = [ + 'masses', 'loadings','springs','id', + 'x','y','z','mass','force', + 'position','gridPosition','velocity','torque', + 'restLength','length','stiffness','damping', + 'bodyA','bodyB', + /[0-9]+/ +] + +// TODO: Replace many magic (heuristic) GUI window constants by reasonable values + +var gui = function (options) { + var self=this; + this.nwgui = options.nwgui; + this.UI = options.UI; + this.webix = options.webix; + this.acgraph = options.acgraph; + this.CANNON = options.CANNON; + this.Database = options.Database; + this.Marked = Marked; + this.utils = options.utils||{}; + this.version = sejamVersion; + + this.worldname = 'MY World'; + // if (Io.getenv('WINE','')!='' || process.platform == 'win32') { + // this.workdir=Io.getenv('CWD','/'); + //} else + // this.workdir = Io.getenv('PWD','/'); + this.workdir=Io.getenv('CWD',Io.getenv('PWD','/')); + this._filename=''; + // Top-level model file name + this.filename = ''; + this.filesimu = 'simulation.js'; + this.model = {}; + this.source = '{\nname:"world",\nclasses:{},\nworld:{}\n}'; + this.imports = {}; + this.objects = {}; + this.level = Comp.array.create(100,1); + this.level[-1]=1; + this.matrix = undefined; + + this.inspect = {root:'/',data:{},filter:{array:true,string:true,number:true,boolean:true,object:true}}; + this.simu = none; + this.simuPhy = none; + + this.messages = []; + // Simulation world window corner coordinates (normalized/zoom=1) + this.window = { + x:0, + y:0, + w:0, + h:0, + mode:'pan' + } + this.message=function (msg,type) { + self.webix.message({text:msg,type:type||'Info',expire:5000}) + }; + + // Statistical logging (one row for each simualtion step) + this.logging = false; + this.logTable = []; + + this.options = { + verbose:0, + select:{agent:1,node:1,link:1,port:1,resource:0,patch:0,physics:0}, + display:{agent:1,node:1,link:1,port:1,resource:1,patch:1,world:1,flag:1,label:1,signal:1, + lazy:0}, + message:{error:1,warning:0}, + numbering:{ + simulation:function () {return ''}, + simulationPhy:function () {return ''}, + plot:function () {return ''} + }, + plot:{ + width:600, + height:400, + margin:10, + styles:Sejam2Plot.plot_styles + }, + simulation:{ + fastcopy:true, // JAM agent process copy/fork/migrate mode + verbose:false, // More SEJAM simulator messages + TMO:1000000 // JAM Node Cache Timeout [gone,signals] in ms + }, + log: { + node:true, + agent:true, + parent:false, + pid:false, // agent process id! + host:false, // host id (os pid) + time:false, + class:true + }, + flag:{fontSize:14}, + } +} + +gui.prototype.addFlags = function (options) { + var p,o,id; + if (!options) options={agent:false,node:true,resource:true,fontSize:this.options.flag.fontSize,color:'red'}; + for(p in this.objects) { + o=this.objects[p]; + if (!o) continue; + id=o.id.replace(/[^\[]+\[([^\]]+)\]/,'$1'); + if (options.node && Comp.string.startsWith(o.id,'node') && !this.objects['label['+id+']']) { + this.objects['flag['+id+']'] = { + visual:{ + x:o.visual.x, + y:o.visual.y-5-options.fontSize, + shape:'text', + fontSize:options.fontSize, + color:options.color, + text:o.id, + },id:'flag['+id+']'}; + // this.drawObject('flag['+id+']'); + } + if (options.resource && Comp.string.startsWith(o.id,'resource')) { + this.objects['flag['+id+']'] = { + visual:{ + x:o.visual.x, + y:o.visual.y-5-options.fontSize, + shape:'text', + fontSize:options.fontSize, + color:options.color, + text:o.id, + },id:'flag['+id+']'}; + // this.drawObject('flag['+id+']'); + } + } + this.clearWorld(); + this.drawWorld(); +} + +/** Auto Layout - it is magic due to width/height widget inconstitencies! + * + */ +gui.prototype.autoLayout = function () { + var self=this, + screen=this.nwgui.Window.get(), + offset=this.toolbar.getNode().offsetHeight, + height=screen.height-(this.nw>"0.11.0"?15:offset), // TODO - nw.js toolbar height + width=screen.width+(this.nw>"0.11.0"?8:0), + margin=2, + h=0,_w=0,w=0,w1=0,w2=0,h2=0; + if (self.toolbar.locked) return; + + if (!this.logWin.isVisible() && + !this.worldWin.isVisible() && + !this.simulationWin.isVisible() && + !this.inspectorWin.isVisible() && + !this.editorWin.isVisible()) { + this.logWin.show(); + this.worldWin.show(); + this.simulationWin.show(); + this.inspectorWin.show(); + } + + if (this.logWin.isVisible()) { + // Align bottom, full width + h=this.logWin.getNode().offsetHeight; + this.logWin.define('width',width-2*margin-10); + this.logWin.define('height',h-2); + this.logWin.define('left',margin); + this.logWin.define('top',height-margin-h+14); + this.logWin.resize(); + } + + if (this.simulationWin.isVisible()) { + h2=this.simulationWin.getNode().offsetHeight; + } + + if (this.inspectorWin.isVisible()) { + w2=this.inspectorWin.getNode().offsetWidth +2*margin+10; + } else if (this.editorWin.isVisible()) { + w2=this.editorWin.getNode().offsetWidth +2*margin+10; + } else if (this.chatWin.isVisible()) { + w2=this.chatWin.getNode().offsetWidth +2*margin+10; + } + + if (this.physicalWin.isVisible() && this.worldWin.isVisible()) { + var _w; + if (w2==0) _w=width-2*margin-8; else _w=width-w2; + w1=_w/2; + } + + if (this.worldWin.isVisible()) { + // Align top, right + _w=this.worldWin.getNode().offsetWidth; + if (w2==0) w=width-2*margin-8; else w=width-w2; + this.worldWin.define('width',w-2-w1); + this.worldWin.define('height',height-h-h2-offset); + this.worldWin.define('left',width-w-margin-8); + this.worldWin.define('top',offset+margin+2); + this.worldWin.resize(); + + } else if (w2==0) w=width-2*margin-8; else w=width-w2; + + if (this.physicalWin.isVisible() && this.worldWin.isVisible()) { + this.physicalWin.define('width',w1-2); + this.physicalWin.define('height',height-h-h2-offset); + this.physicalWin.define('left',width-w1-margin-8); + this.physicalWin.define('top',offset+margin+2); + this.physicalWin.resize(); + } + + if (this.simulationWin.isVisible()) { + if (w>0) this.simulationWin.define('left',width-w-margin-8); + if (h>h2) this.simulationWin.define('top',height-h-h2+8); + this.simulationWin.define('width',w-2); + this.simulationWin.resize(); + } + + if (this.inspectorWin.isVisible()) { + // Align top, left + this.inspectorWin.define('width',w2 -2*margin-12); + this.inspectorWin.define('height',height-h-offset+1); + this.inspectorWin.define('left',margin); + this.inspectorWin.define('top',offset+margin+2); + this.inspectorWin.resize(); + + } else if (this.editorWin.isVisible()) { + // Align top, left + this.editorWin.define('width',w2-2*margin-12); + this.editorWin.define('height',height-h-offset); + this.editorWin.define('left',margin); + this.editorWin.define('top',offset+margin+2); + this.editorWin.resize(); + + } else if (this.chatWin.isVisible()) { + // Align top, left + this.chatWin.define('width',w2-2*margin-12); + this.chatWin.define('height',height-h-offset); + this.chatWin.define('left',margin); + this.chatWin.define('top',offset+margin+2); + this.chatWin.resize(); + + } +} + + +/** Change CSS + * + */ +gui.prototype.changeCSS = function(theClass,element,value) { + var cssRules; + + for (var S = 0; S < document.styleSheets.length; S++) { + try { + document.styleSheets[S].insertRule(theClass+' { '+element+': '+value+'; }', + document.styleSheets[S][cssRules].length); + } catch(err) { + try{ + document.styleSheets[S].addRule(theClass,element+': '+value+';'); + } catch(err){ + try{ + if (document.styleSheets[S]['rules']) { + cssRules = 'rules'; + } else if (document.styleSheets[S]['cssRules']) { + cssRules = 'cssRules'; + } else { + //no rules found... browser unknown + } + + for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) { + if (document.styleSheets[S][cssRules][R].selectorText == theClass) { + if(document.styleSheets[S][cssRules][R].style[element]){ + document.styleSheets[S][cssRules][R].style[element] = value; + break; + } + } + } + } catch (err){} + } + } + } +} + +/** Change the visual of a visual object + * + */ +gui.prototype.changeObject = function (id,visual) { + var self=this,shape=this.worldWin.shapes[id], + zoom=this.worldWin.zoom, + off=this.worldWin.offset, + obj=this.objects[id], + redraw=false, + p; + if (!this.worldWin.container || !obj || !shape) return; + for(p in visual) { + if (p=='fill') { + if (Comp.obj.isNumber(visual.fill.color)) { + var c=Comp.printf.sprintf('%x',((visual.fill.color*255)|0)); + if (c.length==1) c='0'+c; + visual.fill.color='#'+c+c+c; + // Grey code + } else if (Comp.obj.isObject(visual.fill.color)) { + var c=Comp.printf.sprintf('%x',((visual.fill.color.value*255)|0)); + if (c.length==1) c='0'+c; + switch (visual.fill.color.color) { + case 'red': visual.fill.color='#'+c+'00'+'00'; break; + case 'green': visual.fill.color='#'+'00'+c+'00'; break; + case 'blue': visual.fill.color='#'+'00'+'00'+c; break; + default: + visual.fill.color='#'+c+c+c; + } + // Color gradient TODO + } + if (shape.fill) shape.fill(visual.fill.color,visual.fill.opacity||0.5); + } + if (p=='shape' && visual.shape!=obj.visual.shape) redraw=true; + obj.visual[p]=visual[p]; + } + if (redraw) { + this.worldWin.shapes[id].remove(); + this.worldWin.shapes[id]=undefined; + this.drawObject(id); + } +} +/** Return the class of a simulation object: + * {'node','link','port','agent','resource','patch','world','flag'} + */ +gui.prototype.classObject = function (id) { + if (id.indexOf('agent')==0) return 'agent'; + if (id.indexOf('world')==0 || id=="node[world]") return 'world'; + if (id.indexOf('node')==0) return 'node'; + if (id.indexOf('link')==0) return 'link'; + if (id.indexOf('port')==0) return 'port'; + if (id.indexOf('resource')==0) return 'resource'; + if (id.indexOf('patch')==0) return 'patch'; + if (id.indexOf('flag')==0) return 'flag'; + if (id.indexOf('label')==0) return 'label'; + if (id.indexOf('signal')==0) return 'signal'; +} + +/** Clear a logging window + * + */ +gui.prototype.clear = function (win) { + var self=this; + var view = this.UI(win); + var log = this.UI(win+'LogText'); + var scroll = view.getBody(); + var textview = this.UI(win+'LogTextView'); + var text = textview.getValue(); + text = ''; + textview.setValue(text); + if (!textview.update) textview.update=setTimeout(function () { + textview.update=undefined; + self.update(win); + },100); +} + +/** Clean the graphical world from outdated objects (visual.timeout <= 0). + * + */ +gui.prototype.cleanWorld = function () { + var p,pending=0; + // this.log('[GUI] Cleaning world ...'); + if (this.worldWin.container) this.worldWin.container.suspend(); + for (p in this.objects) { + obj=this.objects[p]; + if (!obj || !obj.visual) continue; + if (obj.visual.timeout) { + pending++; + obj.visual.timeout--; + if (obj.visual.timeout <= 0) { + if (this.worldWin.shapes[p]) + this.worldWin.shapes[p].remove(); + this.worldWin.shapes[p]=undefined; + this.objects[p]=undefined; + } + } + } + if (this.worldWin.container) this.worldWin.container.resume(); + return pending; +} + +/** Clear the graphical world. + * + */ +gui.prototype.clearWorld = function () { + var p,_shapes; + this.log('[GUI] Clearing world ...'); + this.window={x0:Number.MAX_SAFE_INTEGER,y0:Number.MAX_SAFE_INTEGER,x1:0,y1:0,mode:this.window.mode}; + if (this.worldWin.container) this.worldWin.container.suspend(); + for (p in this.objects) { + obj=this.objects[p]; + if (this.worldWin.shapes[p]) { + // 1. remove shapes from stage + this.worldWin.shapes[p].removeAllListeners(); + this.worldWin.shapes[p].remove(); + // this.worldWin.shapes[p]=undefined; + } + } + // this.objects={}; + _shapes=this.worldWin.shapes; + this.worldWin.shapes={}; + if (this.worldWin.container) this.worldWin.container.resume(); + // 2. finally dispose shapes after some delay (unlink it from acgraph/stage context) + setTimeout(function () { + for (var p in _shapes) { + _shapes[p].dispose(); + } + _shapes=undefined; + },10); +} + +// Create simulation from model; external API +gui.prototype.createSimulation = function () { + var self=this; + self.clear('logWin'); + self.clear('msgWin'); + self.logTable = []; + self.messages=[]; + self.objects={}; + self.createWorld(true); + self.clearWorld(); + self.drawWorld(); + self.UI('simulationWinButErase').enable(); + self.UI('simulationWinButStep').enable(); + self.UI('simulationWinButPlay').enable(); + self.UI('simulationWinButStop').disable(); + self.UI('simulationWinButCreate').disable(); +} + +/** Create the sensors simulation world + * + */ +gui.prototype.createSimuSens = function () { + var self=this; + if (!this.sensorsWin.isVisible()) + this.sensorsWin.show(); + + if (this.simuSens) return; + + this.log('[GUI] Creating Sensors world ...'); + + this.simuSens = simuSens.Sensors( + { + width:this.sensorsWin.getNode().offsetWidth-26, + height:this.sensorsWin.getNode().offsetHeight-70, + UI:this.UI, + model:this.model, + log:this.log + }); + this.sensorsWin.gui=this.simuSens; + this.UI('sensorsWinButCreate').disable(); + this.UI('sensorsWinButDestroy').enable(); + this.UI('sensorsWinButRun').enable(); + this.UI('sensorsWinButStep').enable(); + this.UI('sensorsWinButStop').disable(); +} + +/** Create the physical simulation world + * + */ +gui.prototype.createSimuPhy = function () { + var self=this; + + if (!this.physicalWin.isVisible()) + this.physicalWin.show(); + + if (this.simuPhy) return; + + this.log('[GUI] Creating PHY world ...'); + + this.simuPhy = simuPhy.Simu({width:this.physicalWin.getNode().offsetWidth-26, + height:this.physicalWin.getNode().offsetHeight-70, + CANNON:this.CANNON, + UI:this.UI, + model:this.model, + log:this.log, + display:this.options.display}); + this.physicalWin.gui=this.simuPhy.gui; + if (this.simu) this.simu.simuPhy = this.simuPhy; // Attach simuPHY to simuWEB + this.simuPhy.init(); + if (this.model && this.model.physics && this.model.physics.scenes) { + for(var p in self.model.physics.scenes) { + var f=this.model.physics.scenes[p]; + if (Comp.obj.isString(f)) { + try { + eval('f='+f); + } catch (e) { + this.log('[GUI] Error in '+p+': '+e); + continue; + } + } + self.simuPhy.addScene(p,f,{}); + } + } + this.simuPhy.gui.animate1(); + + this.UI('physicalWinButCreate').disable(); + this.UI('physicalWinButDestroy').enable(); + this.UI('physicalWinButRun').enable(); + this.UI('physicalWinButStep').enable(); + this.UI('physicalWinButStop').disable(); + + return this.simuPhy; +} + +/** Create MAS simulation world and draw the world. + */ +gui.prototype.createWorld = function (nodraw) { + var self=this,c; + if (this.simu) this.destroyWorld(); + if (!this.model || Comp.obj.isEmpty(this.model)) return; + if (this.model.options && this.model.options.verbose != undefined) this.options.verbose=this.model.options.verbose; + this.log('[GUI] Creating MAS world'+(this.simuPhy?' with simuPHY':'')+' (verbosity '+this.options.verbose+') ...'); + this.simu=Aios.Simu.Simu({ + CANNON:this.CANNON, + log:this.log, + msg:this.msg, + gui:this, + simuPhy:this.simuPhy, + nolimits:true, // No AIOS agent proecss checkpointing and resource control! + fastcopy:this.options.simulation.fastcopy, // Dirty (fast) JAM agent code & signal copy? + TMO:this.options.simulation.TMO, // JAM Node cache timeout + format:this.options.log, + verbose:this.options.verbose // Additional SEJAM messages + }); + this.simu.init(this.model); + if (!nodraw) this.drawWorld(); + this.worldname=this.simu.world.id; + this.UI('myTopLabel').setValue(this.worldname); +} + + +/** Delete inspector tree + */ +gui.prototype.deleteTree = function(name_s) { + var tree = this.UI('inspectorTree'), + root,n,i; + + if (tree._roots) { + for (var p in tree._roots) { + p=tree._roots[p]; + tree.remove(p); + } + } else tree.remove('root'); + tree._roots=undefined; + if (!name_s||Comp.obj.isString(name_s)) { + root={ id:"root", open:true, value:name_s||'/' } + tree.add(root); + } else { + // Multiple objects + tree._roots=[]; + for(i in name_s) { + n=name_s[i]; + tree._roots.push('root@@'+n); + root={ id:'root@@'+n, open:true, value:n } + tree.add(root); + } + } +} + + +/** Destroy one visual object + * + */ +gui.prototype.destroyObject = function (id) { + var self=this,shape, + obj=this.objects[id]; + if (!obj && this.options.verbose>1) this.log('destroyObject: Unknown object '+id); + if (obj) obj.obj=undefined; + delete this.objects[id]; + if (this.worldWin.shapes[id]) { + this.worldWin.shapes[id].removeAllListeners(); + this.worldWin.shapes[id].remove(); + delete this.worldWin.shapes[id]; + } +} + +/** Destroy sensors simulation wolrd + * + */ + +gui.prototype.destroySimuSens = function () { + + this.log('[GUI] Destroying Sensors world ...'); + this.simuSens.destroy(); + this.simuSens = none; + this.UI('sensorsWinButCreate').enable(); + this.UI('sensorsWinButDestroy').disable(); + this.sensorsWin.gui=none; + this.UI('sensorsWinButRun').disable(); + this.UI('sensorsWinButStep').disable(); + this.UI('sensorsWinButStop').disable(); +} + +/** Destroy physical simulation wolrd + * + */ + +gui.prototype.destroySimuPhy = function () { + + this.log('[GUI] Destroying Physical world ...'); + this.simuPhy.destroy(); + this.simuPhy = none; + this.UI('physicalWinButCreate').enable(); + this.UI('physicalWinButDestroy').disable(); + this.physicalWin.gui=none; + this.UI('physicalWinButRun').disable(); + this.UI('physicalWinButStep').disable(); + this.UI('physicalWinButStop').disable(); +} + + +/** Destroy MAS simulation world and clear graphical world. + * + */ +gui.prototype.destroyWorld = function () { + this.clearWorld(); + if (this.simu) { + this.log('[GUI] Destroying old simulation '+this.simu.world.id+' ...'); + if (this.simu) this.simu.destroy(); + this.simu=none; + } + this.objects={}; + this.worldname='No World!'; + this.UI('myTopLabel').setValue(this.worldname); +} + +/** Draw and create one visual object + * + */ +gui.prototype.drawObject = function (id) { + var self=this,shape=this.worldWin.shapes[id], + objClass=this.classObject(id), + zoom=this.worldWin.zoom, + off=this.worldWin.offset, + obj=this.objects[id], + level=(obj && obj.visual && obj.visual.level!=undefined)?obj.visual.level:-1, + x0,x1,x2,y0,y1,y2, + dx=0,dy=0; + + if (!this.worldWin.container || !obj || shape || !this.level[level] || !this.options.display[objClass]) return; + + function makeListener(shape,id) { + if (id != "world-anchor") shape.listen("click", function (e) {self.listenObject(id,e)}); + } + this.window.x0=Math.min(this.window.x0,obj.visual.x); + this.window.y0=Math.min(this.window.y0,obj.visual.y); + if (obj.visual.w) this.window.x1=Math.max(this.window.x1,obj.visual.x+obj.visual.w); + if (obj.visual.h) this.window.y1=Math.max(this.window.y1,obj.visual.y+obj.visual.h); + + switch (obj.visual.shape) { + case 'rect': + shape=this.worldWin.container.rect((obj.visual.x+off.x)*zoom, + (obj.visual.y+off.y)*zoom, + obj.visual.w*zoom, obj.visual.h*zoom); + if (obj.visual.fill) shape.fill(obj.visual.fill.color,obj.visual.fill.opacity||0.5); + if (obj.visual.line) shape.stroke(obj.visual.line.color||'black',checkOption(obj.visual.line.width,1)); + if (obj.visual.line && obj.visual.line.width!=undefined) shape.strokeThickness(obj.visual.line.width); + makeListener(shape,obj.id); + if (obj.visual.pattern) { + var pattern = this.worldWin.container.pattern( + new this.acgraph.math.Rect(0,0,obj.visual.pattern.w*zoom,obj.visual.pattern.h*zoom)); + pattern.rect(0, 0,obj.visual.pattern.w*zoom,obj.visual.pattern.h*zoom).fill("none") + .stroke(obj.visual.pattern.color||"1 blue 0.9"); + shape.fill(pattern); + } + this.worldWin.shapes[obj.id]=shape; + break; + case 'circle': + if (obj.visual.align == 'center') dx=obj.visual.w/2,dy=obj.visual.h/2; + shape=this.worldWin.container.ellipse((obj.visual.x+off.x+dx)*zoom, + (obj.visual.y+off.y+dy)*zoom, + obj.visual.w*zoom/2, obj.visual.h*zoom/2); + if (obj.visual.fill) shape.fill(obj.visual.fill.color,obj.visual.fill.opacity||0.5); + if (obj.visual.line) shape.stroke(obj.visual.line.color||'black',checkOption(obj.visual.line.width,1)); + if (obj.visual.line && obj.visual.line.width!=undefined) shape.strokeThickness(obj.visual.line.width); + makeListener(shape,obj.id); + this.worldWin.shapes[obj.id]=shape; + break; + case 'triangle': + x0=(obj.visual.x+off.x)*zoom; + y0=(obj.visual.y+obj.visual.h*7/8+off.y)*zoom; + x1=(obj.visual.x+obj.visual.w+off.x)*zoom; + x2=(obj.visual.x+obj.visual.w/2+off.x)*zoom; + y2=(obj.visual.y-obj.visual.h/8+off.y)*zoom; + + shape=this.worldWin.container.path(); + shape.moveTo(x0,y0). + lineTo(x1,y0). + lineTo(x2,y2). + lineTo(x0,y0); + + if (obj.visual.fill) shape.fill(obj.visual.fill.color,obj.visual.fill.opacity||0.5); + if (obj.visual.line) shape.stroke(obj.visual.line.color||'black',checkOption(obj.visual.line.width,1)); + if (obj.visual.line && obj.visual.line.width!=undefined) shape.strokeThickness(obj.visual.line.width); + makeListener(shape,obj.id); + this.worldWin.shapes[obj.id]=shape; + break; + case 'text': + shape=this.worldWin.container.text((obj.visual.x+off.x)*zoom,(obj.visual.y+off.y)*zoom,obj.visual.text); + if (obj.visual.fontSize) shape.fontSize(obj.visual.fontSize*zoom+'px'); + if (obj.visual.color) shape.color(obj.visual.color); + this.worldWin.shapes[obj.id]=shape; + break; + case 'icon': + src='icons/'+obj.visual.icon+'.svg'; + shape=this.worldWin.container.image(src, + (obj.visual.x+off.x)*zoom, (obj.visual.y+off.y)*zoom, + obj.visual.w*zoom, obj.visual.h*zoom); + // if (obj.visual.fill) shape.fill(obj.visual.fill.color,obj.visual.fill.opacity||0.5); + makeListener(shape,obj.id); + this.worldWin.shapes[obj.id]=shape; + break; + } +} + +/** Draw the simulation world with current settings. + * + */ + +gui.prototype.drawWorld = function () { + var p,self=this, + objClass; + + if (!self.worldWin.isVisible()) return; + this.log('[GUI] Drawing world ...'); + if (!this.worldWin.container) { + // Install mouse pan and region zoom handler + this.worldWin.container = this.acgraph.create('worldGraphContainer'); + // this.worldWin.layer = this.acgraph.layer(); this.worldWin.layer.parent(container); ?? + this.worldWin.container._mouse = undefined; + this.worldWin.container._mouse_line = undefined; + document.getElementById("worldGraphContainer").addEventListener("mousedown", function(e){ + var m={x:e.clientX,y:e.clientY}; + if (self.worldWin.container._mouse_shape) { + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape=undefined; + } + self.worldWin.container._mouse = {x:m.x,y:m.y}; + switch (self.window.mode) { + case 'pan': + self.worldWin.container._mouse_shape = self.worldWin.container.path(); + self.worldWin.container._mouse_shape.moveTo(m.x-self.worldWin.getNode().offsetLeft-10, + m.y-self.worldWin.getNode().offsetTop-60); + // document.getElementById("worldGraphContainer").style.cursor='move'; + break; + case 'zoom': + case 'select': + self.worldWin.container._mouse_shape = self.worldWin.container.rect( + m.x-self.worldWin.getNode().offsetLeft-10, + m.y-self.worldWin.getNode().offsetTop-60, + 1,1); + //b document.getElementById("worldGraphContainer").style.cursor='s-resize'; + break; + } + + }); + document.getElementById("worldGraphContainer").addEventListener("mousemove", function(e){ + var m={x:e.clientX,y:e.clientY}; + if (self.worldWin.container._mouse_shape && + (Math.abs(m.x-self.worldWin.container._mouse.x)>5 || + Math.abs(m.y-self.worldWin.container._mouse.y)>5)) { + switch (self.window.mode) { + case 'pan': + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape = self.worldWin.container.path(); + self.worldWin.container._mouse_shape.moveTo(self.worldWin.container._mouse.x-self.worldWin.getNode().offsetLeft-10, + self.worldWin.container._mouse.y-self.worldWin.getNode().offsetTop-60); + self.worldWin.container._mouse_shape.lineTo(m.x-self.worldWin.getNode().offsetLeft-10, + m.y-self.worldWin.getNode().offsetTop-60); + break; + case 'zoom': + case 'select': + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape = self.worldWin.container.rect( + self.worldWin.container._mouse.x-self.worldWin.getNode().offsetLeft-10, + self.worldWin.container._mouse.y-self.worldWin.getNode().offsetTop-60, + (m.x-self.worldWin.container._mouse.x), + (m.y-self.worldWin.container._mouse.y)); + + break; + } + } + }); + document.getElementById("worldGraphContainer").addEventListener("mouseup", function(e){ + var x0,y0,dx,dy,dw,dh,zw,zh,m={x:e.clientX,y:e.clientY}; + if (!self.worldWin.container._mouse) return; + switch (self.window.mode) { + case 'pan': + if (Math.abs(m.x-self.worldWin.container._mouse.x)>5 || + Math.abs(m.y-self.worldWin.container._mouse.y)>5) { + var dx=((m.x-self.worldWin.container._mouse.x)/self.worldWin.zoom)|0, + dy=((m.y-self.worldWin.container._mouse.y)/self.worldWin.zoom)|0; + self.worldWin.offset.x += dx; + self.worldWin.offset.y += dy; + for(var o in self.objects) { + self.moveShape(o,dx,dy); + } + } + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape=undefined; + break; + case 'zoom': + if ((m.x-self.worldWin.container._mouse.x)>5 || + (m.y-self.worldWin.container._mouse.y)>5) { + dw=Math.abs(m.x-self.worldWin.container._mouse.x)/self.worldWin.zoom; + dh=Math.abs(m.y-self.worldWin.container._mouse.y)/self.worldWin.zoom; + zw=(self.worldWin.getNode().offsetWidth-35)/(dw); + zh=(self.worldWin.getNode().offsetHeight-70)/(dh); + + dx=-(self.worldWin.container._mouse.x-self.worldWin.getNode().offsetLeft-30)/self.worldWin.zoom|0+10; + dy=-(self.worldWin.container._mouse.y-self.worldWin.getNode().offsetTop-50)/self.worldWin.zoom|0+10; + + dx += self.worldWin.offset.x; + dy += self.worldWin.offset.y; + + self.worldWin.offset = {x:dx,y:dy}; + self.worldWin.zoom=Math.min(zw,zh); + self.clearWorld(); + self.drawWorld(); + } + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape=undefined; + self.UI('worldWinButZoomRegion').enable(); + break; + case 'select': + if ((m.x-self.worldWin.container._mouse.x)>5 || + (m.y-self.worldWin.container._mouse.y)>5) { + x0 = (self.worldWin.container._mouse.x-self.worldWin.getNode().offsetLeft-0)/self.worldWin.zoom; + y0 = (self.worldWin.container._mouse.y-self.worldWin.getNode().offsetTop-50)/self.worldWin.zoom; + x0 -= self.worldWin.offset.x; + y0 -= self.worldWin.offset.y; + dw=Math.abs(m.x-self.worldWin.container._mouse.x)/self.worldWin.zoom; + dh=Math.abs(m.y-self.worldWin.container._mouse.y)/self.worldWin.zoom; + // self.log([x0,y0,dw,dh]); + self.selectRegion(x0,y0,dw,dh,function (id) {return id.indexOf('node')==0||id.indexOf('agent')==0}); + } + self.worldWin.container._mouse_shape.remove(); + self.worldWin.container._mouse_shape=undefined; + self.UI('worldWinButSelectRegion').enable(); + break; + + } + self.worldWin.container._mouse=undefined; + self.window.mode='pan'; + document.getElementById("worldGraphContainer").style.cursor='default'; + // self.log('click '+e.type+' '+e.clientX+','+e.clientY); + }); + } + this.window={x0:Number.MAX_SAFE_INTEGER,y0:Number.MAX_SAFE_INTEGER,x1:0,y1:0,mode:this.window.mode}; + this.worldWin.container.suspend(); + for (p in this.objects) { + this.drawObject(p); + } + this.worldWin.container.resume(); +} + + + +/** Print error message to logging window + * Returns a window-specific print function. + */ +gui.prototype.errToWin = function (win) { + var self=this; + return function(data) { + var view = self.UI(win); + var textview = self.UI(win+'LogTextView'); + var text = textview.getValue(); + if (self.options.message.error) self.message(data); + text = text + 'X '+ data + '\n'; + textview.setValue(text); + } +} + +/** Find objects based on class and regular expression pattern (string) + * + */ +gui.prototype.findObjects = function (classId,pattern) { + var id, regex=RegExp(pattern), + objs={}; + for(id in this.objects) { + if (id.indexOf(classId)==0 && id.match(regex)) objs[id]=this.objects[id]; + } + return objs; +} + +gui.prototype.getObject = function (id,visual) { + return this.objects[id]; +} +/** A shape/object listener (attached to graphics elements) + * + */ +gui.prototype.listenObject = function (id,e) { + var self=this, + obj=this.objects[id]; + + function selectable(id) { + if (Comp.string.startsWith(id,'agent') && !self.options.select.agent) return false; + if (Comp.string.startsWith(id,'node') && !self.options.select.node) return false; + if (Comp.string.startsWith(id,'link') && !self.options.select.link) return false; + if (Comp.string.startsWith(id,'port') && !self.options.select.port) return false; + if (Comp.string.startsWith(id,'resource') && !self.options.select.resource) return false; + if (Comp.string.startsWith(id,'patch') && !self.options.select.patch) return false; + return true + } + + function overlap(id,v) { + var objs=[],id2; + // Return all overlapping shapes + for (id2 in self.objects) { + if (self.objects[id2]==undefined) continue; + var v2=self.objects[id2].visual; + if (id2==id || !self.level[v2.level]) continue; + + if (Comp.string.startsWith(id,'agent') && + !Comp.string.startsWith(id2,'agent')) continue; + else if (Comp.string.startsWith(id,'node') && + !Comp.string.startsWith(id2,'node')) continue; + else if (Comp.string.startsWith(id,'link') && + !Comp.string.startsWith(id2,'link')) continue; + + if (!selectable(id2)) continue; + + if (v.shape=='circle' && v2.shape=='circle') { + var r0=(v.w+v.h)/4, + r1=(v2.w+v2.h)/4, + c=sq(v.x-v2.x)+sq(v.y-v2.y); + if (!(c <= sq(r0+r1))) continue; + } else { + // If one rectangle is on left side of other + if (v.x > (v2.x+v2.w) || v2.x > (v.x+v.w)) continue; + // If one rectangle is above other + if (v.y > (v2.y+v2.h) || v2.y > (v.y+v.h)) continue; + } + objs.push(id2); + }; + return objs; + } + function listen(id,e) { + var ovl=overlap(id,obj.visual),objs={},id2,p,node; + // self.log('Select: '+id+' ['+ovl.length+'] '+ selectable(id)); + + if (!self.inspectorWin.locked && selectable(id)) { + if (ovl.length==0) { + self.inspect.data=self.objects[id].obj; + self.deleteTree(id); + self.makeTree(self.inspect.data,'root'); + self.UI('inspectorTree').close('root'); + } else { + objs[id]=self.objects[id].obj; + for(var id2 in ovl) { + id2=ovl[id2]; + objs[id2]=self.objects[id2].obj; + } + self.inspect.data=objs; + Comp.array.push(ovl,id); + self.deleteTree(ovl); + for(p in objs) { + self.makeTree({},'root@@'+p); + self.UI('inspectorTree').close('root@@'+p); + node = self.UI('inspectorTree').getItem('root@@'+p); + node._data=objs[p]; + } + } + } + if (Comp.string.startsWith(id,'node')) { + id2=id.replace(/node\[([^\]]+)\]/,'$1'); + node = self.simu.world.getNode(id2); + if (node && node.position) { + if (node.position.gps) + self.UI('worldWinInfo').setValue(Comp.printf.sprintf('%s %2.6f° %2.6f° %4.0fm', + node.id, + node.position.gps.latitude, + node.position.gps.longitude, + node.position.gps.height)); + else if (node.position.x != undefined && node.position.y != undefined) + self.UI('worldWinInfo').setValue(Comp.printf.sprintf(node.position.z!=undefined?'%s [%4.0f,%4.0f,%4.0f]':'%s [%4.0f,%4.0f]', + node.id, + node.position.x, + node.position.y, + node.position.z)); + } else self.UI('worldWinInfo').setValue(''); + if (self.options.select.physics && self.simuPhy) { + var tokens = id2.split(','); + // Try to find connected physical object. e.g., masses. + self.simuPhy.select(tokens.map(function (s) {return Number(s)})); + } + } else { + self.UI('worldWinInfo').setValue(id); + if (self.options.select.physics && self.simuPhy) + self.simuPhy.unselect(); + } + } + listen(id,e); +} + +gui.prototype.lockLayout = function () { + this.UI('topWinLock').define('icon','lock'); + this.UI('topWinLock').refresh(); + this.toolbar.locked=true; + this.inspectorWin.define('move',false); + this.msgWin.define('move',false); + this.logWin.define('move',false); + this.simulationWin.define('move',false); + this.worldWin.define('move',false); +} + +/** Print logging message to logging window + * Returns a window-specific print function. + */ +gui.prototype.logToWin = function (win) { + var self=this; + function wrap(data) { + function contains(it) { return data.indexOf(it) != -1; }; + if (contains('Warning:')) return '! '+data + ''; + else if (contains('Error:')) { if (self.options.message.error) self.message(data); return 'X '+data + ''} + else return ' '+data; + } + return function(data) { + if(data==undefined) data='undefined'; + if(typeof data != 'string') data=JSON.stringify(data); + var view = self.UI(win); + // var log = self.UI(win+'LogText'); + var textview = self.UI(win+'LogTextView'); + // var scroll = view.getBody(); + /* + if (typeof log.logtext == 'undefined') log.logtext=''; + data=data.replace(/ /g,' ').replace(/\n/g,'
\n'); + log.logtext += wrap(data) + '
\n'; + log.removeView(win+'LogTextView'); + log.addView({template:''+log.logtext+'', autoheight:true, borderless:true, id:win+'LogTextView'}); + */ + var text = textview.getValue(); + text = text + wrap(data) +'\n'; + textview.setValue(text); + if (!textview.update) textview.update=setTimeout(function () { + textview.update=undefined; + self.update(win); + },100); + } +} + +/** Highlight a line (lineNumber) in the editor + * + */ +gui.prototype.highlightLine = function(editor,lineNumber) { + //Select editor loaded in the DOM + var myEditor = UI(editor).getEditor(); + if (!myEditor) return; + //Set line CSS class to the line number & affecting the background of the line with the css class of line-error + myEditor.setLineClass(lineNumber - 1, 'background', 'line-error'); + highlights[editor]=lineNumber; +} + +// Load simulation model from file; external API +gui.prototype.loadSimulation = function(file) { + var self=this; + // If file != null, use loadFile/fs + if (global.TARGET == "browser") { + function setup(text,filename) { + try { + self.filename=self.filesimu=filename; + self.source = text; + self.imports = {}; + self.model = self.parseModel(text); + if (self.model && self.model.name) + self.log('Loaded simulation model "'+self.model.name+'" ('+self.source.length+') from file '+self.filename); + else + self.log('Loading simulation model from file '+self.filename+' failed.'); + self.UI('sourceText').setValue(self.source); + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + self.editorWin._changed=false; + self.editorWin._active=self.filename; + self.inspect.root = 'model'; + self.inspect.data = self.model; + self.UI('sourceTextWinMenu').remove('root'); + files=[self.filename]; + for(p in self.imports) { + files.push(p); + } + self.UI('sourceTextWinMenu').add({ + id:'root', + value:self.filename, + submenu:files}); + } catch (e) { + self.log('Loading of simulation model from file '+self.filename+' failed: '+e.toString()); + } + } + if (!file) + loadScript("simulation.js",".js",function (text,filename) {setup(text,filename)}) + else { + setup(loadFile(file),file); + } + } else { + if (self.filename.indexOf('.js')<0) { + self.filename='simulation.js'; + self.UI('filedialogWinFormFile').setValue(self.filename); + } + var but = self.UI('filedialogWinAction'); + but.setValue('Load Model'); + but.refresh(); + self.openDir(self.workdir); + self.filedialogWin.show(); + } +} + +/** Make an inspector tree node + */ +gui.prototype.makeTree = function(element,root) { + var self=this, + tree = this.UI('inspectorTree'), + child,childid,i=1,p,v,isfun,name,pat; + + function filter(name,elem,type) { + var p; + if (name && name=='_update') return false; + if (!self.inspect.filter) return true; + if (type) return self.inspect.filter[type]; + type=typeof elem; + if (!self.inspect.filter[type]) return false; + if (self.inspect.filter.attributes) { + if (self.inspect.filter.attributes[name]) return true; + if (self.inspect.filter.attributes.patterns) + for(p in self.inspect.filter.attributes.patterns) { + if (self.inspect.filter.attributes.patterns[p].test(name)) return true; + } + return false; + } + return true; + } + + if (Comp.obj.isObject(element) || Comp.obj.isArray(element)) { + if (element && element != null && element._update) element._update(element); + for (var p in element) { + child=element[p]; + if (filter(p,child)) { + if (child==undefined) v=p+' = undefined'; + else if (Comp.obj.isFunction(child)) { + if (!filter(null,null,'function')) continue; + name = child.toString(); + v=p+' = '+Comp.string.sub(name,0,name.indexOf('{')); + } else if (!Comp.obj.isObject(child) && !Comp.obj.isArray(child)) { + if (!filter(null,null,'array')) continue; + if (Comp.obj.isString(child)) + v=p+' = "'+(child.length<20?child:(Comp.string.sub(child,0,20)+'..'))+'"'; + else + v=p+' = '+child.toString(); + } else if (Comp.obj.isEmpty(child)) + v = p+' = '+(Comp.obj.isArray(child)?'[]':'{}'); + else v=p; + + childid = root+'.'+i; i++; + + tree.add({ + id:childid, + open:false, + value:v, + _data:child + },i,root); + + if ((Comp.obj.isObject(child) || Comp.obj.isArray(child)) && + !Comp.obj.isEmpty(child)) { + tree.add({id:childid+'.0',value:'..'},0,childid); + } + } + } + } else if (element != undefined) { + name = element.toString(); + funpat = /function[\s0-9a-zA-Z_$]*\(/i; + isfun=Comp.obj.isFunction(element)||funpat.test(name); + if (isfun && filter(null,null,'function')) { + element=Comp.string.sub(name,0,name.indexOf('{')); + } + } else { + } +} + +/** Move one visual object (and optionally child objects) and the shapes + * relative to current (x,y) position (normalized coordinates independent of zoom/pan). + * + */ +gui.prototype.moveObject = function (oid,dx,dy,and,andmore) { + var shape=this.worldWin.shapes[oid], + zoom=this.worldWin.zoom, + obj=this.objects[oid], + level=(obj && obj.visual && obj.visual.level!=undefined)?obj.visual.level:-1, + node,pro,i,nid,lid; + if (obj && !this.level[level]) return; + if (!obj || !shape) {this.log('[GUI] moveObject: Unknown shape '+oid); return}; + obj.visual.x += dx; + obj.visual.y += dy; + shape.translate(dx*zoom,dy*zoom); + this.window.x0=Math.min(this.window.x0,obj.visual.x); + this.window.y0=Math.min(this.window.y0,obj.visual.y); + if (obj.visual.w) this.window.x1=Math.max(this.window.x1,obj.visual.x+obj.visual.w); + if (obj.visual.h) this.window.y1=Math.max(this.window.y1,obj.visual.y+obj.visual.h); + + if (and && and=='agent' && Comp.string.startsWith(oid,'node')) { + // Move all agents of this node, too + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + node=this.simu.world.getNode(nid); + for (i in node.processes.table) { + pro=node.processes.table[i]; + if (pro==undefined) continue; + this.moveObject('agent['+pro.agent.ac+':'+pro.agent.id+':'+node.id+']',dx,dy); + } + } + if (andmore && andmore=='port' && Comp.string.startsWith(oid,'node')) { + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + lid='port['+nid+']'; + if (this.objects[lid]) this.moveObject(lid,dx,dy); + } +} + +/** Move one visual object (and optionally child objects) and the shapes + * absolute to new (x,y) position (normalized coordinates independent of zoom/pan). + * + */ +gui.prototype.moveObjectTo = function (oid,x,y,and,andmore) { + var shape=this.worldWin.shapes[oid], + zoom=this.worldWin.zoom, + obj=this.objects[oid], + level=(obj && obj.visual && obj.visual.level!=undefined)?obj.visual.level:-1, + node,pro,i,nid,lid,dx,dy; + if (obj && !this.level[level]) return; + if (!obj || !shape) {this.log('[GUI] moveObjectTo: Unknown shape '+oid); return}; + dx=x-obj.visual.x; + dy=y-obj.visual.y; + obj.visual.x = x; + obj.visual.y = y; + shape.translate(dx*zoom,dy*zoom); + this.window.x0=Math.min(this.window.x0,obj.visual.x); + this.window.y0=Math.min(this.window.y0,obj.visual.y); + if (obj.visual.w) this.window.x1=Math.max(this.window.x1,obj.visual.x+obj.visual.w); + if (obj.visual.h) this.window.y1=Math.max(this.window.y1,obj.visual.y+obj.visual.h); + + if (and && and=='agent' && Comp.string.startsWith(oid,'node')) { + // Move all agents of this node, too + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + node=this.simu.world.getNode(nid); + for (i in node.processes.table) { + pro=node.processes.table[i]; + if (pro==undefined) continue; + // this.log(nid+'['+pro.agent.id+']'); + this.moveObject('agent['+pro.agent.ac+':'+pro.agent.id+':'+node.id+']',dx,dy); + } + } + if (andmore && andmore=='port' && Comp.string.startsWith(oid,'node')) { + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + lid='port['+nid+']'; + if (this.objects[lid]) this.moveObject(lid,dx,dy); + } +} + +/** Move the shapes of the object only! + * + */ +gui.prototype.moveShape = function (oid,dx,dy,and,andmore) { + var obj=this.objects[oid], + shape=this.worldWin.shapes[oid], + zoom=this.worldWin.zoom, + level=(obj && obj.visual && obj.visual.level!=undefined)?obj.visual.level:-1, + node,pro,i,nid,lid; + if (obj && !this.level[level]) return; + if (!shape) {this.log('[GUI] moveShape: Unknown shape '+oid); return}; + shape.translate(dx*zoom,dy*zoom); + + if (and && and=='agent' && Comp.string.startsWith(oid,'node')) { + // Move all agents of this node, too + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + node=this.simu.world.getNode(nid); + for (i in node.processes.table) { + pro=node.processes.table[i]; + if (pro==undefined) continue; + this.moveShape('agent['+pro.agent.ac+':'+pro.agent.id+':'+node.id+']',dx,dy); + } + } + if (andmore && andmore=='port' && Comp.string.startsWith(oid,'node')) { + nid=oid.replace(/node\[([^\]]+)\]/,'$1'); + lid='port['+nid+']'; + if (this.objects[lid]) this.moveShape(lid,dx,dy); + } +} + +/** File Explorer: Open and list directory + * + */ +gui.prototype.openDir = function (dir) { + var self = this; + var list = this.UI('filedialogWinList'); + this.lastdir=dir; + try { + var entry, + entries , + stats, + index=1; + try { entries=Fs.readdirSync(dir) } catch (e) { entries={} } + list.clearAll(); + list.add({ id:0, flag:'d', icon:'', + dir:dir, name:".."}); + function make(entry,mode) { + if (mode=='d') + return { id:index, flag:mode, + icon:'', + name:entry, + dir:dir + } + else + return { id:index, flag:mode, + icon:'', + name:entry, + dir:dir + } + } + entries = entries.sort(entries,function (a,b) {return a (v2.x+v2.w) || v2.x > (v.x+v.w)) continue; + // If one rectangle is above other + if (v.y > (v2.y+v2.h) || v2.y > (v.y+v.h)) continue; + } + objs.push(id2); + }; + return objs; +} + +/** Parse simulation model + * Expected format: { name, classes, world, .. } or model = { } + * Inside the simualtion model, the model attributes can be referenced with the variable model! + */ +gui.prototype.parseModel = function (text) { + var model, + prefix="", + more='', + error, + Model={name:'',classes:{},world:{}}, + self=this; + + // not available in browser mode + function open(filename) { + if (global.TARGET != "browser") { + var text=Io.read_file(self.workdir+'/'+filename); + self.imports[filename]=text; + if (text==undefined) + self.log('Error: Opening of file '+self.workdir+'/'+filename+' failed!'); + else return text; + } else { + var text = loadFile(filename); + return text; + } + } + try { + if (text.match(/^\s*{/)) prefix="model = "; + text = prefix+text; + try { + var ast = Esprima.parse(text, { tolerant: true, loc:true }); + if (ast.errors && ast.errors.length>0) error = ', '+ast.errors[0]; + } catch (e) { + if (e.lineNumber) error = e+', in line '+e.lineNumber; + } + if (error) {this.log(error); return;} + eval(text); +/* + if (res) { + model.name=res.name; + model.classes=res.classes; + model.world=res.world; + model.parameter=res.parameter; + } +*/ + return model; + } catch (e) { + this.log(e.name+(e.message?': '+e.message:'')+(more?more:'')); + } +} + +gui.prototype.removeFlags = function () { + var p,o; + for(p in this.objects) { + o=this.objects[p]; + if (!o) continue; + if (Comp.string.startsWith(o.id,'flag')) { + this.destroyObject(o.id); + } + } +} + +/** Reset some GUI forms/windows/fields + * + */ +gui.prototype.resetGui = function () { + if (this.worldWin.flags) { + this.UI('worldWinButFlags').define('icon','flag'); + this.UI('worldWinButFlags').refresh(); + this.worldWin.flags=false; + this.removeFlags(); + }; + if (this.inspectorWin.locked) { + this.UI('inspectorWinLock').define('icon','unlock'); + this.UI('inspectorWinLock').refresh(); + this.inspectorWin.locked=false; + } + this.UI('worldWinInfo').setValue(''); + this.UI('simulationWinInfoTime').setValue('Time: '+0); + this.UI('simulationWinInfoSteps').setValue('Step: '+0); + this.UI('simulationWinInfoAgents').setValue('Agents: '+0); + this.UI('simulationWinInfoNodes').setValue('Nodes: '+0); + this.inspect.data=this.model; + this.deleteTree(this.inspect.root); + this.makeTree(this.inspect.data,'root'); + this.UI('inspectorTree').close('root'); + this.UI('simulationWinButErase').disable(); + this.UI('simulationWinButStep').disable(); + this.UI('simulationWinButPlay').disable(); + this.UI('simulationWinButCreate').enable(); +} + +/** Save all model data form text editor and reload model. + * + */ +gui.prototype.saveAll = function () { + var self=this,file,text; + try { + self.log('Saving simulation model "'+(self.model?self.model.name:'')+'" ('+self.source.length+') to file '+self.filename); + Io.write_file(self.workdir+'/'+self.filename,self.source); + for(file in self.imports) { + text=self.imports[file]; + self.log('Saving imported module ('+text.length+') to file '+file); + Io.write_file(self.workdir+'/'+file,text); + } + text=Io.read_file(self.workdir+'/'+self.filename); + self.imports={}; + self.model = self.parseModel(text); + if (self.model && self.model.name) { + self.log('Updated simulation model "'+self.model.name+'" ('+self.source.length+') from file '+self.filename); + self.inspect.root = 'model'; + self.inspect.data = self.model; + } else + self.log('Updating simulation model from file '+self.filename+' failed.'); + } catch (e) { + self.log('Saving of simulation model to file '+self.filename+' failed: '+e.toString()); + } +} + +/** Select all objects in the region in inspector window. + * ROI coordinates: normalized! + * + */ + +gui.prototype.selectRegion = function (x0,y0,w,h,filter) { + var p,o,id,objs=[],p,node,ovl=[]; + if (!filter) filter=function (id) { return true}; + for(p in this.objects) { + o=this.objects[p]; + if (!o) continue; + switch (o.visual.shape) { + case 'circle': + case 'rect': + case 'icon': + if ((o.visual.x>=x0 && (o.visual.x+o.visual.w) <= (x0+w)) && + (o.visual.y>=y0 && (o.visual.y+o.visual.h) <= (y0+h)) && + filter(o.id)) ovl.push(o.id),objs.push(o); + break; + case 'triangle': + if ((o.visual.x>=x0 && (o.visual.x+o.visual.w) <= (x0+w)) && + (o.visual.y>=y0 && (o.visual.y+o.visual.h) <= (y0+h)) && + filter(o.id)) ovl.push(o.id),objs.push(o); + break; + } + } + // this.log(map(objs,function (o) {return o.id})); + if (!this.inspectorWin.locked) { + if (objs.length>0) { + this.inspect.data=objs; + this.deleteTree(ovl); + for(p in objs) { + o=objs[p]; + // this.log(o.id); + this.makeTree({},'root@@'+o.id); + this.UI('inspectorTree').close('root@@'+o.id); + node = this.UI('inspectorTree').getItem('root@@'+o.id); + node._data=o; + } + } + } +} +gui.prototype.setFontSize = function (fontsize) { + this.changeCSS('.input','font-size',fontsize+'px') + this.changeCSS('.normalInput','font-size',fontsize+'px') + this.changeCSS('.normalOutput','font-size',fontsize+'px') + this.changeCSS('.error','font-size',fontsize+'px') + this.changeCSS('.webix_inp_label','font-size',fontsize+'px') + this.changeCSS('.webix_inp_top_label','font-size',fontsize+'px') + this.changeCSS('.webix_label_right','font-size',fontsize+'px') + this.changeCSS('.webix_view','font-size',fontsize+'px') + this.changeCSS('.webix_el_box','font-size',fontsize+'px') + this.changeCSS('.webix_el_text','font-size',fontsize+'px') + this.changeCSS('.webix_el_label','font-size',fontsize+'px') + this.changeCSS('.webix_el_textarea','font-size',fontsize+'px !important') + this.changeCSS('textarea','font-size',fontsize+'px !important') + this.changeCSS('input','font-size',fontsize+'px !important') +} + +/** Show simulator and simulation world statistics + * + */ +gui.prototype.showStats = function () { + var mem = process.memoryUsage(), + stats={},n,p,c,proc,nodes=0; + + this.stat('Memory: residentSize: '+div(mem.rss,1024)+' heapUsed:'+div(mem.heapUsed,1024)); + if (this.simu) { + stats=this.simu.getStats(); + this.stat(Comp.printf.sprintf('Nodes: %8d',stats.nodes)); + this.stat(Comp.printf.sprintf('Agents: (%d)',stats.total)); + for (c in stats.agentsN) { + this.stat(Comp.printf.sprintf(' %10s : %6d (%d)',c,stats.agents[c]?stats.agents[c]:0,stats.agentsN[c])); + } + this.stat(Comp.printf.sprintf('[create:%8d migrate:%8d fork:%8d fast:%8d]', + stats.create,stats.migrate,stats.fork,stats.fastcopy)); + this.stat(Comp.printf.sprintf('Signals: %8d',stats.signal)); + this.stat(Comp.printf.sprintf('Communication: %8d Bytes|Obj.',stats.send)); + this.stat(Comp.printf.sprintf('CPU: %8d ms',stats.cpu)); + } +} + +// Start simulation (run); external API +gui.prototype.startSimulation = function (steps) { + var self=this; + if (!self.simu) return; + var delay = Number(self.UI('simulationWinFormDelay').getValue()); + self.simu.setDelay(delay); + self.simu.start(steps||100000); +} + +gui.prototype.unlockLayout = function () { + this.UI('topWinLock').define('icon','unlock'); + this.UI('topWinLock').refresh(); + this.toolbar.locked=false; + this.inspectorWin.define('move',true); + this.msgWin.define('move',true); + this.logWin.define('move',true); + this.simulationWin.define('move',true); + this.worldWin.define('move',true); +} + +/** Update a logging window + * + */ +gui.prototype.update = function (win) { + var view = this.UI(win); + // var log = this.UI(win+'LogText'); + // var scroll = view.getBody(); + var textview = this.UI(win+'LogTextView'); + // textview.refresh(); + + var element = textview.getNode(); + var data = textview.getValue(); + var textareaList = element.getElementsByTagName("textarea"); + if (view.scrollAuto && textareaList.length==1) { + var textarea=textareaList[0]; + textarea.scrollTop = textarea.scrollHeight; + } + + //view.show(); +} + +gui.prototype.updateConfig = function () { + for(i=0;i<10;i++) { + this.UI('configZlevel'+i).setValue(this.level[i]); + this.UI('configZlevel'+i).refresh(); + } +} + +gui.prototype.updateGui = function (full) { + var agents=0,nodes=0,n; + this.update('logWin'); + if (!this.simu) return; + for(n in this.simu.world.nodes) { + agents += this.simu.world.nodes[n].processes.used; + nodes++; + } + this.UI('simulationWinInfoTime').setValue('Time: '+(this.simu.time-this.simu.world.lag)); + this.UI('simulationWinInfoSteps').setValue('Step: '+this.simu.step); + this.UI('simulationWinInfoAgents').setValue('Agents: '+agents); + this.UI('simulationWinInfoNodes').setValue('Nodes: '+nodes); + + if (this.options.movie) { + this.printer.simulation(false); + if (this.simuPhy) this.printer.simulationPhy(); + } +} + +/** Unhighlight all lines in editor + * + */ +gui.prototype.unhighlight = function(editor) { + if (highlights[editor]) { + var myEditor = UI(editor).getEditor(); + if (!myEditor) return; + //Set line CSS class to the line number & affecting the background of the line with the css class of line-error + myEditor.setLineClass(highlights[editor] - 1, 'background', 'line-normal'); + highlights[editor]=0; + } +} + +/** Print a warning messager to the loggging window + * Returns a window-specific function. + */ +gui.prototype.warnToWin = function (win) { + var self=this; + return function(data) { + var view = self.UI(win); + var text = textview.getValue(); + text = text + '! '+ data +'\n'; + textview.setValue(text); + } +} + + +var Sejam2Gui = Require('ui/sejam2/sejam2-gui'); +gui.prototype.init=Sejam2Gui.gui.prototype.init; +var Sejam2Plot = Require('ui/sejam2/sejam2-plot'); +gui.prototype.plot = Sejam2Plot.gui.prototype.plot; +gui.prototype.plotPoint = Sejam2Plot.gui.prototype.plotPoint; +gui.prototype.plotLine = Sejam2Plot.gui.prototype.plotLine; +gui.prototype.plotText = Sejam2Plot.gui.prototype.plotText; +gui.prototype.plotBar = Sejam2Plot.gui.prototype.plotBar; +gui.prototype.plotAuto = Sejam2Plot.gui.prototype.plotAuto; +gui.prototype.plotAutoSave = Sejam2Plot.gui.prototype.plotAutoSave; + + +module.exports = { + Gui: function (options) {return new gui(options)} +} +@ + + +1.4 +log +@. +@ +text +@d20 1 +a20 1 + ** $INITIAL: (C) 2006-2017 bLAB +d22 1 +a22 1 + ** $VERSION: 1.8.7 +d34 3 +a36 1 + nonetwork:true +d38 1 +d40 8 +a47 6 +var Io = Require('com/io'); +var Comp = Require('com/compat'); +var Name = Require('com/pwgen'); +var Aios = Require('jam/aios'); +var Fs = Require('fs'); +var Path = Require('com/path'); +d49 1 +a49 1 +var util = Require('util'); +d51 1 +d53 6 +d67 1 +d86 4 +d92 5 +a96 4 + if (Io.getenv('WINE','')!='') { + this.workdir=Io.getenv('CWD','/'); + } else + this.workdir = Io.getenv('PWD','/'); +d100 1 +d132 3 +a134 2 + select:{agent:1,node:1,link:1,resource:1,physics:0}, + display:{agent:1,node:1,link:1,port:1,resource:1,flag:1,label:1,signal:1}, +d148 2 +a149 1 + fastcopy:false, // JAM agent process copy/fork/migrate mode +d152 9 +d167 1 +a167 1 + if (!options) options={node:true,fontSize:this.options.flag.fontSize,color:'red'}; +d184 12 +d208 2 +a209 2 + height=screen.height-offset, // TODO - nw.js toolbar height + width=screen.width, +d243 3 +a245 1 + } +d296 8 +d353 1 +d377 1 +d380 5 +d387 1 +a387 1 + * {'node','link','port','agent','resource','world','flag'} +d391 1 +d396 1 +d449 1 +a449 1 + var p; +d455 3 +a457 1 + if (this.worldWin.shapes[p]) +d459 2 +d463 1 +d466 53 +d531 2 +d537 1 +d539 2 +a540 1 + log:this.log}); +d542 1 +a542 1 + if (this.simu) this.simu.simuPhy = this.simuPhy; +d571 1 +a571 1 +gui.prototype.createWorld = function () { +d575 2 +a576 1 + this.log('[GUI] Creating world ...'); +d578 10 +a587 8 + CANNON:self.CANNON, + log:self.log, + msg:self.msg, + gui:self, + simuPhy:self.simuPhy, + nocp:true, // No AIOS agent proecss checkpointing! + fastcopy:self.options.simulation.fastcopy, // Dirty (fast) JAM agent code & signal copy? + TMO:self.options.simulation.TMO // JAM Node cache timeout +d590 1 +a590 1 + this.drawWorld(); +d624 35 +a658 1 +/** Destroy physical simualtion wolrd +d664 9 +a672 8 + this.simuPhy.destroy(); + this.simuPhy = none; + this.UI('physicalWinButCreate').enable(); + this.UI('physicalWinButDestroy').disable(); + this.physicalWin.gui=none; + this.UI('physicalWinButRun').disable(); + this.UI('physicalWinButStep').disable(); + this.UI('physicalWinButStop').disable(); +d675 1 +a680 1 + this.objects={}; +d682 2 +a683 2 + this.log('[GUI] Destroying old world '+this.simu.world.id+' ...'); + this.simu.destroy(); +d686 1 +a690 14 +/** Destroy one visual object + * + */ +gui.prototype.destroyObject = function (id) { + var self=this,shape, + obj=this.objects[id]; + if (obj) obj.obj=undefined; + delete this.objects[id]; + if (this.worldWin.shapes[id]) { + this.worldWin.shapes[id].remove(); + this.worldWin.shapes[id]=undefined; + } +} + +d701 2 +a702 1 + x0,x1,x2,y0,y1,y2; +d707 1 +a707 1 + shape.listen("click", function (e) {self.listenObject(id,e)}); +d720 1 +d723 7 +d733 3 +a735 2 + shape=this.worldWin.container.ellipse((obj.visual.x+off.x)*zoom, + (obj.visual.y+off.y)*zoom, +d738 2 +a739 1 + if (obj.visual.line) shape.stroke(obj.visual.line.color||'black',obj.visual.line.width||1); +d757 2 +a758 1 + if (obj.visual.line) shape.stroke(obj.visual.line.color||'black',obj.visual.line.width||1); +d793 1 +d938 11 +d950 4 +a953 1 +/** Install a shape/object listener +d959 11 +d985 2 +d1004 3 +a1006 2 + // self.log('Select: '+id+' ['+ovl.length+']'); + if (!self.inspectorWin.locked) { +d1011 1 +a1011 1 + self.UI('inspectorTree').close('root'); +d1116 54 +a1169 1 +} +d1208 1 +a1208 1 + if (Comp.isString(child)) +d1253 1 +a1253 1 + if (!obj || !shape) {this.log('[GUI] Unknown shape '+oid); return}; +d1290 1 +a1290 1 + if (!obj || !shape) {this.log('[GUI] Unknown shape '+oid); return}; +d1308 1 +d1329 1 +a1329 1 + if (!shape) {this.log('[GUI] Unknown shape '+oid); return}; +d1355 1 +a1355 1 + +d1358 1 +a1358 1 + entries = Fs.readdirSync(dir), +d1361 1 +d1381 1 +d1394 1 +d1397 1 +d1410 1 +d1455 1 +a1455 1 + * Expected format: { name, classes, world, .. } +d1459 2 +a1460 1 + var res, +d1463 1 +a1463 1 + model={name:'',classes:{},world:{}}, +d1465 2 +d1468 10 +a1477 5 + var text=Io.read_file(self.workdir+'/'+filename); + self.imports[filename]=text; + if (text==undefined) + self.log('Error: Opening of file '+self.workdir+'/'+filename+' failed!'); + else return text; +d1480 2 +a1481 1 + text = 'res = '+text; +d1489 2 +a1490 1 + eval('res = '+text); +d1495 1 +d1497 2 +a1498 1 + return res; +d1534 1 +d1571 1 +d1614 16 +d1650 1 +d1654 9 +d1687 1 +a1687 1 + if (textareaList.length==1) { +d1703 1 +a1703 1 + var agents=0,n; +d1708 1 +d1713 6 +d1751 7 +a1757 5 +gui.prototype.plot=Sejam2Plot.gui.prototype.plot; +gui.prototype.plotPoint=Sejam2Plot.gui.prototype.plotPoint; +gui.prototype.plotLine=Sejam2Plot.gui.prototype.plotLine; +gui.prototype.plotText=Sejam2Plot.gui.prototype.plotText; +gui.prototype.plotBar=Sejam2Plot.gui.prototype.plotBar; +@ + + +1.3 +log +@. +@ +text +@d22 1 +a22 1 + ** $VERSION: 1.8.6 +d1371 1 +a1371 1 + this.stat(Comp.printf.sprintf('Communication: %8d Bytes/Obj.',stats.send)); +@ + + +1.2 +log +@*** empty log message *** +@ +text +@d22 1 +a22 1 + ** $VERSION: 1.7.3 +d26 1 +a26 1 + ** SEJAM2: Simulation Environment for JAM, GUI Webix+, Cannon Phy Simu, NW edition +d107 4 +d114 1 +a114 1 + display:{agent:1,node:1,link:1,port:1,resource:1,flag:1,label:1}, +d116 11 +d128 2 +a129 1 + fastcopy:false, // JAM agent process copy/fork/migrate mode +d131 1 +a131 1 + flag:{fontSize:14} +d254 2 +d338 1 +d359 25 +d459 3 +a461 2 + nocp:true, // No AIOS agent proecss checkpointing! + fastcopy:self.options.simulation.fastcopy // Dirty (fast) JAM agent process copy? +d548 1 +d555 2 +a556 1 + if (!this.worldWin.container || !obj || shape || !this.level[level]) return; +d755 1 +a755 3 + objClass=this.classObject(p); + if (this.options.display[objClass]) + this.drawObject(p); +d1453 8 +a1460 1091 +/** Build and initialize the GUI using the Webix toolkit. + * + */ +gui.prototype.init = function () { + var self = this; + + this.changeCSS('.webix_el_textarea textarea','font-size','12px'); + this.changeCSS('tt','font-size','12px'); + this.changeCSS('.CodeMirror pre','font-size',"12px"); + this.changeCSS('.CodeMirror pre','font-family','"DejaVu Sans Mono",Tahoma'); + + // TOP TOOLBAR + this.toolbar = this.webix.ui({ + view:"toolbar", + id:"myToolbar", + left:00, top:0, width:'100%', + cols:[ + { view:"button", type:"icon", icon:"folder-open", tooltip:'Open Model', width:30, click:function () { + var but = self.UI('filedialogWinAction'); + but.setValue('Load Model'); + but.refresh(); + self.openDir(self.workdir); + self.filedialogWin.show(); + }}, + { view:"button", type:"icon", icon:"repeat", tooltip:'Reload', width:30, click:function () { + if (!self.filename || self.filename=='') return; + self.clear('msgWin'); + self.messages=[]; + self.destroyWorld(); + self.resetGui(); + if (self.simuPhy) self.simuPhy.destroy(); + self.simuPhy = none; + self.UI('physicalWinButCreate').enable(); + self.UI('physicalWinButDestroy').disable(); + self.physicalWin.gui=none; + self.UI('physicalWinButRun').disable(); + self.UI('physicalWinButStep').disable(); + self.UI('physicalWinButStop').disable(); + try { + text = Io.read_file(self.workdir+'/'+self.filename); + self.source = text; + self.imports = {}; + self.model = self.parseModel(text); + if (self.model && self.model.name) + self.log('Loaded simulation model "'+self.model.name+'" ('+self.source.length+') from file '+self.filename); + else + self.log('Loading simulation model from file '+self.filename+' failed.'); + self.filedialogWin.hide(); + self.UI('sourceText').setValue(self.source); + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + self.editorWin._changed=false; + self.editorWin._active=self.filename; + self.inspect.root = 'model'; + self.inspect.data = self.model; + self.UI('sourceTextWinMenu').remove('root'); + files=[self.filename]; + for(p in self.imports) { + files.push(p); + } + self.UI('sourceTextWinMenu').add({ + id:'root', + value:self.filename, + submenu:files}); + } catch (e) { + self.log('Loading of simulation model from file '+self.filename+' failed: '+e.toString()); + } + + }}, + { view:"button", id:'buttonTopSave', type:"icon", icon:"save", tooltip:'Save Model', width:30, click:function () { + /* + var but = self.UI('filedialogWinAction'); + but.setValue('Save Model'); + but.refresh(); + self.filedialogWin.show(); + */ + self.saveAll(); + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + }}, + { view:"button", type:"icon", icon:"magic", tooltip:'New Model Wizard', width:30, click:function () { + + }}, + { view:"button", type:"icon", icon:"edit", tooltip:'Edit', width:30, click:function () { + if (self.editorWin.isVisible()) + self.editorWin.hide(); + else { + self.editorWin.show(); + if (!self.editorWin._active && self.filename) self.editorWin._active=self.filename; + if (!self.editorWin._changed) self.editorWin._switched=true; + if (self.editorWin._active==self.filename) + self.UI('sourceText').setValue(self.source); + else + self.UI('sourceText').setValue(self.imports[self.editorWin._active]); + + if (!self.editorWin._changed) { + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + } + + self.UI('sourceText').editor.setOption("onChange", function(id){ + if (!self.editorWin._switched) { + self.UI('buttonTopSave').enable(); + self.UI('buttonEditorSave').enable(); + self.editorWin._changed=true; + } + self.editorWin._switched=false; + }); + } + }}, + { view:"button", type:"icon", icon:"sitemap", tooltip:'Inspector', width:30, click:function () { + if (self.inspectorWin.isVisible()) + self.inspectorWin.hide(); + else { + self.deleteTree(self.inspect.root); + self.makeTree(self.inspect.data,'root'); + self.inspectorWin.show(); + } + }}, + { view:"button", type:"icon", icon:"info-circle", tooltip:'System Console', width:30, click:function () { + if (self.logWin.isVisible()) + self.logWin.hide(); + else + self.logWin.show(); + }}, + { view:"button", type:"icon", icon:"table", tooltip:'Classes', width:30, click:function () { + }}, + { view:"button", type:"icon", icon:"cloud", tooltip:'World', width:30, click:function () { + if (self.worldWin.isVisible()) + self.worldWin.hide(); + else { + self.worldWin.show(); + self.clearWorld(); + self.drawWorld(); + } + }}, + { view:"button", type:"icon", icon:"play", tooltip:'Simulation', width:30, click:function () { + if (self.simulationWin.isVisible()) + self.simulationWin.hide(); + else + self.simulationWin.show(); + }}, + { view:"button", type:"icon", icon:"navicon", tooltip:'Configuration', width:30, click:function () { + if (self.configWin.isVisible()) + self.configWin.hide(); + else { + self.configWin.show(); + self.updateConfig(); + } + }}, + { view:"button", type:"icon", icon:"th-large", tooltip:'Auto Layout', width:30, click:function () { + var _locked=self.toolbar.locked; + self.toolbar.locked=false; + self.autoLayout(); + self.toolbar.locked=_locked; + }}, + { view:"button", id:'topWinLock', type:"icon", icon:"unlock", tooltip:'Lock/Unlock Layout', width:30, click:function () { + if (self.toolbar.locked) { + self.unlockLayout(); + } else { + self.lockLayout(); + } + }}, + { view:"button", type:"icon", icon:"cubes", tooltip:'Physical Engine', width:30, click:function () { + if (self.physicalWin.isVisible()) + self.physicalWin.hide(); + else + self.physicalWin.show(); + }}, + { view:"label", id:'myTopLabel', label:'JAM World '+self.worldname+' ', align:'right'}, + { view:"button", type:"icon", icon:"close", tooltip:'Exit', width:30, click:function () { + process.exit(); + }}, + ] + }); + + // STATISTICS WIN + this.statWin = this.webix.ui({ + view:"popup", + id:'statWin', + resize: true, + width:500, + body: { + rows: [ + {cols: [ + { view:"button", type:"icon", icon:"repeat", tooltip:'Refresh', width:30, click:function () { + }}, + { view:"label", label:"Statistics", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.statWin.hide(); + }} + ]}, + {view:'textarea', autoheight:true, readonly:true, borderless:true, id:'statWinLogTextView',value: ''} + ] + } + }); + + // MESSAGE WIN + this.msgWin = this.webix.ui({ + view:"popup", + id:'msgWin', + resize: true, + width:500, + body: { + rows: [ + {cols: [ + { view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () { + self.clear('msgWin'); + var textview = self.UI('msgWinLogTextView'); + self.messages=[]; + textview.setValue(''); + }}, + { view:"button", type:"icon", icon:"repeat", tooltip:'Refresh', width:30, click:function () { + var textview = self.UI('msgWinLogTextView'); + var text='',off=self.messages.length>1000?self.messages.length-1000:0; + Comp.array.iter(self.messages,function (m,i) {if (i>=off) text=text+m+'\n'}); + textview.setValue(text); + textview.refresh(); + var element = textview.getNode(); + var data = textview.getValue(); + var textareaList = element.getElementsByTagName("textarea"); + if (textareaList.length==1) { + var textarea=textareaList[0]; + textarea.scrollTop = textarea.scrollHeight; + } + }}, + { view:"label", label:"Agent Messages", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.msgWin.hide(); + }} + ]}, + {view:'textarea', autoheight:true, readonly:true, borderless:true, id:'msgWinLogTextView',value: ''} + ] + } + }); + + // LOG WIN + this.logWin = this.webix.ui({ + id:'logWin', + view:"window", + height:200, + width:500, + left:50, top:50, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarlogWin", + cols:[ + { view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () { + self.clear('logWin'); + }}, + { view:"button", type:'icon', icon:'info' , tooltip:'Statistics', id: 'SysWinInfoBut', width:30, click:function () { + var parent = self.UI("logWin").getNode(); + if (self.statWin.isVisible()) { + self.statWin.hide(); + return; + } + + //console.log(node); return; + self.clear('statWin'); + self.showStats(); + self.statWin.show(parent , {pos:'bottom'}); + }}, + { view:"button", type:'icon', icon:'inbox' , tooltip:'Agent Messages', id: 'SysWinMsgBut', width:30, click:function () { + var parent = self.UI("logWin").getNode(); + if (self.msgWin.isVisible()) { + self.msgWin.hide(); + return; + } + self.clear('msgWin'); + var textview = self.UI('msgWinLogTextView'); + var text='',off=self.messages.length>1000?self.messages.length-1000:0; + Comp.array.iter(self.messages,function (m,i) {if (i>=off) text=text+m+'\n'}); + textview.setValue(text); + self.msgWin.define('width',self.logWin.getNode().offsetWidth-2); + self.msgWin.resize(); + self.msgWin.show(parent , {pos:'bottom'}); + + }}, + { view:"button", type:'icon', icon:'plus-circle' , tooltip:'Increase Font Size', width:30, click:function () { + self.changeCSS('.webix_el_textarea textarea','font-size','14px'); + self.changeCSS('tt','font-size','14px'); + self.changeCSS('.CodeMirror pre','font-size',"14px"); + }}, + { view:"button", type:'icon', icon:'minus-circle' , tooltip:'Decrease Font Size', width:30, click:function () { + self.changeCSS('.webix_el_textarea textarea','font-size','12px'); + self.changeCSS('tt','font-size','12px'); + self.changeCSS('.CodeMirror pre','font-size',"12px"); + }}, + { view:"label", label:"System Console", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.logWin.hide(); + }} + ] + }, +/* + body:{ + id : 'logWinLog', + view : 'scrollview', + scroll : 'y', + body : {view:'textarea',autoheight:true, borderless:true, id:'logWinLogTextView',value: ''} + } +*/ + body: {view:'textarea', autoheight:true, readonly:true, borderless:true, id:'logWinLogTextView', value: ''} + }); + this.log = this.logToWin('logWin'); + this.stat = this.logToWin('statWin'); + this.msg = function (line) {self.messages.push(line)}; + this.log('Ready.'); + this.log('My current working directory is '+this.workdir); + this.log('My versions: node:'+process.version+', node-wekbkit:'+process.versions['node-webkit']+ + ', nw:'+process.versions['nw']+', chromium: '+process.versions['chromium']); + + // FILE DIALOG WIN + this.filedialogWin = this.webix.ui({ + id:'filedialogWin', + view:"window", + height:350, + width:500, + left:100, top:100, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarfiledialogWin", + cols:[ + { view:"label", label:"File Explorer", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.filedialogWin.hide(); + }} + ] + }, + body:{ + id: 'filedialogWinForm', + view:"form", + elements:[ + { + view:"list", + // height:150, + id: 'filedialogWinList', + template:"#icon# #name#", + select:false, + data:[ + // { id:0, flag:'d', icon:'', name:".."}, + ] + }, + { view:"text", id:'filedialogWinFormDirectory', label:"Directory", value:self.workdir }, + { view:"text", id:'filedialogWinFormFile', label:"Filename" }, + {cols:[ + { view:"button", id:'filedialogWinAction', value:'?', type:'form', click : function () { + var text,files=[],p,filename; + switch (self.UI('filedialogWinAction').getValue()) { + case 'Load Model': + try { + self.filename=self._filename; + text = Io.read_file(self.workdir+'/'+self.filename); + self.source = text; + self.imports = {}; + self.model = self.parseModel(text); + if (self.model && self.model.name) + self.log('Loaded simulation model "'+self.model.name+'" ('+self.source.length+') from file '+self.filename); + else + self.log('Loading simulation model from file '+self.filename+' failed.'); + self.filedialogWin.hide(); + self.UI('sourceText').setValue(self.source); + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + self.editorWin._changed=false; + self.editorWin._active=self.filename; + self.inspect.root = 'model'; + self.inspect.data = self.model; + self.UI('sourceTextWinMenu').remove('root'); + files=[self.filename]; + for(p in self.imports) { + files.push(p); + } + self.UI('sourceTextWinMenu').add({ + id:'root', + value:self.filename, + submenu:files}); + } catch (e) { + self.log('Loading of simulation model from file '+self.filename+' failed: '+e.toString()); + } + break; + + case 'Load Module': + try { + filename = self._filename; + text = Io.read_file(self.workdir+'/'+filename); + self.filedialogWin.hide(); + self.imports[filename]=text; + files=[self.filename]; + for(p in self.imports) { + files.push(p); + } + self.UI('sourceTextWinMenu').add({ + id:'root', + value:self.filename, + submenu:files}); + self.log('Loaded simulation module "'+filename+'" ('+text.length+') from file '); + } catch (e) { + self.log('Loading of simulation module from file '+filename+' failed: '+e.toString()); + } + break; + + case 'Save Model': + try { + self.filename=self._filename; + self.log('Saving simulation model "'+(self.model?self.model.name:'')+'" ('+self.source.length+') to file '+self.filename); + self.filedialogWin.hide(); + Io.write_file(self.workdir+'/'+self.filename,self.source); + text=Io.read_file(self.workdir+'/'+self.filename); + self.imports={}; + self.model = self.parseModel(text); + if (self.model && self.model.name) { + self.log('Updated simulation model "'+self.model.name+'" ('+self.source.length+') from file '+self.filename); + self.inspect.root='model'; + self.inspect.data=self.model; + } else + self.log('Updating simulation model from file '+self.filename+' failed.'); + } catch (e) { + self.log('Saving of simulation model to file '+self.filename+' failed: '+e.toString()); + } + break; + } + }}, + { view:"button", value:'Cancel', click: function () { + self.filedialogWin.hide(); + }} + ]} + ] + } + }); + this.UI('filedialogWinList').attachEvent("onItemClick", function(id, e, node){ + var item = this.getItem(id); + if (item.flag=='d') { + self.workdir = Path.resolve(item.dir+'/'+item.name); + self.UI('filedialogWinFormDirectory').setValue(self.workdir); + self._filename = ''; + self.UI('filedialogWinFormFile').setValue(self._filename); + self.openDir(self.workdir); + } else { + self._filename = item.name; + self.UI('filedialogWinList').select(id); + self.UI('filedialogWinFormFile').setValue(self._filename); + } + }); + + // EDITOR WIN + this.editorWin = this.webix.ui({ + id:'sourceTextWin', + view:"window", + height:300, + width:500, + left:100, top:100, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarsourceTextWin", + cols:[ + { view:"button", type:"icon", icon:"folder-open", + tooltip:'Open Module File', width:30, click:function () { + var but = self.UI('filedialogWinAction'); + but.setValue('Load Module'); + but.refresh(); + self.openDir(self.workdir); + self.filedialogWin.show(); + } + }, + { view:"button", id:'buttonEditorSave', type:"icon", icon:"save", disable:true, + tooltip:'Save Model', width:30, click:function () { + /* + var but = self.UI('filedialogWinAction'); + self.source = self.UI('sourceText').getValue(); + but.setValue('Save'); + but.refresh(); + self.openDir(self.workdir); + self.filedialogWin.show(); + */ + if (self.editorWin._active && self.editorWin._active!=self.filename) + self.imports[self.editorWin._active]=self.UI('sourceText').getValue(); + else + self.source=self.UI('sourceText').getValue(); + self.saveAll(); + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + self.editorWin._changed=false; + }}, + { view:"button", type:"icon", icon:"file", + tooltip:'New Module File', width:30, click:function () { + } + }, + { + view:"menu", + id:"sourceTextWinMenu", + subMenuPos:"right", + layout:'x', + autowidth:true, + data:[ //menu data + { id:'root', value:"Modules", submenu:["Main"]}, + ], + click:function(id) { + var p,files; + self.log('Selected '+id); + if (id!='root') { + self.UI('sourceTextWinMenu').remove('root'); + files=[self.filename]; + for(p in self.imports) files.push(p); + self.UI('sourceTextWinMenu').add({ + id:'root', + value:id, + submenu:files}); + + if (!self.editorWin._changed) self.editorWin._switched=true; + if (self.editorWin._active && self.editorWin._active!=self.filename) + self.imports[self.editorWin._active]=self.UI('sourceText').getValue(); + else + self.source=self.UI('sourceText').getValue(); + + if (id==self.filename) + self.UI('sourceText').setValue(self.source); + else + self.UI('sourceText').setValue(self.imports[id]); + self.editorWin._active=id; + if (!self.editorWin._changed) { + self.UI('buttonTopSave').disable(); + self.UI('buttonEditorSave').disable(); + } + } + }, + type:{ + subsign:true + } + }, + { view:"label", label:"Model Editor", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + if (self.editorWin._active==self.filename) + self.source = self.UI('sourceText').getValue(); + else + self.imports[self.editorWin._active]=self.UI('sourceText').getValue(); + + self.editorWin.hide(); + }} + ] + }, + body:{ + id : 'sourceText', + view: "codemirror-editor" + } + }); + + // SIMULATION CONTROL WIN + this.simulationWin = this.webix.ui({ + id:'simulationWin', + view:"window", + height:120, + width:400, + left:110, top:110, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarsimulationWin", + cols:[ + { view:"button", id:'simulationWinButCreate', type:"icon", icon:"star", tooltip:'Create Simulation World', width:30, click: function () { + self.clearWorld(); + self.clear('logWin'); + self.objects={}; + self.createWorld(); + self.UI('simulationWinButErase').enable(); + self.UI('simulationWinButStep').enable(); + self.UI('simulationWinButPlay').enable(); + self.UI('simulationWinButStop').disable(); + self.UI('simulationWinButCreate').disable(); + }}, + { view:"button", id:'simulationWinButErase', type:"icon", icon:"trash", tooltip:'Destroy Simulation World', width:30, click:function () { + self.clear('msgWin'); + self.messages=[]; + self.destroyWorld(); + self.resetGui(); + }}, + { view:"button", id:'simulationWinButStep', type:"icon", icon:"step-forward", tooltip:'Step Mode', width:30, click: function () { + var steps = Number(self.UI('simulationWinFormSteps').getValue()); + if (steps > 0 && self.simu) { + self.UI('simulationWinButStep').disable(); + self.UI('simulationWinButPlay').disable(); + self.UI('simulationWinButStop').enable(); + self.simu.simulate(steps,function () { + self.UI('simulationWinButStep').enable(); + self.UI('simulationWinButPlay').enable(); + self.UI('simulationWinButStop').disable(); + }); + } + + }}, + { view:"button", id:'simulationWinButPlay', type:"icon", icon:"play", tooltip:'Start Simulation', width:30, click: function () { + self.UI('simulationWinButStep').disable(); + self.UI('simulationWinButPlay').disable(); + self.UI('simulationWinButStop').enable(); + self.simu.simulate(100000,function () { + self.UI('simulationWinButStep').enable(); + self.UI('simulationWinButPlay').enable(); + self.UI('simulationWinButStop').disable(); + }); + }}, + { view:"button", id:'simulationWinButStop', type:"icon", icon:"stop", tooltip:'Stop Simulation', width:30, click: function () { + self.simu.stop(); + self.UI('simulationWinButStep').enable(); + self.UI('simulationWinButPlay').enable(); + self.UI('simulationWinButStop').disable(); + }}, + { view:"label", label:"Simulation Control", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.simulationWin.hide(); + }} + ] + }, + body:{ + id: 'simulationWinForm', + view:"form", + paddingX:2, + paddingY:4, + elements:[ + {cols:[ + { view:"text", id:'simulationWinFormSteps', label:"Steps", value:'1', maxWidth:150}, + { view:"text", id:'simulationWinFormDelay', label:"Delay [ms]", value:'0', maxWidth:150}, + { view:"label", id:'simulationWinInfoTime', label:"Time: 0" }, + { view:"label", id:'simulationWinInfoSteps', label:"Steps: 0" }, + { view:"label", id:'simulationWinInfoAgents', label:"Agents: 0" }, + ]} + ] + } + }); + + // SIMULATION WORLD WIN + this.worldWin = this.webix.ui({ + id:'worldWin', + view:"window", + height:400, + width:500, + left:70, top:70, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarworldWin", + cols:[ + { view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () { + if (self.worldWin.flags) { + self.UI('worldWinButFlags').define('icon','flag'); + self.UI('worldWinButFlags').refresh(); + self.worldWin.flags=false; + self.removeFlags(); + }; + self.clearWorld(); + }}, + { view:"button", type:"icon", icon:"repeat", tooltip:'Redraw', width:30, click:function () { + self.clearWorld(); + self.drawWorld(); + }}, + { view:"button", type:"icon", icon:"search-plus", tooltip:'Zoom In', width:28, click:function () { + self.worldWin.zoom *= 1.25; + self.clearWorld(); + self.drawWorld(); + }}, + { view:"button", type:"icon", icon:"search-minus", tooltip:'Zoom Out', width:28, click:function () { + self.worldWin.zoom /= 1.25; + self.clearWorld(); + self.drawWorld(); + }}, + { view:"button", id:'worldWinButZoomRegion', type:"icon", icon:"search", tooltip:'Zoom Region', width:28, click:function () { + self.window.mode='zoom'; + self.UI('worldWinButZoomRegion').disable(); + }}, + { view:"button", type:"icon", icon:"square-o", tooltip:'Zoom Fit', width:28, click:function () { + var zw=1,zh=1,o,dx,dy; + self.worldWin.offset={x:0,y:0}; + // self.log(util.inspect(self.window)); + zw=(self.worldWin.getNode().offsetWidth-35)/(self.window.x1-self.window.x0); + zh=(self.worldWin.getNode().offsetHeight-70)/(self.window.y1-self.window.y0); + self.worldWin.zoom=Math.min(zw,zh); + dx=-self.window.x0+10; + dy=-self.window.y0+10; + for(o in self.objects) { + self.moveShape(o,dx,dy); + } + self.clearWorld(); + self.drawWorld(); + }}, + { view:"button", id:'worldWinButSelectRegion', type:"icon", icon:"crop", tooltip:'Select Region', width:28, click:function () { + self.window.mode='select'; + self.UI('worldWinButSelectRegion').disable(); + }}, +/* + { view:"button", type:"icon", icon:"angle-left", tooltip:'Move Left', width:20, click:function () { + self.worldWin.offset.x += 30; + for(var o in self.objects) { + self.moveShape(o,30,0); + } + }}, + { view:"button", type:"icon", icon:"angle-right", tooltip:'Move Right', width:20, click:function () { + self.worldWin.offset.x -= 30; + for(var o in self.objects) { + self.moveShape(o,-30,0); + } + }}, + { view:"button", type:"icon", icon:"angle-up", tooltip:'Move Up', width:22, click:function () { + self.worldWin.offset.y += 30; + for(var o in self.objects) { + self.moveShape(o,0,30); + } + }}, + { view:"button", type:"icon", icon:"angle-down", tooltip:'Move Down', width:22, click:function () { + self.worldWin.offset.y -= 30; + for(var o in self.objects) { + self.moveShape(o,0,-30); + } + }}, +*/ + { view:"button", id:'worldWinButFlags', type:"icon", icon:"flag", tooltip:'Enable/Disable Object Flags', width:30, click:function () { + if (self.worldWin.flags) { + self.UI('worldWinButFlags').define('icon','flag'); + self.UI('worldWinButFlags').refresh(); + self.worldWin.flags=false; + self.removeFlags(); + } else { + self.UI('worldWinButFlags').define('icon','flag-o'); + self.UI('worldWinButFlags').refresh(); + self.worldWin.flags=true; + self.addFlags(); + } + }}, + + { view:"button", id:'worldWinSave', type:"icon", icon:"save", tooltip:'Export simualtion world to SVG', width:30, click:function () { + function snap() { + var image = self.worldWin.container.toSvg(self.window.x1-self.window.x0+50,self.window.y1-self.window.y0+20); + self.worldWin.container.toSvg(); + return image; + }; + try { Io.write_file('Z:/tmp/simulation.svg',snap()); + self.log('Exported world to /tmp/simulation.svg'); } catch (e) { self.log(util.inspect(e)) }; + }}, + + { view:"label", id:'worldWinInfo', label:'', align:'center'}, + { view:"label", label:'Simulation World', width:200, align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.worldWin.hide(); + }} + ] + }, + body:{ + template : '
', + borderless:false + } + }); + this.UI('simulationWinButErase').enable(); + this.UI('simulationWinButStep').enable(); + this.UI('simulationWinButPlay').enable(); + + this.worldWin.shapes={}; + this.worldWin.zoom=1.0; + this.worldWin.offset={x:0,y:0}; + this.toolbar.show(); + this.UI('buttonTopSave').disable(); + + // INSPECTOR WIN + this.inspectorWin = this.webix.ui({ + id:'inspectorWin', + view:"window", + height:400, + width:300, + left:90, top:90, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarinspectorWin", + cols:[ + { view:"button", type:"icon", icon:"eraser", tooltip:'Clear', width:30, click:function () { + self.deleteTree('/'); + }}, + { view:"button", type:"icon", icon:"university", tooltip:'Model', width:30, click:function () { + self.inspect.data=self.model; + self.deleteTree(self.inspect.root); + self.makeTree(self.inspect.data,'root'); + self.UI('inspectorTree').close('root'); + }}, + { view:"button", type:"icon", icon:"picture-o", tooltip:'GUI Objects', width:30, click:function () { + self.inspect.data=self.objects; + self.deleteTree('GUI'); + self.makeTree(self.inspect.data,'root'); + self.UI('inspectorTree').close('root'); + }}, + { view:"button", id:'inspectorWinLock', type:"icon", icon:"unlock", tooltip:'Lock/Unlock View', width:30, click:function () { + if (self.inspectorWin.locked) { + self.UI('inspectorWinLock').define('icon','unlock'); + self.UI('inspectorWinLock').refresh(); + self.inspectorWin.locked=false; + } else { + self.UI('inspectorWinLock').define('icon','lock'); + self.UI('inspectorWinLock').refresh(); + self.inspectorWin.locked=true; + } + }}, + { view:"label", label:"Inspector", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.inspectorWin.hide(); + }} + ] + }, + body: { + id:'inspectorTree', + view:'tree', + type:'lineTree', + template:"{common.icon()} #value#", + select:true, + data: [ + { id:"root", open:true, value:"/"} + ] + } + }); + this.UI('inspectorTree').attachEvent("onBeforeOpen", function(id){ + var tree = self.UI('inspectorTree'), + node = tree.getItem(id), + childid,n=100000,p,remove=[]; + childid=tree.getFirstChildId(id); + while (childid != undefined && n>0) { + n--; + remove.push(childid); + childid=tree.getNextSiblingId(childid); + } + for(p in remove) tree.remove(remove[p]); + if (node._data) self.makeTree(node._data,id); + else if (id=='root') self.makeTree(self.inspect.data,id); + }); + this.UI('inspectorTree').attachEvent("onBeforeClose", function(id){ + var tree = self.UI('inspectorTree'), + node = tree.getItem(id); + tree.add({id:id+'.0',value:'..'},0,id); + }); + + // CONFIGURATION WIN + this.configWin = this.webix.ui({ + id:'configWin', + view:"window", + width:300, + height:450, + left:90, top:90, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarconfigWin", + cols:[ + { view:"label", label:"Configuration", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.configWin.hide(); + }} + ] + }, + body: { + rows:[ + { view:"form", scroll:true, width:300, height:400, elements: [ + + { view:"label", label:"Object Selection", height:'18px', align:'left'}, + { view:"checkbox", id:'configObjectSelectionAgent', customCheckbox:false, labelRight:"Agents", height:'18px', value:1, + click: function (o) {self.options.select.agent=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectSelectionNode', customCheckbox:false, labelRight:"Nodes", height:'18px',value:1, + click: function (o) {self.options.select.node=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectSelectionLink', customCheckbox:false, labelRight:"Links", height:'18px',value:1, + click: function (o) {self.options.select.link=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectSelectionPort', customCheckbox:false, labelRight:"Ports", height:'18px',value:1, + click: function (o) {self.options.select.port=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectSelectionResource', customCheckbox:false, labelRight:"Resources", height:'18px',value:1, + click: function (o) {self.options.select.resource=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectSelectionPhysics', customCheckbox:false, labelRight:"Physics Connect", height:'18px',value:0, + click: function (o) {self.options.select.physics=self.UI(o).getValue()}}, + + { view:"label", label:"Object Display", height:'18px', align:'left'}, + { view:"checkbox", id:'configObjectDisplayAgents', customCheckbox:false, labelRight:"Agents", height:'18px', value:1, + click: function (o) {self.options.display.agent=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayNodes', customCheckbox:false, labelRight:"Nodes", height:'18px',value:1, + click: function (o) {self.options.display.node=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayLinks', customCheckbox:false, labelRight:"Links", height:'18px',value:1, + click: function (o) {self.options.display.link=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayPorts', customCheckbox:false, labelRight:"Ports", height:'18px',value:1, + click: function (o) {self.options.display.port=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayResources', customCheckbox:false, labelRight:"Resources", height:'18px',value:1, + click: function (o) {self.options.display.resource=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayFlags', customCheckbox:false, labelRight:"Flags", height:'18px',value:1, + click: function (o) {self.options.display.flag=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectDisplayLabels', customCheckbox:false, labelRight:"Labels", height:'18px',value:1, + click: function (o) {self.options.display.label=self.UI(o).getValue()}}, + + { view:"label", label:"Inspector Object Filter", height:'18px', align:'left'}, + { view:"checkbox", id:'configInspectorFilterFunction', customCheckbox:false, labelRight:"Functions", height:'18px', value:0, + click: function (o) {self.inspect.filter.function=self.UI(o).getValue()}}, + { view:"checkbox", id:'configInspectorFilterCannon', customCheckbox:false, labelRight:"Physical Attributes", height:'18px', value:0, + click: function (o) { + var set=self.UI(o).getValue(); + if (!set) {self.inspect.filter.attributes=undefined; return;} + if (!self.inspect.filter.attributes) self.inspect.filter.attributes={}; + for(var p in physicalAttributeSet) { + if (typeof physicalAttributeSet[p] == 'string') + self.inspect.filter.attributes[physicalAttributeSet[p]]=true; + else if (physicalAttributeSet[p] instanceof RegExp) { + if (!self.inspect.filter.attributes.patterns) self.inspect.filter.attributes.patterns=[]; + self.inspect.filter.attributes.patterns.push(physicalAttributeSet[p]); + } + } + } + }, + + + { view:"label", label:"Balloon Messages", height:'18px', align:'left'}, + { view:"checkbox", id:'configObjectMessageWarning', customCheckbox:false, labelRight:"Warning", height:'18px', value:0, + click: function (o) {self.options.message.warning=self.UI(o).getValue()}}, + { view:"checkbox", id:'configObjectMessageError', customCheckbox:false, labelRight:"Error", height:'18px', value:1, + click: function (o) {self.options.message.error=self.UI(o).getValue()}}, + + { view:'label', label:'Flag Fontsize',height:0}, + { + view:"radio", + id:"configFlagSize", + name:"configFlagSize", + label:" ", + value:14, + vertical:true, + customRadio:false, + click: function () {self.options.flag.fontSize=self.UI('configFlagSize').getValue()}, + options:[ + {"id":14, "value":"14 px"}, + {"id":18, "value":"18 px"}, + {"id":24, "value":"24 px"}, + {"id":28, "value":"28 px"}, + ] + }, + + { view:'label', label:'Verbosity Level', height:0}, + { + view:"radio", + id:"configVerbosity", + name:"configVerbosity", + label:" ", + value:0, + vertical:true, + customRadio:false, + click: function () {self.options.verbose=self.UI('configVerbosity').getValue()}, + options:[ + {"id":0, "value":"None"}, + {"id":1, "value":"Low"}, + {"id":2, "value":"Mid"}, + {"id":3, "value":"High"}, + ] + }, + + { view:'label', label:'Simulation', height:0}, + { view:"checkbox", id:'configSimulationFastCopy', customCheckbox:false, labelRight:"Fast Agent Copy", height:'18px', value:0, + click: function (o) {self.options.simulation.fastcopy=Number(self.UI(o).getValue())==1;}}, + + { view:'label', label:'Z Level', height:0}, + { view:"checkbox", id:'configZlevel0', customCheckbox:false, labelRight:"0", height:'18px', value:self.level[0], + click: function (o) {self.level[0]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel1', customCheckbox:false, labelRight:"1", height:'18px', value:self.level[1], + click: function (o) {self.level[1]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel2', customCheckbox:false, labelRight:"2", height:'18px', value:self.level[2], + click: function (o) {self.level[2]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel3', customCheckbox:false, labelRight:"3", height:'18px', value:self.level[3], + click: function (o) {self.level[3]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel4', customCheckbox:false, labelRight:"4", height:'18px', value:self.level[4], + click: function (o) {self.level[4]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel5', customCheckbox:false, labelRight:"5", height:'18px', value:self.level[5], + click: function (o) {self.level[5]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel6', customCheckbox:false, labelRight:"6", height:'18px', value:self.level[6], + click: function (o) {self.level[6]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel7', customCheckbox:false, labelRight:"7", height:'18px', value:self.level[7], + click: function (o) {self.level[7]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel8', customCheckbox:false, labelRight:"8", height:'18px', value:self.level[8], + click: function (o) {self.level[8]=Number(self.UI(o).getValue())}}, + { view:"checkbox", id:'configZlevel9', customCheckbox:false, labelRight:"9", height:'18px', value:self.level[9], + click: function (o) {self.level[9]=Number(self.UI(o).getValue())}}, + + ]} + ] + } + }); + + // PHYSICAL SIMULATION WIN + this.physicalWin = this.webix.ui({ + id:'physicalWin', + view:"window", + height:400, + width:600, + left:50, top:50, + move:true, + resize: true, + toFront:true, + head: { + view:"toolbar", + id:"myToolbarRenderWin", + cols:[ + { view:"button", id:"physicalWinButCreate", type:"icon", icon:"star", tooltip:'Create', width:30, click:function () { + self.createSimuPhy(); + }}, + { view:"button", id:"physicalWinButDestroy", type:"icon", icon:"trash", tooltip:'Destroy', width:30, click:function () { + self.destroySimuPhy(); + }}, + { view:"button", id:"physicalWinButRun",type:"icon", icon:"play", tooltip:'Run', width:30, click:function () { + self.physicalWin.gui.enable(); + //self.UI('physicalWinButRender').define('icon','toggle-on'); + //self.UI('physicalWinButRender').refresh(); + self.physicalWin.render=true; + self.physicalWin.gui.start(); + self.UI('physicalWinButRun').disable(); + self.UI('physicalWinButStep').disable(); + self.UI('physicalWinButStop').enable(); + }}, + { view:"button", id:"physicalWinButStep", type:"icon", icon:"step-forward", tooltip:'Step', width:30, click:function () { + var steps = Number(self.UI('physicalWinFormSteps').getValue()); + self.physicalWin.gui.enable(); + self.physicalWin.gui.step(steps); + //self.UI('physicalWinButRender').define('icon','toggle-off'); + //self.UI('physicalWinButRender').refresh(); + self.physicalWin.render=false; + }}, + { view:"button", id:"physicalWinButStop", type:"icon", icon:"stop", tooltip:'Stop', width:30, click:function () { + self.physicalWin.gui.disable() + self.physicalWin.gui.stop(); + self.UI('physicalWinButRun').enable(); + self.UI('physicalWinButStep').enable(); + self.UI('physicalWinButStop').disable(); + //self.UI('physicalWinButRender').define('icon','toggle-off'); + //self.UI('physicalWinButRender').refresh(); + self.physicalWin.render=false; + }}, + { view:"button", type:"icon", icon:"sitemap", tooltip:'Inspector', width:30, click:function () { + if (self.simuPhy && self.simuPhy.objects) { + self.inspect.data=self.simuPhy.objects; + self.deleteTree('PHY'); + self.makeTree(self.inspect.data,'root'); + self.UI('inspectorTree').close('root'); + } + + }}, + { view:"button", id:'physicalWinSave', type:"icon", icon:"save", tooltip:'Export simulation world to PNG', width:30, click:function () { + function snap() { + var image = Base64.decodeBuf(self.physicalWin.gui.exportImage().replace('data:image/png;base64,', '')); + return image; + }; + try { var len = Io.write_file_bin('Z:/tmp/simulation.png',snap()); + self.log('Exported physical world to /tmp/simulation.png ['+len+']'); } catch (e) { self.log(util.inspect(e)) }; + }}, + +/* + { view:"button", id:"physicalWinButRender", type:"icon", icon:"toggle-off", tooltip:'Render', width:30, click:function () { + if (!self.physicalWin.render) { + self.UI('physicalWinButRender').define('icon','toggle-on'); + self.UI('physicalWinButRender').refresh(); + self.physicalWin.render=true; + self.physicalWin.gui.enable(); + self.physicalWin.gui.animate(); + } else { + self.UI('physicalWinButRender').define('icon','toggle-off'); + self.UI('physicalWinButRender').refresh(); + self.physicalWin.render=false; + self.physicalWin.gui.disable(); + } + }}, +*/ + { view:"text", id:'physicalWinFormSteps', label:"Steps", value:'1', maxWidth:150}, + { view:"label", label:"Physical World", align:'right'}, + { view:"button", type:"icon", icon:"close", align:'center', width:30, click: function () { + self.physicalWin.hide(); + }} + ] + }, + body: { + template : '
', + borderless:false + } + }); + +a1461 28 + this.physicalWin.attachEvent("onViewResize", function(id){ + if (self.physicalWin.gui) { + self.physicalWin.gui.resize({width:self.physicalWin.getNode().offsetWidth-26, + height:self.physicalWin.getNode().offsetHeight-70}); + self.physicalWin.gui.animate1(); + } + }); + + + this.autoLayout(); + this.lockLayout(); + // window.update_timeout = null; + this.nwgui.Window.get().on('resize',function(x,y){ + var width = window.width; + var height = window.height; + /* + if(typeof(window.update_timeout) !== null){ + clearTimeout(window.update_timeout); + } + window.update_timeout = setTimeout(function(){ + // Do your required stuff here + },125); + */ + self.unlockLayout(); + self.autoLayout(); + self.lockLayout(); + }); +} +@ + + +1.1 +log +@Initial revision +@ +text +@d22 1 +a22 1 + ** $VERSION: 1.7.1 +d46 2 +a47 1 + +d113 1 +a113 1 + dirty:false, // JAM agent process copy/fork/migrate mode +d416 1 +a416 1 + dirty:self.options.simulation.dirty // Dirty (fast) JAM agent process copy? +d1318 2 +a1319 2 + this.stat('Nodes: '+stats.nodes); + this.stat('Agents: ('+stats.total+')'); +d1321 1 +a1321 1 + this.stat(Comp.printf.sprintf(' %10s : %4d (%d)',c,stats.agents[c]?stats.agents[c]:0,stats.agentsN[c])); +d1324 3 +a1326 1 + stats.create,stats.migrate,stats.fork,stats.dirty)); +d2147 11 +d2375 1 +a2375 1 + click: function (o) {self.options.simulation.dirty=Number(self.UI(o).getValue())==1;}}, +d2461 8 +@