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` `; } else if ((this.dataType = "color")) { const v = this.value || "#000"; return html`
`; } else if (this.dataType == "choice") { return html` `; } } updated(changedProperties: PropertyValues) { 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; // } } }