diff web/fade/Light9EffectFader.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/fade/Light9EffectFader.ts@06bf6dae8e64
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/fade/Light9EffectFader.ts	Sun May 12 19:02:10 2024 -0700
@@ -0,0 +1,190 @@
+import debug from "debug";
+import { css, html, LitElement } from "lit";
+import { customElement, property, state } from "lit/decorators.js";
+import { NamedNode, Quad } from "n3";
+import { getTopGraph } from "../RdfdbSyncedGraph";
+import { showRoot } from "../show_specific";
+import { SyncedGraph } from "../SyncedGraph";
+import { Patch } from "../patch";
+import { Literal } from "n3";
+export { Light9Fader } from "./Light9Fader";
+
+const log = debug("efffader")
+
+//////////////////////////////////////
+const RETURN_URI = new NamedNode("");
+const RETURN_FLOAT = 1;
+function get2Step<T extends NamedNode | number>(returnWhat: T, graph: SyncedGraph, subj1: NamedNode, pred1: NamedNode, pred2: NamedNode): T | undefined {
+  // ?subj1 ?pred1 ?x . ?x ?pred2 ?returned .
+  let x: NamedNode;
+  try {
+    x = graph.uriValue(subj1, pred1);
+  } catch (e) {
+    return undefined;
+  }
+  try {
+    if (typeof returnWhat === "object" && (returnWhat as NamedNode).termType == "NamedNode") {
+      return graph.uriValue(x, pred2) as T;
+    } else if (typeof returnWhat === "number") {
+      return graph.floatValue(x, pred2) as T;
+    }
+  } catch (e) {
+    return undefined;
+  }
+}
+function set2Step(
+  graph: SyncedGraph, //
+  subj1: NamedNode,
+  pred1: NamedNode,
+  baseName: string,
+  pred2: NamedNode,
+  newObjLiteral: Literal
+) { }
+
+function maybeUriValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): NamedNode | undefined {
+  try {
+    return graph.uriValue(s, p);
+  } catch (e) {
+    return undefined;
+  }
+}
+function maybeStringValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): string | undefined {
+  try {
+    return graph.stringValue(s, p);
+  } catch (e) {
+    return undefined;
+  }
+}
+function maybeFloatValue(graph: SyncedGraph, s: NamedNode, p: NamedNode): number | undefined {
+  try {
+    return graph.floatValue(s, p);
+  } catch (e) {
+    return undefined;
+  }
+}
+
+//////////////////////////////////////
+class EffectFader {
+  constructor(public uri: NamedNode) { }
+  column: string = "unset";
+  effect?: NamedNode;
+  effectAttr?: NamedNode; // :strength
+  setting?: NamedNode; // we assume fader always has exactly one setting
+  value?: number;
+}
+
+@customElement("light9-effect-fader")
+export class Light9EffectFader extends LitElement {
+  static styles = [
+    css`
+      :host {
+        display: inline-block;
+        border: 2px gray outset;
+        background: #272727;
+      }
+      light9-fader {
+        margin: 0px;
+        width: 100%;
+      }
+    `,
+  ];
+  render() {
+    if (this.conf === undefined || this.conf.value === undefined) {
+      return html`...`;
+    }
+    return html`
+      <div><resource-display .uri=${this.uri}></resource-display>
+      <light9-fader .value=${this.conf.value} @change=${this.onSliderInput}></light9-fader>
+      <div>${this.conf.value.toPrecision(3)}</div>
+      <div>effect <edit-choice nounlink .uri=${this.conf.effect} @edited=${this.onEffectChange}></edit-choice></div>
+      <div>attr <edit-choice nounlink .uri=${this.conf.effectAttr} @edited=${this.onEffectAttrChange}></edit-choice></div>
+    `;
+  }
+
+  graph?: SyncedGraph;
+  ctx: NamedNode = new NamedNode(showRoot + "/fade");
+  @property() uri!: NamedNode;
+  @state() conf?: EffectFader; // compiled from graph
+
+  constructor() {
+    super();
+    getTopGraph().then((g) => {
+      this.graph = g;
+      this.graph.runHandler(this.compile.bind(this, this.graph), `fader config ${this.uri.value}`);
+    });
+  }
+
+  private compile(graph: SyncedGraph) {
+    const U = graph.U();
+    this.conf = undefined;
+
+    const conf = new EffectFader(this.uri);
+
+    if (!graph.contains(this.uri, U("rdf:type"), U(":Fader"))) {
+      // not loaded yet, perhaps
+      return;
+    }
+
+    conf.column = maybeStringValue(graph, this.uri, U(":column")) || "unset";
+    conf.effect = maybeUriValue(graph, this.uri, U(":effect"));
+    conf.effectAttr = get2Step(RETURN_URI, graph, this.uri, U(":setting"), U(":effectAttr"));
+
+    this.conf = conf;
+    graph.runHandler(this.compileValue.bind(this, graph, this.conf), `fader config.value ${this.uri.value}`);
+  }
+
+  private compileValue(graph: SyncedGraph, conf: EffectFader) {
+    // external graph change -> conf.value
+    const U = graph.U();
+    conf.value = get2Step(RETURN_FLOAT, graph, this.uri, U(":setting"), U(":value"));
+    // since conf attrs aren't watched as property:
+    this.requestUpdate()
+  }
+
+  onSliderInput(ev: CustomEvent) {
+    // slider user input -> graph
+    if (this.conf === undefined) return;
+    this.conf.value = ev.detail.value
+    this.writeValueToGraph()
+  }
+
+  writeValueToGraph() {
+    // this.value -> graph
+    if (this.graph === undefined) {
+      return;
+    }
+    const U = this.graph.U();
+    if (this.conf === undefined) {
+      return;
+    }
+    if (this.conf.value === undefined) {
+      log(`value of ${this.uri} is undefined`)
+      return;
+    }
+    log('writeValueToGraph', this.conf.value)
+    const valueTerm = this.graph.LiteralRoundedFloat(this.conf.value);
+    const settingNode = this.graph.uriValue(this.uri, U(":setting"));
+    this.graph.patchObject(settingNode, this.graph.Uri(":value"), valueTerm, this.ctx);
+
+  }
+
+  onEffectChange(ev: CustomEvent) {
+    if (this.graph === undefined) {
+      return;
+    }
+    const { newValue } = ev.detail;
+    this.graph.patchObject(this.uri, this.graph.Uri(":effect"), newValue, this.ctx);
+  }
+
+  onEffectAttrChange(ev: CustomEvent) {
+    if (this.graph === undefined) {
+      return;
+    }
+    // const { newValue } = ev.detail;
+    // if (this.setting === undefined) {
+    //   this.setting = this.graph.nextNumberedResource(this.graph.Uri(":fade_set"));
+    //   this.graph.patchObject(this.uri, this.graph.Uri(":setting"), this.setting, this.ctx);
+    // }
+    // this.graph.patchObject(this.setting, this.graph.Uri(":effectAttr"), newValue, this.ctx);
+  }
+}