diff --git a/light9/live/Light9LiveControl.ts b/light9/live/Light9AttrControl.ts copy from light9/live/Light9LiveControl.ts copy to light9/live/Light9AttrControl.ts --- a/light9/live/Light9LiveControl.ts +++ b/light9/live/Light9AttrControl.ts @@ -1,24 +1,25 @@ import debug from "debug"; import { css, html, LitElement, PropertyValues } from "lit"; -import { customElement, property } from "lit/decorators.js"; +import { customElement, property, state } from "lit/decorators.js"; import { Literal, NamedNode } from "n3"; import { SubEvent } from "sub-events"; import { SyncedGraph } from "../web/SyncedGraph"; -import { ControlValue } from "./Effect"; +import { ControlValue, Effect } from "./Effect"; import { GraphToControls } from "./GraphToControls"; import { DeviceAttrRow } from "./Light9DeviceControl"; import { Choice } from "./Light9Listbox"; +import { getTopGraph } from "../web/RdfdbSyncedGraph"; export { Slider } from "@material/mwc-slider"; export { Light9ColorPicker } from "../web/light9-color-picker"; -const log = debug("control"); +const log = debug("settings.dev.attr"); - -const makeType = (d: "scalar" | "color" | "choice") => new NamedNode(`http://light9.bigasterisk.com/${d}`); +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-live-control") -export class Light9LiveControl extends LitElement { +@customElement("light9-attr-control") +export class Light9AttrControl extends LitElement { graph!: SyncedGraph; static styles = [ @@ -30,67 +31,132 @@ export class Light9LiveControl extends L #colorControls > * { margin: 0 3px; } - :host { - border: 2px solid white; - } + :host { + border: 2px solid white; + } + mwc-slider { + width: 250px; + } `, ]; - // passed from parent - @property() device!: NamedNode; - @property() dataType: NamedNode; - @property() deviceAttrRow!: DeviceAttrRow; + @property() deviceAttrRow: DeviceAttrRow | null = null; + @state() dataType: DataTypeNames = "scalar"; + + @property() effect: Effect | null = null; // we'll connect to this and receive graphValueChanged and send uiValueChanged - @property() graphToControls!: GraphToControls; + // @property() graphToControls!: GraphToControls; @property() enableChange: boolean = false; - @property() value: ControlValue | null = null; + @property() value: ControlValue | null = null; // e.g. color string // slider mode - @property() sliderValue: number = 0; + // @property() sliderValue: number = 0; // color mode // choice mode - @property() pickedChoice: Choice | null = null; - @property() choiceValue: Choice | null = null; + // @property() pickedChoice: Choice | null = null; + // @property() choiceValue: Choice | null = null; valueChanged: SubEvent = new SubEvent(); constructor() { super(); - this.dataType = makeType("color"); - // getTopGraph().then((g) => { - // this.graph = g; - // // this.graph.runHandler(this.graphReads.bind(this), `${this.device} ${this.deviceAttrRow.uri} reads`); - // }); + getTopGraph().then((g) => { + this.graph = g; + if (this.deviceAttrRow === null) throw new Error(); + // this.graph.runHandler(this.graphReads.bind(this), `${this.deviceAttrRow.device} ${this.deviceAttrRow.uri} reads`); + }); + } + + connectedCallback(): void { + super.connectedCallback(); } render() { - const dbg=html` - ]` - if (this.dataType.equals(makeType("scalar"))) { - return html`${dbg} `; - } else if (this.dataType.equals(makeType("color"))) { - return html` ${dbg} + if (this.deviceAttrRow === null) throw new Error(); + const dbg = html` live-control ${this.dataType} ]`; + if (this.dataType == "scalar") { + const v = this.value || 0; + return html`${dbg} `; + } else if ((this.dataType = "color")) { + const v = this.value || '#000' + return html` + ${dbg}
- +
`; - } else if (this.dataType.equals(makeType("choice"))) { - return html`${dbg} `; + } else if (this.dataType == "choice") { + return html`${dbg} `; } } // graphReads() { + // if (this.deviceAttrRow === null) throw new Error(); // const U = this.graph.U(); + // this.effect?.currentValue(this.deviceAttrRow.device, this.deviceAttrRow.uri); // } - updated(changedProperties: PropertyValues) { - if (changedProperties.has("graphToControls")) { - this.graphToControls.register(this.device, this.deviceAttrRow.uri, this.onGraphValueChanged.bind(this)); - this.enableChange = true; + updated(changedProperties: PropertyValues) { + super.updated(changedProperties); + // if (changedProperties.has("graphToControls")) { + // // this.graphToControls.register(this.device, this.deviceAttrRow.uri, this.onGraphValueChanged.bind(this)); + // this.enableChange = true; + // } + + 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.effect !== null && this.graph !== undefined) { + const p = this.effect.edit(this.deviceAttrRow.device, this.deviceAttrRow.uri, this.value); + log("patch", p, "to", this.graph); + if (p.adds.length || p.dels.length) { + this.graph.applyAndSendPatch(p); + } + } + } + + private onEffectProperty() { + if (this.effect === null) throw new Error(); + // 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() { + // anything in the settings graph is new + log("i check the effect current value"); + 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"; } } @@ -99,23 +165,32 @@ export class Light9LiveControl extends L // not sure what this is, but it seems to be followed by good events return; } - log(ev.type, ev.detail?.value); - this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value); + log(ev.type, ev.detail.value); + this.value = ev.detail.value; + // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value); } +onColorInput(ev: CustomEvent) { + this.value = ev.detail.value; +} + onGraphValueChanged(v: ControlValue | null) { - // log("change: control must display", v); + 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.equals(makeType("scalar"))) { + if (this.dataType == "scalar") { if (v !== null) { setTimeout(() => { // only needed once per page layout this.shadowRoot?.querySelector("mwc-slider")?.layout(/*skipUpdateUI=*/ false); }, 1); - this.sliderValue = v as number; + this.value = v; } else { - this.sliderValue = 0; + this.value = 0; } + } else if (this.dataType == "color") { + log('graph sets coolor', v) + this.value=v; } // if (v === null) { // this.clear(); @@ -128,34 +203,47 @@ export class Light9LiveControl extends L // this.enableChange = true; } + graphToColor(v: ControlValue | null) { + this.value = v === null ? "#000" : v; + return; + // const cp = this.shadowRoot?.querySelector("light9-color-picker") as Light9ColorPicker | null; + // if (cp) { + // if (typeof v != "string") throw new Error("type v is " + typeof v); + // if (v === null) { + // v = "#000"; + // } + // cp.setColor(v as string); + // } + } + goBlack() { this.value = "#000000"; } onChoice(value: any) { - if (this.graphToControls == null || !this.enableChange) { - return; - } - if (value != null) { - value = this.graph.Uri(value); - } else { - value = null; - } - this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value); + // if (this.graphToControls == null || !this.enableChange) { + // return; + // } + // if (value != null) { + // value = this.graph.Uri(value); + // } else { + // value = null; + // } + // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value); } onChange(value: any) { - if (this.graphToControls == null || !this.enableChange) { - return; - } - 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; - } - this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value); + // if (this.graphToControls == null || !this.enableChange) { + // return; + // } + // 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; + // } + // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value); } // clear() {