From 2ff7bf9b8aab1c5addeafae2ad86ead5e684f19e Mon Sep 17 00:00:00 2001 From: STEINNI Date: Mon, 20 Oct 2025 14:33:13 +0000 Subject: [PATCH] bz-toggler --- app/assets/json/global/services.json | 8 ++ app/assets/styles/app.css | 8 +- app/controllers/editors/EditorsController.js | 1 - app/controllers/live/DashboardsController.js | 8 +- app/models/AgentsModel.js | 18 ++++ app/thirdparty/buildoz/buildoz.css | 79 +++++++++++++++- app/thirdparty/buildoz/buildoz.js | 94 ++++++++++++++++++- app/views/editors/KeyframeView.html | 5 +- app/views/editors/KeyframeView.js | 63 +++++++++++-- .../editors/modules/agentPreview.module.js | 12 ++- core/libs/MessageBusWorker.js | 2 +- 11 files changed, 272 insertions(+), 26 deletions(-) diff --git a/app/assets/json/global/services.json b/app/assets/json/global/services.json index f966c7c..bf0f72f 100644 --- a/app/assets/json/global/services.json +++ b/app/assets/json/global/services.json @@ -3,9 +3,17 @@ "error": "", "payload": { "/agents": { + "getTypes": { + "uri": "/api/agent-types/{family}", + "method": "GET" + }, "getSprites": { "uri": "/api/agent-sprites/{group}", "method": "GET" + }, + "getProperties": { + "uri": "/api/agent/{id}", + "method": "GET" } } } diff --git a/app/assets/styles/app.css b/app/assets/styles/app.css index 226ee48..396d745 100755 --- a/app/assets/styles/app.css +++ b/app/assets/styles/app.css @@ -331,7 +331,10 @@ menu[eicmenu] [menuitem] a label { menu[eicmenu] [menuitem] i[class^="icon-"] { color:#fdfb93;; } +article[eiccard] > header h1{ text-align: center; } + +/* Customizations to buildoz*/ bz-select > button{ background: linear-gradient( to bottom, #251, #372 15%, #483 50%, #372 85%, #251 ) !important; color:#EEE; @@ -343,4 +346,7 @@ bz-select option{ } bz-select option:hover{ background-color: #493; -} \ No newline at end of file +} + +bz-toggler div.toggle-switch span.toggle-bar { background-color: #473; } +bz-toggler div.toggle-switch span.toggle-thumb { background-color:#9D8; } \ No newline at end of file diff --git a/app/controllers/editors/EditorsController.js b/app/controllers/editors/EditorsController.js index 6d5205c..f83a309 100644 --- a/app/controllers/editors/EditorsController.js +++ b/app/controllers/editors/EditorsController.js @@ -6,7 +6,6 @@ class EditorsController extends WindozController { constructor(params) { super(params) this.arenaConfig = app.Assets.Store.json.arenaConfig - this.agentDefs = app.Assets.Store.json.agentDefs this.eventsMapping = app.Assets.Store.json.eventsMapping } diff --git a/app/controllers/live/DashboardsController.js b/app/controllers/live/DashboardsController.js index ca398a4..8c1a035 100644 --- a/app/controllers/live/DashboardsController.js +++ b/app/controllers/live/DashboardsController.js @@ -26,9 +26,9 @@ class DashboardsController extends WindozController { grid: true, }) - this.agentDefs = await models.agents.getSprites('Basic 3D') - const a1 = ttb.createAgent('agent42', this.agentDefs.nocode1) - const a2 = ttb.createAgent('agent42', this.agentDefs.nocode2) + this.agentSprites = await models.agents.getSprites('Basic 3D') + const a1 = ttb.createAgent('agent42', this.agentSprites.find(item => item.atp_name=='nocode1').atp_3d) + const a2 = ttb.createAgent('agent42', this.agentSprites.find(item => item.atp_name=='nocode1').atp_3d) ttb.scene.add(a1) ttb.scene.add(a2) @@ -46,7 +46,6 @@ class DashboardsController extends WindozController { }, { models: models, - agentDefs: this.agentDefs, rendererId:'3drenderer', mode: '3D', ttb: ttb, @@ -65,7 +64,6 @@ class DashboardsController extends WindozController { }, { models: models, - agentDefs: this.agentDefs, rendererId:'2drenderer', mode: '2D', ttb: ttb, diff --git a/app/models/AgentsModel.js b/app/models/AgentsModel.js index 450fbf6..23b4044 100644 --- a/app/models/AgentsModel.js +++ b/app/models/AgentsModel.js @@ -5,6 +5,15 @@ class AgentsModel extends WindozModel { this.ressource = '/agents' } + async getTypes(family) { + let endpoint = app.config.api[this.ressource].getTypes + endpoint.uri = endpoint.uri.replace('{family}', family) + return ( + this.request(endpoint.uri, endpoint.method) + .then( async serverData => serverData.payload.agentTypes) + ) + } + async getSprites(group) { let endpoint = app.config.api[this.ressource].getSprites endpoint.uri = endpoint.uri.replace('{group}', group) @@ -13,6 +22,15 @@ class AgentsModel extends WindozModel { .then( async serverData => serverData.payload.agentSprites) ) } + + async getProperties(id) { + let endpoint = app.config.api[this.ressource].getProperties + endpoint.uri = endpoint.uri.replace('{id}', id) + return ( + this.request(endpoint.uri, endpoint.method) + .then( async serverData => serverData.payload.agentProperties) + ) + } } app.registerClass('AgentsModel', AgentsModel); \ No newline at end of file diff --git a/app/thirdparty/buildoz/buildoz.css b/app/thirdparty/buildoz/buildoz.css index 161bf18..25585b8 100644 --- a/app/thirdparty/buildoz/buildoz.css +++ b/app/thirdparty/buildoz/buildoz.css @@ -1,6 +1,13 @@ bz-select { display: block; margin: .5rem 0 .5rem 0; + position:relative; +} +bz-select[disabled] > button{ + opacity: 0.6; + cursor: not-allowed; + pointer-events: none; + filter: grayscale(30%); } bz-select > button{ width:100%; @@ -16,7 +23,7 @@ bz-select > button::after { content: "\00BB"; transform: rotate(90deg) translateX(-0.4rem); position: absolute; - right: 1.5rem; + right: 0.5rem; pointer-events: none; font-size: 1.5rem; color: #444; @@ -45,4 +52,74 @@ bz-select option.open{ bz-select option:hover{ background-color: #44F; color: #FFF; +} + + + + +bz-toggler{ + outline: none; + min-height: 1.5rem; + padding: 0.75rem !important; + display: inline-table; + max-width: fit-content; + transition: all 0.5s; +} +bz-toggler div.toggle-label-left{ + padding-right: 0.3rem; + display: table-cell; + vertical-align: middle; + text-align: right; + font-size:.8rem; +} +bz-toggler div.toggle-label-right{ + padding-left: 0.3rem; + display: table-cell; + vertical-align: middle; + text-align: left; + font-size:.8rem; +} +bz-toggler div.toggle-switch{ + user-select: none; + height: inherit; + cursor: pointer; + display: table-cell; + vertical-align: middle; + text-align: center; +} +bz-toggler div.toggle-switch span.toggle-bar { + display: inline-block; + position: relative; + background-color: #CCC; +} + +bz-toggler div.toggle-switch span.toggle-thumb { + display: inline-block; + border-radius: 50%; + background-color: white; + position: absolute; + z-index: 1; +} + +bz-toggler div.toggle-switch span.toggle-thumb:not(.turned-on) { + left: 0; + transition: all 0.4s; +} +bz-toggler div.toggle-switch span.toggle-thumb.turned-on { + transition: all 0.4s; +} +bz-toggler div.toggle-switch span.toggle-bar { + width: 2rem; + height: 0.75rem; + border-radius: .75rem; +} + +bz-toggler div.toggle-switch span.toggle-thumb { + height: 1rem; + width: 1rem; + top: -0.1rem; +} + +bz-toggler div.toggle-switch span.toggle-thumb.turned-on { + left : 1rem; } \ No newline at end of file diff --git a/app/thirdparty/buildoz/buildoz.js b/app/thirdparty/buildoz/buildoz.js index 207ed71..70555aa 100644 --- a/app/thirdparty/buildoz/buildoz.js +++ b/app/thirdparty/buildoz/buildoz.js @@ -32,6 +32,10 @@ class Buildoz extends HTMLElement { attributeChangedCallback(name, oldValue, newValue) { this.attrs[name] = newValue } + + getBZAttribute(attrName){ // Little helper for defaults + return(this.getAttribute(attrName) || this.defaultAttrs[attrName] ) + } } class BZselect extends Buildoz { @@ -47,7 +51,7 @@ class BZselect extends Buildoz { connectedCallback() { super.connectedCallback() this.button = document.createElement('button') - this.button.textContent = this.getAttribute('label') || this.defaultAttrs.label + this.button.textContent = this.getBZAttribute('label') this.prepend(this.button) this.button.addEventListener('click', this.toggle.bind(this)) this.options = this.querySelectorAll('option') @@ -58,9 +62,9 @@ class BZselect extends Buildoz { } // static get observedAttributes(){ // Only if you want actions on attr change - // return([...super.observedAttributes, 'myattr']) + // return([...super.observedAttributes, 'disabled']) // } - // + // attributeChangedCallback(name, oldValue, newValue) { // super.attributeChangedCallback(name, oldValue, newValue) // } @@ -79,11 +83,12 @@ class BZselect extends Buildoz { } onOption(value, silent=false){ + if(this.getAttribute('disabled') !== null) return this.value = value if(!silent) this.toggle() const opt = Array.from(this.options).find(opt => opt.value==value) if(value || (opt && opt.textContent)) this.button.textContent = opt.textContent - else this.button.textContent = this.getAttribute('label') || this.defaultAttrs.label + else this.button.textContent = this.getBZAttribute('label') this.dispatchEvent(new Event('change', { bubbles: true, composed: false, @@ -109,5 +114,84 @@ class BZselect extends Buildoz { for(const opt of opts) this.addOption(opt.value, opt.markup) } } +Buildoz.define('select', BZselect) -Buildoz.define('select', BZselect) \ No newline at end of file + +class BZtoggler extends Buildoz { + constructor(){ + super() + this.value = null + this.open = false + this.defaultAttrs = { + labelLeft:'', + labelRight:'', + trueValue: 'yes', + falseValue: 'no', + classOn:'', + classOff:'', + tabindex:0, + disabled:false + } + } + + connectedCallback(){ + super.connectedCallback() + + this.labelRight = document.createElement('div') + this.labelRight.classList.add('toggle-label-right') + this.labelRight.innerHTML = this.getBZAttribute('labelRight') + + this.labelLeft = document.createElement('div') + this.labelLeft.classList.add('toggle-label-left') + this.labelLeft.innerHTML = this.getBZAttribute('labelLeft') + + this.switch = document.createElement('div') + this.switch.classList.add('toggle-switch') + + this.toggleBar = document.createElement('span') + this.toggleBar.classList.add('toggle-bar') + + this.thumb = document.createElement('span') + this.thumb.classList.add('toggle-thumb') + this.toggleBar.append(this.thumb) + + this.switch.append(this.toggleBar) + + this.appendChild(this.labelLeft) + this.appendChild(this.switch) + this.appendChild(this.labelRight) + this.setAttribute('tabindex', this.getBZAttribute('tabindex')) + + this.switch.addEventListener('click', this.toggle.bind(this)) + + } + + turnOn() { + if(this.getBZAttribute('classOff')) this.switch.classList.remove(this.getBZAttribute('classOff')) + if(this.getBZAttribute('classOn')) this.switch.classList.add(this.getBZAttribute('classOn')) + this.thumb.classList.add('turned-on') + this.value = this.getBZAttribute('trueValue') + this.focus() + } + + turnOff() { + if(this.getBZAttribute('classOn')) this.switch.classList.remove(this.getBZAttribute('classOn')) + if(this.getBZAttribute('classOff'))this.switch.classList.add(this.getBZAttribute('classOff')) + this.thumb.classList.remove('turned-on') + this.value = this.getBZAttribute('falseValue') + this.focus() + } + + toggle(event) { + if(event) { event.preventDefault(); event.stopPropagation(); } + if(this.getBZAttribute('disabled')) return + if(this.value == this.getBZAttribute('trueValue')) this.turnOff() + else this.turnOn() + this.dispatchEvent(new Event('change', { + bubbles: true, + composed: false, + cancelable: false + })) + } +} +Buildoz.define('toggler', BZtoggler) diff --git a/app/views/editors/KeyframeView.html b/app/views/editors/KeyframeView.html index e43e1b5..ac17fec 100644 --- a/app/views/editors/KeyframeView.html +++ b/app/views/editors/KeyframeView.html @@ -23,10 +23,13 @@
Arena + + +
-
Properties
+

Agent properties

Props form
diff --git a/app/views/editors/KeyframeView.js b/app/views/editors/KeyframeView.js index a95ed74..237b3ea 100644 --- a/app/views/editors/KeyframeView.js +++ b/app/views/editors/KeyframeView.js @@ -21,23 +21,74 @@ class KeyframeView extends WindozDomContent { this.setupTriggers(components) this.setupRefs(components) - this.agentDefs = await this.models.agents.getSprites('Basic 3D') - this.outputs.agentsSelector.fillOptions( Object.keys(this.agentDefs).map(aname => { - console.log(this.agentDefs[aname]) - return({ markup: `${aname}`, value: aname}) + const [sprites, types] = await Promise.all([ + this.models.agents.getSprites('Basic 3D'), + this.models.agents.getTypes('Test agents') + ]) + + this.agentSprites = sprites + this.agentTypes = types + + + this.outputs.agentsSelector.fillOptions( this.agentTypes.map(item => { + return({ markup: `${item.atp_name}`, value: item.atp_id}) })) this.outputs.agentsSelector.addEventListener('change',this.onChangeAgent.bind(this)) - this.agentPreview = new app.LoadedModules.AgentPreview(this.outputs.agentSampleCanvas, this.agentDefs) + this.agentPreview = new app.LoadedModules.AgentPreview(this.outputs.agentSampleCanvas, this.agentSprites) this.onChangeAgent() this.agentPreview.startRendering() this.agentPreview.animation = true + + + this.outputs.testToggler.addEventListener('change',(e)=> { + console.log(e.target.value, e) + + }) } - onChangeAgent(event){ + async onChangeAgent(event){ if(this.outputs.agentsSelector.value) this.agentPreview.setAgent(this.outputs.agentsSelector.value) + if(!this.outputs.agentsSelector.value) return + const agent = await this.models.agents.getProperties(this.outputs.agentsSelector.value) + this.fillAgentProperties(agent.atp_props) + } + + fillAgentProperties(agentProps){ + for(const propName in agentProps){ + const fieldRow = ui.create(`
`) + let component + switch(agentProps[propName].type){ + case 'number': + component = document.createElement('input') + component.setAttribute('type','number') + if(agentProps[propName].min) component.setAttribute('min', agentProps[propName].min) + if(agentProps[propName].max) component.setAttribute('max', agentProps[propName].max) + component.value = agentProps[propName].default + break + case 'string': + component = document.createElement('input') + component.setAttribute('type','text') + break + case 'boolean': + component = new InputToggler({ + value: agentProps[propName].default, + }) + fieldRow.append(component.el) + break + case 'list': + component = document.createElement('bz-select') + component.fillOptions( agentProps[propName].choices.map(item => { + return({ markup: `${item}`, value: item}) + })) + break + default: + console.warn(`Unknown field type ${agentProps[propName].type}`) + } + fieldRow.append(component) + } } } diff --git a/app/views/editors/modules/agentPreview.module.js b/app/views/editors/modules/agentPreview.module.js index a467845..8693b07 100644 --- a/app/views/editors/modules/agentPreview.module.js +++ b/app/views/editors/modules/agentPreview.module.js @@ -4,11 +4,11 @@ import * as TWEEN from '/app/thirdparty/Three/tween.module.js' export class AgentPreview{ - constructor(canvasEl, agentDefs){ + constructor(canvasEl, agentSprites){ Object.assign(this, app.helpers.helpers3D) - this.agentDefs = app.Assets.Store.json.agentDefs + this.agentSprites = app.Assets.Store.json.agentSprites this.canvasEl = canvasEl - this.agentDefs = agentDefs + this.agentSprites = agentSprites this.currentAgentObj = null this.renderer = null this._animation = false @@ -41,11 +41,13 @@ export class AgentPreview{ this.renderer.render(this.scene, this.camera) } - setAgent(atype){ + setAgent(id){ if(this.currentAgentObj && (this.scene.children.includes(this.currentAgentObj))){ this.scene.remove(this.currentAgentObj) } - this.currentAgentObj = this.agentFromJSON('previewedAgent', this.agentDefs[atype]) + const agentSprite = this.agentSprites.find(item => item.atp_id==id) + if(!agentSprite) return + this.currentAgentObj = this.agentFromJSON('previewedAgent', agentSprite.asp_3d) this.currentAgentObj.position.set(0, 0, 0) this.scene.add(this.currentAgentObj) diff --git a/core/libs/MessageBusWorker.js b/core/libs/MessageBusWorker.js index 6fe8f0c..09042bf 100755 --- a/core/libs/MessageBusWorker.js +++ b/core/libs/MessageBusWorker.js @@ -99,7 +99,7 @@ class MessageBusWorker { } if((data.action=='PING') && this.keepAlive){ // Keep Alive is managed here - this.clientActionDispatch({'action':'PONG'}); + this.clientActionDispatch({'action':'PONG', 'reqid':data.reqid}); return }