diff --git a/dash-apps/web-compose/core/demo.js b/dash-apps/web-compose/core/demo.js index bde35c8..a9ed6f0 100644 --- a/dash-apps/web-compose/core/demo.js +++ b/dash-apps/web-compose/core/demo.js @@ -26,6 +26,7 @@ fusedSpeedLimit: t % 30 < 15 ? 90 : 130, gear: 4, adasOn: t > 6, + egoSteeringAngle: Math.sin(t * 0.5) * 45, leftBlinker: blinkPhase > 4 && blinkPhase < 7 ? 1 : 0, rightBlinker: blinkPhase > 12 && blinkPhase < 15 ? 1 : 0, leftBlindSpot: blinkPhase > 4.5 && blinkPhase < 6 ? 1 : 0, diff --git a/dash-apps/web-compose/core/editor.js b/dash-apps/web-compose/core/editor.js index 2297558..9d0b7c1 100644 --- a/dash-apps/web-compose/core/editor.js +++ b/dash-apps/web-compose/core/editor.js @@ -465,9 +465,10 @@ body.appendChild(field(t("editor.type"), typeControl(item))); - if ((descriptor.binds || []).length) { + const binds = (descriptor.binds || []).filter((bind) => !bind.hidden); + if (binds.length) { body.appendChild(el("h3", "sheet__section", t("editor.shows"))); - for (const bind of descriptor.binds) { + for (const bind of binds) { const label = bind.name ? DC.i18n.localized(bind.name) : t("editor.shows"); body.appendChild(field(label, bindControl(item, bind, refresh))); } diff --git a/dash-apps/web-compose/widgets/_generated.css b/dash-apps/web-compose/widgets/_generated.css index b170b6e..a76b97c 100644 --- a/dash-apps/web-compose/widgets/_generated.css +++ b/dash-apps/web-compose/widgets/_generated.css @@ -75,7 +75,7 @@ width: clamp(16px, 48cqmin, 120px); height: clamp(16px, 48cqmin, 120px); fill: var(--track); - transition: fill 120ms linear, filter 120ms linear; + transition: fill 120ms linear, filter 120ms linear, transform 80ms linear; } .lamp__label { color: var(--text-dim); @@ -91,6 +91,8 @@ fill: var(--lamp-on); filter: drop-shadow(0 0 6px var(--lamp-on)); } +.w-lamp[data-steer="1"] .lamp__icon { will-change: transform; } +.w-lamp[data-steer="1"][data-on="1"] .lamp__icon { filter: none; } .w-lamp[data-on="1"] .lamp__label { color: var(--text); } .w-lamp[data-on="1"][data-blink="1"] .lamp__icon { animation: lamp-blink 0.8s steps(1) infinite; } .w-lamp[data-hide-off="1"][data-on="0"] { visibility: hidden; } diff --git a/dash-apps/web-compose/widgets/_generated.js b/dash-apps/web-compose/widgets/_generated.js index 6258588..6e13cd9 100644 --- a/dash-apps/web-compose/widgets/_generated.js +++ b/dash-apps/web-compose/widgets/_generated.js @@ -86,7 +86,7 @@ return create; })()); // --- lamp - register({"type":"lamp","version":1,"renderer":"dom","name":{"en":"Indicator","hu":"Jelzőfény","de":"Kontrollleuchte"},"defaultSize":{"w":2,"h":2},"minSize":{"w":1,"h":1},"binds":[{"key":"value","kinds":["bool"],"name":{"en":"Condition","hu":"Feltétel","de":"Bedingung"},"default":"adasOn"}],"props":[{"key":"label","type":"string","default":"","name":{"en":"Label","hu":"Felirat","de":"Beschriftung"}},{"key":"icon","type":"enum","default":"dot","options":["dot","arrow-left","arrow-right","warning","wheel"],"name":{"en":"Icon","hu":"Ikon","de":"Symbol"}},{"key":"color","type":"color","default":"#22c55e","name":{"en":"Active color","hu":"Aktív szín","de":"Aktive Farbe"}},{"key":"blink","type":"bool","default":false,"name":{"en":"Blink when active","hu":"Villogjon aktívan","de":"Blinken wenn aktiv"}},{"key":"hideWhenOff","type":"bool","default":false,"name":{"en":"Hide when off","hu":"Rejtve, ha nem aktív","de":"Ausblenden wenn aus"}},{"key":"showLabel","type":"bool","default":false,"name":{"en":"Show label","hu":"Felirat mutatása","de":"Beschriftung anzeigen"}}]}, (function () { + register({"type":"lamp","version":1,"renderer":"dom","name":{"en":"Indicator","hu":"Jelzőfény","de":"Kontrollleuchte"},"defaultSize":{"w":2,"h":2},"minSize":{"w":1,"h":1},"binds":[{"key":"value","kinds":["bool"],"name":{"en":"Condition","hu":"Feltétel","de":"Bedingung"},"default":"adasOn"},{"key":"steering","kinds":["number"],"default":"egoSteeringAngle","hidden":true}],"props":[{"key":"label","type":"string","default":"","name":{"en":"Label","hu":"Felirat","de":"Beschriftung"}},{"key":"icon","type":"enum","default":"dot","options":["dot","arrow-left","arrow-right","warning","wheel"],"name":{"en":"Icon","hu":"Ikon","de":"Symbol"}},{"key":"color","type":"color","default":"#22c55e","name":{"en":"Active color","hu":"Aktív szín","de":"Aktive Farbe"}},{"key":"blink","type":"bool","default":false,"name":{"en":"Blink when active","hu":"Villogjon aktívan","de":"Blinken wenn aktiv"}},{"key":"hideWhenOff","type":"bool","default":false,"name":{"en":"Hide when off","hu":"Rejtve, ha nem aktív","de":"Ausblenden wenn aus"}},{"key":"showLabel","type":"bool","default":false,"name":{"en":"Show label","hu":"Felirat mutatása","de":"Beschriftung anzeigen"}}]}, (function () { // On/off indicator for any bool signal. The whole visual state is one // data-on attribute on the cell body; colors and blinking live in CSS. function create(ctx) { @@ -118,13 +118,25 @@ el.appendChild(label); } + const steers = props.icon === "wheel"; + if (steers) { + el.dataset.steer = "1"; + icon.style.transform = "rotate(0deg)"; + } let last = "0"; + let lastAngle = 0; return { update(values) { const next = values.value ? "1" : "0"; - if (next === last) return; - last = next; - el.dataset.on = next; + if (next !== last) { + last = next; + el.dataset.on = next; + } + if (!steers) return; + const angle = values.steering === undefined ? 0 : Math.round(values.steering); + if (angle === lastAngle) return; + lastAngle = angle; + icon.style.transform = "rotate(" + angle + "deg)"; }, }; } diff --git a/dash-apps/web-compose/widgets/lamp/descriptor.json b/dash-apps/web-compose/widgets/lamp/descriptor.json index e579b9e..115e4e8 100644 --- a/dash-apps/web-compose/widgets/lamp/descriptor.json +++ b/dash-apps/web-compose/widgets/lamp/descriptor.json @@ -27,6 +27,14 @@ "de": "Bedingung" }, "default": "adasOn" + }, + { + "key": "steering", + "kinds": [ + "number" + ], + "default": "egoSteeringAngle", + "hidden": true } ], "props": [ diff --git a/dash-apps/web-compose/widgets/lamp/widget.css b/dash-apps/web-compose/widgets/lamp/widget.css index c0ee57f..d93851a 100644 --- a/dash-apps/web-compose/widgets/lamp/widget.css +++ b/dash-apps/web-compose/widgets/lamp/widget.css @@ -10,7 +10,7 @@ width: clamp(16px, 48cqmin, 120px); height: clamp(16px, 48cqmin, 120px); fill: var(--track); - transition: fill 120ms linear, filter 120ms linear; + transition: fill 120ms linear, filter 120ms linear, transform 80ms linear; } .lamp__label { color: var(--text-dim); @@ -26,6 +26,8 @@ fill: var(--lamp-on); filter: drop-shadow(0 0 6px var(--lamp-on)); } +.w-lamp[data-steer="1"] .lamp__icon { will-change: transform; } +.w-lamp[data-steer="1"][data-on="1"] .lamp__icon { filter: none; } .w-lamp[data-on="1"] .lamp__label { color: var(--text); } .w-lamp[data-on="1"][data-blink="1"] .lamp__icon { animation: lamp-blink 0.8s steps(1) infinite; } .w-lamp[data-hide-off="1"][data-on="0"] { visibility: hidden; } diff --git a/dash-apps/web-compose/widgets/lamp/widget.js b/dash-apps/web-compose/widgets/lamp/widget.js index bf0a23e..1978753 100644 --- a/dash-apps/web-compose/widgets/lamp/widget.js +++ b/dash-apps/web-compose/widgets/lamp/widget.js @@ -29,13 +29,25 @@ function create(ctx) { el.appendChild(label); } + const steers = props.icon === "wheel"; + if (steers) { + el.dataset.steer = "1"; + icon.style.transform = "rotate(0deg)"; + } let last = "0"; + let lastAngle = 0; return { update(values) { const next = values.value ? "1" : "0"; - if (next === last) return; - last = next; - el.dataset.on = next; + if (next !== last) { + last = next; + el.dataset.on = next; + } + if (!steers) return; + const angle = values.steering === undefined ? 0 : Math.round(values.steering); + if (angle === lastAngle) return; + lastAngle = angle; + icon.style.transform = "rotate(" + angle + "deg)"; }, }; } diff --git a/dashpilot-ios/dashpilot/DataSource/DemoDataSource.swift b/dashpilot-ios/dashpilot/DataSource/DemoDataSource.swift index f4ea61b..b495d64 100644 --- a/dashpilot-ios/dashpilot/DataSource/DemoDataSource.swift +++ b/dashpilot-ios/dashpilot/DataSource/DemoDataSource.swift @@ -50,12 +50,6 @@ final class DemoDataSource: IDataSource { private static let goEnd: TimeInterval = 78 // cycleLength is the end of the accelerate-back-to-cruise phase. - #if DEBUG - private static let parked = true - #else - private static let parked = false - #endif - /// Slowly drifting base speed, continuous across cycle boundaries so /// cruise phases never jump. private static func cruiseSpeed(at t: TimeInterval) -> Float { @@ -86,7 +80,7 @@ final class DemoDataSource: IDataSource { case ..