diff --git a/client/source/class/cv/io/Client.js b/client/source/class/cv/io/Client.js index 085c182df4..f4c838d827 100644 --- a/client/source/class/cv/io/Client.js +++ b/client/source/class/cv/io/Client.js @@ -90,6 +90,8 @@ qx.Class.define('cv.io.Client', { this.pass = ''; this.device = ''; this.headers = {}; + + this.delayedRestart = qx.util.Function.debounce(this.restart.bind(this), 50); }, /* @@ -356,6 +358,15 @@ qx.Class.define('cv.io.Client', { } }, + addSubscription(address) { + if (!this.addresses.includes()) { + this.addresses.push(address); + if (this.isConnected()) { + this.delayedRestart(); + } + } + }, + /** * This function starts the communication by a login and then runs the * ongoing communication task diff --git a/client/source/class/cv/io/IClient.js b/client/source/class/cv/io/IClient.js index 4d5f8aa8bf..a7abfbfc89 100644 --- a/client/source/class/cv/io/IClient.js +++ b/client/source/class/cv/io/IClient.js @@ -99,12 +99,18 @@ qx.Interface.define('cv.io.IClient', { * Subscribe to the addresses in the parameter. The second parameter * (filter) is optional * - * @param addresses {Array?} addresses to subscribe to + * @param addresses {Array} addresses to subscribe to * @param filters {Array?} Filters * */ subscribe(addresses, filters) {}, + /** + * Add a single subscription + * @param address {String} + */ + addSubscription(address) {}, + /** * This function starts the communication by a login and then runs the * ongoing communication task diff --git a/doc/manual/de/config/structure-tile/components/_static/cv-power-entity-multiple.png b/doc/manual/de/config/structure-tile/components/_static/cv-power-entity-multiple.png index 71c4232d2b..eb89d20bf8 100644 Binary files a/doc/manual/de/config/structure-tile/components/_static/cv-power-entity-multiple.png and b/doc/manual/de/config/structure-tile/components/_static/cv-power-entity-multiple.png differ diff --git a/doc/manual/de/config/structure-tile/components/_static/cv-select-auto.png b/doc/manual/de/config/structure-tile/components/_static/cv-select-auto.png index 643e28749f..a924574ecb 100644 Binary files a/doc/manual/de/config/structure-tile/components/_static/cv-select-auto.png and b/doc/manual/de/config/structure-tile/components/_static/cv-select-auto.png differ diff --git a/doc/manual/de/config/structure-tile/components/_static/cv-select-comfort.png b/doc/manual/de/config/structure-tile/components/_static/cv-select-comfort.png index e9586eaac4..040edcbb25 100644 Binary files a/doc/manual/de/config/structure-tile/components/_static/cv-select-comfort.png and b/doc/manual/de/config/structure-tile/components/_static/cv-select-comfort.png differ diff --git a/doc/manual/de/config/structure-tile/components/_static/shot-index.json b/doc/manual/de/config/structure-tile/components/_static/shot-index.json index 17a6ae151b..89bfb5dd78 100644 --- a/doc/manual/de/config/structure-tile/components/_static/shot-index.json +++ b/doc/manual/de/config/structure-tile/components/_static/shot-index.json @@ -18,8 +18,8 @@ "tile-nav-menu-dock": "7dab3e8d4617fed50625a5a234fd036a", "tile-status-popup-closed": "1254594b451cf46fa77c5cdb7c5b5c16", "tile-status-popup-open": "f76da4ef8093fbadf8adab625a05ba92", - "cv-select-auto": "7271a35782383009c2d5ef16ee64155a", - "cv-select-comfort": "0d062cfbc4600b384ebd051e0b9fe4eb", + "cv-select-auto": "6d5d768d262e52aa254db545e8987c2e", + "cv-select-comfort": "cadc0f598dbc5c2169875625aa889471", "cv-slider-volume": "a24068c988bac68c219271c623b733da", "cv-spinner": "0ae12e5518898d6109217b6b643fd476", "cv-value-label": "3e02c9c1f32b0dca63ddb76c1cf6548f", @@ -56,7 +56,7 @@ "cv-power-entity-charger": "bee790df8a071d67df272a60c14dcb39", "cv-power-entity-heatpump": "7d4772e050e0ca91509dc9489fe18ec6", "cv-power-entity-battery-load": "4260226cdbb2b192680c7430a4e3209a", - "cv-power-entity-multiple": "7be9af6d18f7065a754b7a665794797f", + "cv-power-entity-multiple": "1f1de94c535f171de764222735d01de0", "cv-svg-text-value": "ba817d707ceffaac00bf13b855aecdbb", "cv-svg-text-value-title": "616e54d291b48ec81d962031bf8b7bb9", "cv-energy-entity-pv": "3c42710f18d52b6a25832714be1d6887", diff --git a/doc/manual/de/config/structure-tile/components/select.rst b/doc/manual/de/config/structure-tile/components/select.rst index 448be16c74..e4eb74aad1 100644 --- a/doc/manual/de/config/structure-tile/components/select.rst +++ b/doc/manual/de/config/structure-tile/components/select.rst @@ -11,10 +11,13 @@ Beschreibung Die Select-Komponente ermöglicht es einen Wert aus einer vorgegebenen Liste auszuwählen. Ein möglicher Anwendungsfall ist zum Beispiel die Auswahl des Betriebsmodus eines Raumtemperaturreglers. -Es wird der aktuell ausgewählte Wert angezeigt (sofern Icons benutzt werden, wird nur dieses angezeigt -ohne den zugehörigen Text) und bei Klick auf die Komponente öffnet sich die Liste +Es wird der aktuell ausgewählte Wert angezeigt und bei Klick auf die Komponente öffnet sich die Liste mit möglichen Werten aus der dann einer ausgewählt werden kann. +Über das ``show``-Attribut kann man festlegen ob von dem aktuell ausgewählten Wert nur das Icon (``show="icon"``), nur +den Text (``show="label"``) oder beides (``show="both"``) angezeigt wird. Wenn das Attribut nicht angegeben wird, +wird beides angezeigt. + .. widget-example:: @@ -29,19 +32,19 @@ mit möglichen Werten aus der dann einer ausgewählt werden kann. 1/4/2 - + ri-character-recognition-lineAuto - + ri-temp-cold-lineKomfort - + ri-shut-down-lineAus - + ri-leaf-lineEco - + ri-shield-lineFrostschutz diff --git a/doc/manual/de/config/structure-tile/elements/mapping.rst b/doc/manual/de/config/structure-tile/elements/mapping.rst index c2bb6d4f2c..750bfa805f 100644 --- a/doc/manual/de/config/structure-tile/elements/mapping.rst +++ b/doc/manual/de/config/structure-tile/elements/mapping.rst @@ -186,9 +186,9 @@ werden: .. code-block:: xml - Negativ + Negativ Null - Positiv + Positiv Bei genauer Betrachtung sieht man, dass die "0" drei mal vorkommt. Hier @@ -409,35 +409,35 @@ Für Wetterdaten in km/h: .. code-block:: xml - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 - Windstille - leiser Zug - leichte Brise - schwache Brise - maessige Brise - frische Brise - starker Wind - steifer Wind - stuermischer Wind - Sturm - schwerer Sturm - orkanartiker Sturm - Orkan + Windstille + leiser Zug + leichte Brise + schwache Brise + maessige Brise + frische Brise + starker Wind + steifer Wind + stuermischer Wind + Sturm + schwerer Sturm + orkanartiker Sturm + Orkan Für Wetterdaten in m/s: @@ -445,51 +445,51 @@ Für Wetterdaten in m/s: .. code-block:: xml - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 - Windstille - leiser Zug - leichte Brise - schwache Brise - maessige Brise - frische Brise - starker Wind - steifer Wind - stuermischer Wind - Sturm - schwerer Sturm - orkanartiger Sturm - Orkan + Windstille + leiser Zug + leichte Brise + schwache Brise + maessige Brise + frische Brise + starker Wind + steifer Wind + stuermischer Wind + Sturm + schwerer Sturm + orkanartiger Sturm + Orkan - Windstille - Keine Luftbewegung. Rauch steigt senkrecht empor - Geringer Wind - Kaum merklich. Rauch treibt leicht ab - Leichter Wind - Blätter rascheln. Wind im Gesicht spürbar - Schwacher Wind - Blätter und dünne Zweige bewegen sich, Wimpel werden gestreckt - Mäßiger Wind - Zweige bewegen sich, loses Papier wird vom Boden gehoben - Frischer Wind - Größere Zweige und Bäume bewegen sich, Wind deutlich hörbar - Starker Wind - Dicke Äste bewegen sich, hörbares Pfeifen an Drahtseilen, in Telefonleitungen - Steifer Wind - Bäume schwanken, Widerstand beim Gehen gegen den Wind - Stürmischer Wind - Große Bäume werden bewegt, Fensterläden werden geöffnet, Zweige brechen von Bäumen, beim Gehen erhebliche Behinderung - Sturm - Äste brechen, kleiner Schäden an Häusern, Ziegel und Rauchhauben werden von Dächern gehoben, Gartenmöbel werden umgeworfen und verweht, beim Gehen erhebliche Behinderung - schwerer Sturm - Bäume werden entwurzelt, Baumstämme brechen, Gartenmöbel werden weggeweht, größere Schäden an Häusern; selten im Landesinneren - orkanartiker Sturm - heftige Böen, schwere Sturmschäden, schwere Schäden an Wäldern (Windbruch), Dächer werden abgedeckt, Autos werden aus der Spur geworfen, dicke Mauern werden beschädigt, Gehen ist unmöglich; sehr selten im Landesinneren - Orkan - Schwerste Sturmschäden und Verwüstungen; sehr selten im Landesinneren + Windstille - Keine Luftbewegung. Rauch steigt senkrecht empor + Geringer Wind - Kaum merklich. Rauch treibt leicht ab + Leichter Wind - Blätter rascheln. Wind im Gesicht spürbar + Schwacher Wind - Blätter und dünne Zweige bewegen sich, Wimpel werden gestreckt + Mäßiger Wind - Zweige bewegen sich, loses Papier wird vom Boden gehoben + Frischer Wind - Größere Zweige und Bäume bewegen sich, Wind deutlich hörbar + Starker Wind - Dicke Äste bewegen sich, hörbares Pfeifen an Drahtseilen, in Telefonleitungen + Steifer Wind - Bäume schwanken, Widerstand beim Gehen gegen den Wind + Stürmischer Wind - Große Bäume werden bewegt, Fensterläden werden geöffnet, Zweige brechen von Bäumen, beim Gehen erhebliche Behinderung + Sturm - Äste brechen, kleiner Schäden an Häusern, Ziegel und Rauchhauben werden von Dächern gehoben, Gartenmöbel werden umgeworfen und verweht, beim Gehen erhebliche Behinderung + schwerer Sturm - Bäume werden entwurzelt, Baumstämme brechen, Gartenmöbel werden weggeweht, größere Schäden an Häusern; selten im Landesinneren + orkanartiker Sturm - heftige Böen, schwere Sturmschäden, schwere Schäden an Wäldern (Windbruch), Dächer werden abgedeckt, Autos werden aus der Spur geworfen, dicke Mauern werden beschädigt, Gehen ist unmöglich; sehr selten im Landesinneren + Orkan - Schwerste Sturmschäden und Verwüstungen; sehr selten im Landesinneren Windrichtung @@ -498,21 +498,21 @@ Windrichtung .. code-block:: xml - Nord - Nordnordost - Nordost - Ostnordost - Ost - Ostsüdost - Südost - Südsüdost - Süd - Südsüdwest - Südwest - Westsüdwest - West - Westnordwest - Nordwest - Nordnordwest - Nord + Nord + Nordnordost + Nordost + Ostnordost + Ost + Ostsüdost + Südost + Südsüdost + Süd + Südsüdwest + Südwest + Westsüdwest + West + Westnordwest + Nordwest + Nordnordwest + Nord diff --git a/doc/manual/de/config/structure-tile/elements/styling.rst b/doc/manual/de/config/structure-tile/elements/styling.rst index 78d63d113d..e4eca463b3 100644 --- a/doc/manual/de/config/structure-tile/elements/styling.rst +++ b/doc/manual/de/config/structure-tile/elements/styling.rst @@ -127,9 +127,9 @@ Im folgenden Beispiel wie folgt: .. code-block:: xml - blue + blue purple - red + red .. IMPORTANT:: diff --git a/source/class/cv/Transform.js b/source/class/cv/Transform.js index 6a0740603f..dfc9220a4b 100644 --- a/source/class/cv/Transform.js +++ b/source/class/cv/Transform.js @@ -133,7 +133,7 @@ qx.Class.define('cv.Transform', { /** * transform JavaScript to bus value and raw value * - * @param {{transform: string, selector: string?, ignoreError: string?, variantInfo: string?}} address - type of the transformation, as address object + * @param {{transform: string, selector?: string, ignoreError?: string, variantInfo?: string}} address - type of the transformation, as address object * @param {*} value - value to transform * @return {*} object with both encoded values */ @@ -175,7 +175,7 @@ qx.Class.define('cv.Transform', { /** * transform JavaScript to bus value * - * @param {{transform: string, selector: string?, ignoreError: string?}} address - type of the transformation, as address object + * @param {{transform: string, selector?: string, ignoreError?: string}} address - type of the transformation, as address object * @param {*} value - value to transform * @return {*} the encoded value */ @@ -185,7 +185,7 @@ qx.Class.define('cv.Transform', { /** * transform bus to JavaScript value - * @param {{transform: string, selector: string?, ignoreError: string?, variantInfo: string?}} address - type of the transformation, as address object + * @param {{transform: string, selector?: string, ignoreError?: string, variantInfo?: string}} address - type of the transformation, as address object * @param {*} value - value to transform * @return {*} the decoded value */ diff --git a/source/class/cv/data/Model.js b/source/class/cv/data/Model.js index dc44a2e880..3af596712b 100644 --- a/source/class/cv/data/Model.js +++ b/source/class/cv/data/Model.js @@ -202,6 +202,11 @@ qx.Class.define('cv.data.Model', { this.__stateListeners[backendName][address] = []; } this.__stateListeners[backendName][address].push([callback, context]); + + const backend = cv.io.BackendConnections.getClient(backendName); + if (backend && backend.isConnected()) { + backend.addSubscription(address); + } }, /** diff --git a/source/class/cv/io/Mockup.js b/source/class/cv/io/Mockup.js index 86817cda17..f9ae149c2e 100644 --- a/source/class/cv/io/Mockup.js +++ b/source/class/cv/io/Mockup.js @@ -143,6 +143,12 @@ qx.Class.define('cv.io.Mockup', { } }, + addSubscription(address) { + if (!this.addresses.includes(address)) { + this.addresses.push(address); + } + }, + __decode(address, value) { if (/\d{1,2}\/\d{1,2}\/\d{1,2}/.test(address)) { if (/^[\da-fA-F]+$/.test(value)) { diff --git a/source/class/cv/io/System.js b/source/class/cv/io/System.js index 9d7fe43f3f..43c06a240d 100644 --- a/source/class/cv/io/System.js +++ b/source/class/cv/io/System.js @@ -114,6 +114,12 @@ qx.Class.define('cv.io.System', { } }, + addSubscription(address) { + if (!this.addresses.includes(address)) { + this.addresses.push(address); + } + }, + write(address, value, options) { if (address) { const parts = address.split(':'); diff --git a/source/class/cv/io/mqtt/Client.js b/source/class/cv/io/mqtt/Client.js index bf0d675026..b88a0f5dfe 100644 --- a/source/class/cv/io/mqtt/Client.js +++ b/source/class/cv/io/mqtt/Client.js @@ -69,6 +69,7 @@ qx.Class.define('cv.io.mqtt.Client', { */ _client: null, _type: null, + addresses: null, /** * Returns the current backend configuration @@ -129,9 +130,17 @@ qx.Class.define('cv.io.mqtt.Client', { * */ subscribe(addresses, filters) { + this.addresses = addresses ? addresses : []; addresses.forEach(value => this._client.subscribe(value)); }, + addSubscription(address) { + if (!this.addresses.includes(address)) { + this.addresses.push(address); + this._client.subscribe(address); + } + }, + /** * This function starts the communication by a login and then runs the * ongoing communication task diff --git a/source/class/cv/io/openhab/Rest.js b/source/class/cv/io/openhab/Rest.js index c26c3edb13..99275adc74 100644 --- a/source/class/cv/io/openhab/Rest.js +++ b/source/class/cv/io/openhab/Rest.js @@ -331,6 +331,14 @@ qx.Class.define('cv.io.openhab.Rest', { } }, + addSubscription(address) { + if (!this.__subscribedAddresses) { + this.__subscribedAddresses = [address]; + } else if (!this.__subscribedAddresses.includes(address)) { + this.__subscribedAddresses.push(address); + } + }, + terminate() { this.debug('terminating connection'); if (this.eventSource) { diff --git a/source/class/cv/ui/structure/tile/components/Button.js b/source/class/cv/ui/structure/tile/components/Button.js index b44a097279..1d33a8def0 100644 --- a/source/class/cv/ui/structure/tile/components/Button.js +++ b/source/class/cv/ui/structure/tile/components/Button.js @@ -105,6 +105,7 @@ qx.Class.define('cv.ui.structure.tile.components.Button', { * @var {Map} value store for addresses to be able to use them e.g. in mapping formulas */ __store: null, + _triggerOnValue: null, _parseInt(val) { const intVal = parseInt(val); @@ -189,6 +190,7 @@ qx.Class.define('cv.ui.structure.tile.components.Button', { this.onClicked(ev); }); } + let triggerAddresses = []; if (hasReadAddress) { element.addEventListener('stateUpdate', ev => { this.onStateUpdate(ev); @@ -197,29 +199,36 @@ qx.Class.define('cv.ui.structure.tile.components.Button', { }); } else if (element.hasAttribute('mapping') || element.hasAttribute('styling')) { // apply the trigger state - const triggerAddresses = writeAddresses.filter(addr => addr.hasAttribute('value') && !addr.hasAttribute('on')); - - if (triggerAddresses.length === 1) { - const value = triggerAddresses[0].getAttribute('value'); - qx.event.Timer.once( - () => { - // using == comparisons to make sure that e.g. 1 equals "1" - // noinspection EqualityComparisonWithCoercionJS - this.setOn(value == this.getOnValue()); - }, - this, - 1000 - ); - } + triggerAddresses = writeAddresses.filter(addr => addr.hasAttribute('value') && !addr.hasAttribute('on')); } // detect button type if ( !hasReadAddress && - writeAddresses.filter(addr => addr.hasAttribute('value') && !addr.hasAttribute('on')).length === 1 + triggerAddresses.length === 1 ) { // only one write address with a fixed value and no special event => simple trigger this.setType('trigger'); + + if (!element.hasAttribute('on-value')) { + // we consider the trigger address value as on-value when no one is given + this._triggerOnValue = triggerAddresses[0].getAttribute('value'); + } else { + this._triggerOnValue = this.getOnValue(); + } + + const value = triggerAddresses[0].getAttribute('value'); + qx.event.Timer.once( + () => { + // set it to the opposite of what is being sent when clicked to make the feedback simulation work + // e.g. value="1", trigger is off and when clicked for a short amount of time in on state, + // using == comparisons to make sure that e.g. 1 equals "1" + // noinspection EqualityComparisonWithCoercionJS + this.setOn(value != this._triggerOnValue); + }, + this, + 1000 + ); } else { let hasDown = false; let hasUp = false; @@ -410,20 +419,24 @@ qx.Class.define('cv.ui.structure.tile.components.Button', { } }); + const wa = this._writeAddresses + .filter(addr => !addr.hasAttribute('on') || addr.getAttribute('on') === 'click'); + if (this.getType() === 'trigger') { // simulate feedback - this.setOn(true); + // using == comparisons to make sure that e.g. 1 equals "1" + // noinspection EqualityComparisonWithCoercionJS + const simulatedValue = wa[0].getAttribute('value') == this._triggerOnValue; + this.setOn(simulatedValue); qx.event.Timer.once( () => { - this.setOn(false); + this.setOn(!simulatedValue); }, null, - 250 + 500 ); } - this._writeAddresses - .filter(addr => !addr.hasAttribute('on') || addr.getAttribute('on') === 'click') - .forEach(address => address.dispatchEvent(ev)); + wa.forEach(address => address.dispatchEvent(ev)); event.stopPropagation(); } }, diff --git a/source/class/cv/ui/structure/tile/components/Select.js b/source/class/cv/ui/structure/tile/components/Select.js index e119215bc4..2bd27e2feb 100644 --- a/source/class/cv/ui/structure/tile/components/Select.js +++ b/source/class/cv/ui/structure/tile/components/Select.js @@ -23,6 +23,19 @@ qx.Class.define('cv.ui.structure.tile.components.Select', { extend: cv.ui.structure.tile.components.AbstractComponent, + /* + *********************************************** + PROPERTIES + *********************************************** + */ + properties: { + show: { + check: ['icon', 'label', 'both'], + init: 'both', + apply: '_applyShow' + } + }, + /* *********************************************** MEMBERS @@ -61,8 +74,30 @@ qx.Class.define('cv.ui.structure.tile.components.Select', { } }, - onClicked(ev) { + _toggleOptions(close) { + // open popup const style = getComputedStyle(this.__popup); + if (style.getPropertyValue('display') === 'none' && !close) { + this.__popup.style.display = 'block'; + window.requestAnimationFrame(() => { + // delay adding this listener, otherwise it would fire immediately + // also the native addEventListener does not allow the listener to be re-added once removed, so we use the qx way here + // which works fine + qx.event.Registration.addListener(document.body, 'click', this.handleEvent, this, true); + }); + } else { + this.__popup.style.display = 'none'; + qx.event.Registration.removeListener(document.body, 'click', this.handleEvent, this, true); + } + }, + + handleEvent(ev) { + ev.preventDefault(); + ev.stopPropagation(); + this._toggleOptions(true); + }, + + onClicked(ev) { let target = ev.target; // find out event target (either the cv-select of cv-option while (target !== ev.currentTarget && target.tagName.toLowerCase() !== 'cv-option') { @@ -72,12 +107,7 @@ qx.Class.define('cv.ui.structure.tile.components.Select', { // select this option this._sendSelection(target.getAttribute('key'), true); } - // open popup - if (style.getPropertyValue('display') === 'none') { - this.__popup.style.display = 'block'; - } else { - this.__popup.style.display = 'none'; - } + this._toggleOptions(); }, _sendSelection(key, predictive) { @@ -97,18 +127,39 @@ qx.Class.define('cv.ui.structure.tile.components.Select', { }, _updateValue(mappedValue, value) { - if (this.__options.has(mappedValue)) { + const key = typeof mappedValue !== 'undefined' ? '' + mappedValue : ''; + if (this.__options.has(key)) { this.__value.innerHTML = ''; - const current = this.__options.get(mappedValue); - if (current.children.length > 0) { - // if we have non text children, we only use them (only icons no text) - for (const child of current.children) { - this.__value.appendChild(child.cloneNode()); - } - } else { - this.__value.innerHTML = current.innerHTML; + const current = this.__options.get(key); + switch (this.getShow()) { + case 'icon': + // if we have non text children, we only use them (only icons no text) + for (const child of current.children) { + if (child.nodeName.toLowerCase() === 'cv-icon') { + this.__value.appendChild(child.cloneNode()); + } + } + break; + + case 'label': + for (const child of current.childNodes) { + if (child.nodeType === Node.TEXT_NODE || (child.nodeType === Node.ELEMENT_NODE && child.nodeName.toLowerCase() === 'label')) { + this.__value.appendChild(child.cloneNode()); + } + } + break; + + case 'both': + this.__value.innerHTML = current.innerHTML; + break; } } + }, + + _applyShow(show) { + if (this.getValue()) { + this._updateValue(this.getValue()); + } } }, @@ -116,6 +167,7 @@ qx.Class.define('cv.ui.structure.tile.components.Select', { customElements.define( cv.ui.structure.tile.Controller.PREFIX + 'select', class extends QxConnector { + static observedAttributes = ['show']; constructor() { super(QxClass); } diff --git a/source/resource/designs/tile/basic.scss b/source/resource/designs/tile/basic.scss index 4d8ff11c12..61f45c7c02 100644 --- a/source/resource/designs/tile/basic.scss +++ b/source/resource/designs/tile/basic.scss @@ -714,25 +714,25 @@ body { } } &[size="2x1"] { - width: calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing)); + width: min(calc(100vw - var(--spacing)*3), calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing))); } &[size="2x1.5"] { - width: calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing)); + width: min(calc(100vw - var(--spacing)*3), calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing))); height: calc(var(--tileCellHeight) * #{$tileRows} * 1.5 + var(--spacing)); } &[size="2x2"] { - width: calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing)); + width: min(calc(100vw - var(--spacing)*3), calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing))); height: calc(var(--tileCellHeight) * #{$tileRows} * 2 + var(--spacing)); } &[size="1x2"] { height: calc(var(--tileCellHeight) * #{$tileRows} * 2 + var(--spacing)); } &[size="2x4"] { - width: calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing)); + width: min(calc(100vw - var(--spacing)*3), calc(var(--tileCellWidth) * #{$tileColumns} * 2 + var(--spacing))); height: calc(var(--tileCellHeight) * #{$tileRows} * 4 + var(--spacing) * 3); } &[size="4x2"] { - width: min(100vw, calc(var(--tileCellWidth) * #{$tileColumns} * 4 + var(--spacing))); + width: min(calc(100vw - var(--spacing)*3), min(100vw, calc(var(--tileCellWidth) * #{$tileColumns} * 4 + var(--spacing)))); height: calc(var(--tileCellHeight) * #{$tileRows} * 2 + var(--spacing) * 3); } } @@ -1536,8 +1536,7 @@ body { cv-select { position: relative; width: 100%; - border-top: 1px solid var(--borderColor); - border-bottom: 1px solid var(--borderColor); + height: 100%; .value { margin: 0; @@ -1559,6 +1558,11 @@ body { padding: calc(var(--spacing)/2) var(--spacing); vertical-align: middle; font-size: 18px; + cursor: pointer; + + &:hover { + color: var(--primaryColor); + } } } diff --git a/source/resource/structures/tile/templates.xml b/source/resource/structures/tile/templates.xml index ea3e52a7d1..c03c0938f6 100644 --- a/source/resource/structures/tile/templates.xml +++ b/source/resource/structures/tile/templates.xml @@ -10,10 +10,10 @@ ri-stop-fill - + 0 ? Math.round(100/d*x) : 0; - + y = d > 0 && x <= d ? Math.round(100/d*x) : 0; + ]]> inactive @@ -207,7 +207,7 @@

- + NEEDS ADDRESS ri-character-recognition-lineAuto diff --git a/source/resource/visu_config_tile.xsd b/source/resource/visu_config_tile.xsd index d060c0b5a6..d1dc5577a3 100644 --- a/source/resource/visu_config_tile.xsd +++ b/source/resource/visu_config_tile.xsd @@ -701,6 +701,18 @@ level:expert + + + Value of the "on" state. Defaults to "1". + Wert für den An-Zustand. Default ist "1". + + + + + Value of the "off" state. Defaults to "0". + Wert für den Aus-Zustand. Default ist "0". + + @@ -955,6 +967,19 @@ + + + Defines which content of the selection option should be shown ("both": icon and label, "icon": only the icon, "label": only the label). + Gibt an was von der selektierten Option angezeigt werden soll ("both": Icon und Text, "icon": nur das Icon, "text" nur der Text. + + + + + + + + +