Files @ 9645581bff24
Branch filter:

Location: light9/light9/live/Light9LiveControl.ts

drewp@bigasterisk.com
redo color picker code in lit
import debug from "debug";
import { css, html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators.js";
import { Literal, NamedNode } from "n3";
import { SubEvent } from "sub-events";
import { SyncedGraph } from "../web/SyncedGraph";
import { ControlValue } from "./Effect";
import { GraphToControls } from "./GraphToControls";
import { DeviceAttrRow } from "./Light9DeviceControl";
import { Choice } from "./Light9Listbox";
export { Slider } from "@material/mwc-slider";
export { Light9ColorPicker } from "../web/light9-color-picker";

const log = debug("control");


const makeType = (d: "scalar" | "color" | "choice") => new NamedNode(`http://light9.bigasterisk.com/${d}`);

// UI for one device attr (of any type).
@customElement("light9-live-control")
export class Light9LiveControl extends LitElement {
  graph!: SyncedGraph;

  static styles = [
    css`
      #colorControls {
        display: flex;
        align-items: center;
      }
      #colorControls > * {
        margin: 0 3px;
      }
    :host {
      border: 2px solid white;
    }
    `,
  ];

  // passed from parent
  @property() device!: NamedNode;
  @property() dataType: NamedNode;
  @property() deviceAttrRow!: DeviceAttrRow;
  // we'll connect to this and receive graphValueChanged and send uiValueChanged
  @property() graphToControls!: GraphToControls;

  @property() enableChange: boolean = false;
  @property() value: ControlValue | null = null;

  // slider mode
  @property() sliderValue: number = 0;

  // color mode

  // choice mode
  @property() pickedChoice: Choice | null = null;
  @property() choiceValue: Choice | null = null;

  valueChanged: SubEvent<Literal> = 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`);
    // });
  }

  render() {
    const dbg=html`
       ]`
    if (this.dataType.equals(makeType("scalar"))) {
      return html`${dbg} <mwc-slider .value=${this.sliderValue} step=${1 / 255} min="0" max="1" @input=${this.onSliderInput}></mwc-slider> `;
    } else if (this.dataType.equals(makeType("color"))) {
      return html` ${dbg}
        <div id="colorControls">
          <button on-click="goBlack">0.0</button>
          <light9-color-picker color="${this.value}"></light9-color-picker>
        </div>
      `;
    } else if (this.dataType.equals(makeType("choice"))) {
      return html`${dbg} <light9-listbox choices="{{deviceAttrRow.choices}}" value="{{choiceValue}}"> </light9-listbox> `;
    }
  }

  // graphReads() {
  //   const U = this.graph.U();
  // }

  updated(changedProperties: PropertyValues) {
    if (changedProperties.has("graphToControls")) {
      this.graphToControls.register(this.device, this.deviceAttrRow.uri, this.onGraphValueChanged.bind(this));
      this.enableChange = true;
    }
  }

  onSliderInput(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.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value);
  }

  onGraphValueChanged(v: ControlValue | null) {
    // log("change: control must display", v);
    // this.enableChange = false;
    if (this.dataType.equals(makeType("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;
      } else {
        this.sliderValue = 0;
      }
    }
    // if (v === null) {
    //   this.clear();
    // } else {
    //   this.value = v;
    // }
    // if (this.deviceAttrRow.useChoice) {
    //   this.choiceValue = v === null ? v : v.value;
    // }
    // this.enableChange = true;
  }

  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);
  }

  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);
  }

  // clear() {
  //   this.pickedChoice = null;
  //   this.sliderWriteValue = 0;
  //   if (this.deviceAttrRow.useColor) {
  //     return (this.value = "#000000");
  //   } else if (this.deviceAttrRow.useChoice) {
  //     return (this.value = this.pickedChoice = null);
  //   } else {
  //     return (this.value = this.sliderValue = 0);
  //   }
  // }
}