Mercurial > code > home > repos > light9
view web/live/Light9AttrControl.ts @ 2376:4556eebe5d73
topdir reorgs; let pdm have its src/ dir; separate vite area from light9/
author | drewp@bigasterisk.com |
---|---|
date | Sun, 12 May 2024 19:02:10 -0700 |
parents | light9/web/live/Light9AttrControl.ts@06bf6dae8e64 |
children |
line wrap: on
line source
import debug from "debug"; import { css, html, LitElement, PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { Literal, NamedNode } from "n3"; import { SubEvent } from "sub-events"; import { getTopGraph } from "../RdfdbSyncedGraph"; import { SyncedGraph } from "../SyncedGraph"; import { ControlValue, Effect } from "./Effect"; import { DeviceAttrRow } from "./Light9DeviceControl"; export { Slider } from "@material/mwc-slider"; export { Light9ColorPicker } from "../light9-color-picker"; export { Light9Listbox } from "./Light9Listbox"; const log = debug("settings.dev.attr"); type DataTypeNames = "scalar" | "color" | "choice"; const makeType = (d: DataTypeNames) => new NamedNode(`http://light9.bigasterisk.com/${d}`); // UI for one device attr (of any type). @customElement("light9-attr-control") export class Light9AttrControl extends LitElement { graph!: SyncedGraph; static styles = [ css` #colorControls { display: flex; align-items: center; } #colorControls > * { margin: 0 3px; } :host { } mwc-slider { width: 250px; } `, ]; @property() deviceAttrRow: DeviceAttrRow | null = null; @state() dataType: DataTypeNames = "scalar"; @property() effect: Effect | null = null; @property() enableChange: boolean = false; @property() value: ControlValue | null = null; // e.g. color string constructor() { super(); getTopGraph().then((g) => { this.graph = g; if (this.deviceAttrRow === null) throw new Error(); }); } connectedCallback(): void { super.connectedCallback(); setTimeout(() => { // only needed once per page layout this.shadowRoot?.querySelector("mwc-slider")?.layout(/*skipUpdateUI=*/ false); }, 1); } render() { if (this.deviceAttrRow === null) throw new Error(); if (this.dataType == "scalar") { const v = this.value || 0; return html`<mwc-slider .value=${v} step=${1 / 255} min="0" max="1" @input=${this.onValueInput}></mwc-slider> `; } else if ((this.dataType = "color")) { const v = this.value || "#000"; return html` <div id="colorControls"> <button @click=${this.goBlack}>0.0</button> <light9-color-picker .color=${v} @input=${this.onValueInput}></light9-color-picker> </div> `; } else if (this.dataType == "choice") { return html`<light9-listbox .choices=${this.deviceAttrRow.choices} .value=${this.value}> </light9-listbox> `; } } updated(changedProperties: PropertyValues<this>) { super.updated(changedProperties); if (changedProperties.has("deviceAttrRow")) { this.onDeviceAttrRowProperty(); } if (changedProperties.has("effect")) { this.onEffectProperty(); } if (changedProperties.has("value")) { this.onValueProperty(); } } private onValueProperty() { if (this.deviceAttrRow === null) throw new Error(); if (!this.graph) { log('ignoring value change- no graph yet') return; } if (this.effect === null) { this.value = null; } else { const p = this.effect.edit( // this.deviceAttrRow.device, this.deviceAttrRow.uri, this.value ); if (!p.isEmpty()) { log("Effect told us to graph.patch this:\n", p.dump()); this.graph.applyAndSendPatch(p); } } } private onEffectProperty() { if (this.effect === null) { log('no effect obj yet') return; } // effect will read graph changes on its own, but emit an event when it does this.effect.settingsChanged.subscribe(() => { this.effectSettingsChanged(); }); this.effectSettingsChanged(); } private effectSettingsChanged() { // something in the settings graph is new if (this.deviceAttrRow === null) throw new Error(); if (this.effect === null) throw new Error(); // log("graph->ui on ", this.deviceAttrRow.device, this.deviceAttrRow.uri); const v = this.effect.currentValue(this.deviceAttrRow.device, this.deviceAttrRow.uri); this.onGraphValueChanged(v); } private onDeviceAttrRowProperty() { if (this.deviceAttrRow === null) throw new Error(); const d = this.deviceAttrRow.dataType; if (d.equals(makeType("scalar"))) { this.dataType = "scalar"; } else if (d.equals(makeType("color"))) { this.dataType = "color"; } else if (d.equals(makeType("choice"))) { this.dataType = "choice"; } } onValueInput(ev: CustomEvent) { if (ev.detail === undefined) { // not sure what this is, but it seems to be followed by good events return; } // log(ev.type, ev.detail.value); this.value = ev.detail.value; // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value); } onGraphValueChanged(v: ControlValue | null) { if (this.deviceAttrRow === null) throw new Error(); // log("change: control must display", v, "for", this.deviceAttrRow.device.value, this.deviceAttrRow.uri.value); // this.enableChange = false; if (this.dataType == "scalar") { if (v !== null) { this.value = v; } else { this.value = 0; } } else if (this.dataType == "color") { this.value = v; } } goBlack() { this.value = "#000000"; } onChoice(value: any) { // if (value != null) { // value = this.graph.Uri(value); // } else { // value = null; // } } onChange(value: any) { // if (typeof value === "number" && isNaN(value)) { // return; // } // let onChoice do it // //log('change: control tells graph', @deviceAttrRow.uri.value, value) // if (value === undefined) { // value = null; // } } }