Changeset - b09ff4b0094c
[Not reviewed]
default
0 4 0
drewp@bigasterisk.com - 20 months ago 2023-06-02 16:42:18
drewp@bigasterisk.com
faders in pages now
4 files changed with 191 insertions and 72 deletions:
0 comments (0 inline, 0 general)
light9/fade/Light9EffectFader.ts
Show inline comments
 
import { css, html, LitElement } from "lit";
 
import { customElement, property, state } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { NamedNode, Quad } from "n3";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { showRoot } from "../web/show_specific";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
import { Patch } from "../web/patch";
 
import { Literal } from "n3";
 
export { Light9Fader } from "./Light9Fader";
 

	
 
//////////////////////////////////////
 
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 {
 
@@ -20,87 +83,91 @@ export class Light9EffectFader extends L
 
        margin: 4px;
 
        width: 100%;
 
      }
 
    `,
 
  ];
 
  render() {
 
    if (this.conf === undefined || this.conf.value === undefined) {
 
      return html`...`;
 
    }
 
    return html`
 
      <light9-fader .value=${this.value} @change=${this.onSliderInput}></light9-fader>
 
      <div>${this.value.toPrecision(3)}</div>
 
      <div>eff: <edit-choice nounlink .uri=${this.effect} @edited=${this.onEffectChange}></edit-choice></div>
 
      <div>attr: <edit-choice nounlink .uri=${this.effectAttr} @edited=${this.onEffectAttrChange}></edit-choice></div>
 
      <div>Slider ${this.column}</div>
 
      <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;
 
  @property() column!: string;
 
  @property() effect?: NamedNode;
 
  @property() effectAttr?: NamedNode;
 
  @state() setting?: NamedNode;
 

	
 
  @property() value: number = 0.0;
 
  @state() conf?: EffectFader; // compiled from graph
 

	
 
  constructor() {
 
    super();
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
      this.graph.runHandler(this.compile.bind(this, this.graph), `config ${this.uri.value}`);
 
      this.graph.runHandler(this.compileValue.bind(this, this.graph), `valueSync ${this.uri.value}`);
 
      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
 
      this.column = "unset";
 
      this.effect = undefined;
 
      this.effectAttr = undefined;
 
      return;
 
    }
 
    this.column = graph.stringValue(this.uri, U(":column"));
 
    this.effect = graph.uriValue(this.uri, U(":effect"));
 
    this.setting = graph.uriValue(this.uri, U(":setting"));
 
    if (this.setting !== undefined) {
 
      try {
 
        this.effectAttr = graph.uriValue(this.setting, U(":effectAttr"));
 
      } catch (e) {
 
        this.effectAttr = undefined;
 
      }
 
    }
 

	
 
    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) {
 
  private compileValue(graph: SyncedGraph, conf: EffectFader) {
 
    //  external graph change -> conf.value
 
    const U = graph.U();
 
    if (!graph.contains(this.uri, U("rdf:type"), U(":Fader"))) {
 
      // not loaded yet
 
      // console.timeEnd(`valueSync ${this.uri.value}`)
 
      return;
 
    }
 
    const st = graph.uriValue(this.uri, U(":setting"));
 
    this.value = graph.floatValue(st, graph.Uri(":value"));
 
    conf.value = get2Step(RETURN_FLOAT, graph, this.uri, U(":setting"), U(":value"));
 
  }
 

	
 
  onSliderInput(ev: CustomEvent) {
 
    // slider user input -> graph
 
    if (this.graph === undefined) {
 
      return;
 
    }
 
    const U = this.graph.U();
 
    const prev = this.value;
 
    const v: number = ev.detail.value;
 
    this.value = parseFloat(v.toPrecision(3)); // rewrite pls
 
    if (this.value == prev) {
 
    // const prev = this.value;
 
    // const v: number = ev.detail.value;
 
    // this.value = parseFloat(v.toPrecision(3)); // rewrite pls
 
    // if (this.value == prev) {
 
    //   return;
 
    // }
 
    // if (!this.setting) {
 
    //   throw new Error("can't make new settings yet");
 
    // }
 

	
 
    if (this.conf === undefined) {
 
      return;
 
    }
 
    if (!this.setting) {
 
      throw new Error("can't make new settings yet");
 
    let patch = new Patch([], []);
 
    let settingNode: NamedNode;
 
    const valueTerm = this.graph.LiteralRoundedFloat(ev.detail.value);
 
    try {
 
      settingNode = this.graph.uriValue(this.uri, U(":setting"));
 
    } catch (e) {
 
      settingNode = this.graph.nextNumberedResource(U(":fadeset"));
 
      patch = patch.update(new Patch([], [new Quad(this.conf.uri, U(":setting"), settingNode, this.ctx)]));
 
    }
 
    this.graph.patchObject(this.setting, this.graph.Uri(":value"), this.graph.LiteralRoundedFloat(this.value), this.ctx);
 
    patch = patch.update(this.graph.getObjectPatch(settingNode, this.graph.Uri(":value"), valueTerm, this.ctx));
 
    this.graph.applyAndSendPatch(patch);
 
  }
 

	
 
  onEffectChange(ev: CustomEvent) {
 
    if (this.graph === undefined) {
 
      return;
 
    }
 
@@ -109,14 +176,14 @@ export class Light9EffectFader extends L
 
  }
 

	
 
  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);
 
    // 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);
 
  }
 
}
light9/fade/Light9FadeUi.ts
Show inline comments
 
import debug from "debug";
 
import { css, html, LitElement } from "lit";
 
import { css, html, LitElement, TemplateResult } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import * as N3 from "n3";
 
import { NamedNode, Quad } from "n3";
 
import { Patch } from "../web/patch";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { shortShow } from "../web/show_specific";
 
import { showRoot } from "../web/show_specific";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
export { EditChoice } from "../web/EditChoice";
 
export { Light9EffectFader } from "./Light9EffectFader";
 

	
 
debug.enable("*");
 
debug.enable("*,autodep");
 
const log = debug("fade");
 

	
 
class FadePage {
 
  constructor(public uri: NamedNode) {}
 
  faders: NamedNode[] = [];
 
}
 
class FadePages {
 
  pages: FadePage[] = [];
 
}
 

	
 
@customElement("light9-fade-ui")
 
export class Light9FadeUi extends LitElement {
 
  static styles = [
 
    css`
 
      :host {
 
        display: block;
 
@@ -24,38 +34,80 @@ export class Light9FadeUi extends LitEle
 
  render() {
 
    return html`
 
      <rdfdb-synced-graph></rdfdb-synced-graph>
 

	
 
      <h1>Fade</h1>
 

	
 
      ${(this.fadePages?.pages || []).map(this.renderPage)}
 

	
 
      ${this.faders.map((fd) => html` <light9-effect-fader .uri=${fd}></light9-effect-fader> `)}
 
      <div><button @click=${this.addPage}>Add new page</button></div>
 
    `;
 
  }
 
  private renderPage(page: FadePage): TemplateResult {
 
    return html`<div>
 
      <fieldset>
 
        <legend>Page <resource-display rename .uri=${page.uri}></resource-display></legend>
 
        ${page.faders.map((fd) => html` <light9-effect-fader .uri=${fd}></light9-effect-fader> `)}
 
      </fieldset>
 
    </div>`;
 
  }
 

	
 
  graph!: SyncedGraph;
 
  ctx: NamedNode = new NamedNode(showRoot + "/fade");
 

	
 
  @property() faders: NamedNode[] = [];
 
  @property() fadePages?: FadePages;
 

	
 
  constructor() {
 
    super();
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
      // todo: start with a page, then find the faders on that page
 
      this.faders = [
 
        g.Uri(`:show/${shortShow}/fadePage1f0`),
 
        g.Uri(`:show/${shortShow}/fadePage1f1`),
 
        g.Uri(`:show/${shortShow}/fadePage1f2`),
 
        g.Uri(`:show/${shortShow}/fadePage1f3`),
 
        g.Uri(`:show/${shortShow}/fadePage1f4`),
 
        g.Uri(`:show/${shortShow}/fadePage1f5`),
 
        g.Uri(`:show/${shortShow}/fadePage1f6`),
 
        g.Uri(`:show/${shortShow}/fadePage1f7`),
 
      ];
 
      this.graph.runHandler(this.compile.bind(this), `faders layout`);
 
    });
 
  }
 
  connectedCallback(): void {
 
    super.connectedCallback();
 
  }
 
}
 

	
 
  compile() {
 
    const U = this.graph.U();
 
    this.fadePages = undefined;
 
    const fadePages = new FadePages();
 
    for (let page of this.graph.subjects(U("rdf:type"), U(":FadePage"))) {
 
      const fp = new FadePage(page as NamedNode);
 
      try {
 
        for (let fader of this.graph.objects(page, U(":fader"))) {
 
          fp.faders.push(fader as NamedNode);
 
        }
 
        fp.faders.sort((a, b) => {
 
          // todo this is supposed to sort by :column so you can reorder
 
          return a.value.localeCompare(b.value);
 
        });
 
        fadePages.pages.push(fp);
 
      } catch (e) {}
 
    }
 
    fadePages.pages.sort((a, b) => {
 
      return a.uri.value.localeCompare(b.uri.value);
 
    });
 
    this.fadePages = fadePages;
 
  }
 

	
 
  addPage() {
 
    const U = this.graph.U();
 
    const uri = this.graph.nextNumberedResource(showRoot + "/fadePage");
 
    const adds = [
 
      //
 
      new Quad(uri, U("rdf:type"), U(":FadePage"), this.ctx),
 
      new Quad(uri, U("rdfs:label"), N3.DataFactory.literal("unnamed"), this.ctx),
 
    ];
 
    for (let n = 1; n <= 8; n++) {
 
      const f = this.graph.nextNumberedResource(showRoot + "/fader");
 
      const s = this.graph.nextNumberedResource(showRoot + "/faderset");
 
      adds.push(new Quad(uri, U(":fader"), f, this.ctx));
 
      adds.push(new Quad(f, U("rdf:type"), U(":Fader"), this.ctx));
 
      adds.push(new Quad(f, U(":column"), N3.DataFactory.literal("" + n), this.ctx));
 
      adds.push(new Quad(f, U(":setting"), s, this.ctx));
 
      adds.push(new Quad(s, U(":effectAttr"), U(":strength"), this.ctx));
 
      adds.push(new Quad(s, U(":value"), this.graph.LiteralRoundedFloat(0), this.ctx));
 
    }
 
    this.graph.applyAndSendPatch(new Patch([], adds));
 
  }
 
}
light9/fade/Light9Fader.ts
Show inline comments
 
@@ -14,13 +14,13 @@ export class Light9Fader extends LitElem
 
  static styles = [
 
    css`
 
      :host {
 
        display: inline-block;
 
        border: 2px gray inset;
 
        background: #000;
 
        height: 250px;
 
        height: 130px;
 
      }
 
      #handle {
 
        background: gray;
 
        border: 5px gray outset;
 
        position: relative;
 
        left: 0;
 
@@ -30,13 +30,13 @@ export class Light9Fader extends LitElem
 
  ];
 

	
 
  @property() value: number = 0;
 

	
 
  @query("#handle") handleEl!: HTMLElement;
 

	
 
  troughHeight = 250 - 2 - 2 - 5 - 5;
 
  troughHeight = 130 - 2 - 2 - 5 - 5;
 
  handleHeight = 20;
 

	
 
  drag?: Drag;
 
  unmutedValue: number = 1;
 

	
 
  render() {
light9/web/EditChoice.ts
Show inline comments
 
@@ -14,17 +14,17 @@ function setupDrop(
 
  coordinateOriginElem: HTMLElement | null,
 
  onDrop: (uri: NamedNode, pos: Vector | null) => void
 
) {
 
  const highlight = () => highlightElem.classList.add("dragging");
 
  const unhighlight = () => highlightElem.classList.remove("dragging");
 

	
 
  senseElem.addEventListener("drag", (event: DragEvent) => {});
 
  senseElem.addEventListener("drag", (event: DragEvent) => { });
 

	
 
  senseElem.addEventListener("dragstart", (event: DragEvent) => {});
 
  senseElem.addEventListener("dragstart", (event: DragEvent) => { });
 

	
 
  senseElem.addEventListener("dragend", (event: DragEvent) => {});
 
  senseElem.addEventListener("dragend", (event: DragEvent) => { });
 

	
 
  senseElem.addEventListener("dragover", (event: DragEvent) => {
 
    event.preventDefault();
 
    event.dataTransfer!.dropEffect = "copy";
 
    highlight();
 
  });
 
@@ -105,13 +105,13 @@ export class EditChoice extends LitEleme
 
  //     setupDrop(this.box, this.box, null, this._setUri.bind(this));
 
  //   }
 
  // }
 

	
 
  _setUri(u?: NamedNode) {
 
    this.uri = u;
 
    this.dispatchEvent(new CustomEvent("edited", {detail: {newValue: u}}));
 
    this.dispatchEvent(new CustomEvent("edited", { detail: { newValue: u } }));
 
  }
 

	
 
  unlink() {
 
    return this._setUri(undefined);
 
  }
 
}
0 comments (0 inline, 0 general)