diff --git a/light9/fade/Light9FadeUi.ts b/light9/fade/Light9FadeUi.ts --- a/light9/fade/Light9FadeUi.ts +++ b/light9/fade/Light9FadeUi.ts @@ -1,13 +1,12 @@ -import { fastSlider, fastSliderLabel, provideFASTDesignSystem } from "@microsoft/fast-components"; import debug from "debug"; import { css, html, LitElement } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import { NamedNode } from "n3"; import { getTopGraph } from "../web/RdfdbSyncedGraph"; +import { shortShow, showRoot } from "../web/show_specific"; import { SyncedGraph } from "../web/SyncedGraph"; -import { shortShow, showRoot } from "../web/show_specific"; export { EditChoice } from "../web/EditChoice"; -provideFASTDesignSystem().register(fastSlider(), fastSliderLabel()); +export { Light9Fader } from "./Light9Fader"; debug.enable("*"); const log = debug("fade"); @@ -19,6 +18,7 @@ export class Light9FadeUi extends LitEle css` :host { display: block; + user-select: none; /* really this is only desirable during slider drag events */ } `, ]; @@ -30,7 +30,7 @@ export class Light9FadeUi extends LitEle
- ${this.faders.map((fd) => html` `)} + ${this.faders.map((fd) => html` `)} `; } @@ -62,8 +62,8 @@ export class Light9FadeUi extends LitEle } } -@customElement("light9-fader") -export class Light9Fader extends LitElement { +@customElement("light9-effect-fader") +export class Light9EffectFader extends LitElement { static styles = [ css` :host { @@ -71,24 +71,15 @@ export class Light9Fader extends LitElem border: 2px gray outset; background: #272727; } - fast-slider { - height: 256px; - } - fast-slider > .track { - background: #e3bbc0; - box-shadow: 0 0 8px; - } - fast-slider { - --accent-foreground-rest: #0a0a0c; + light9-fader { + margin: 4px; + width: 100%; } `, ]; render() { return html` - - - - +
${this.value.toPrecision(3)}
eff:
attr:
@@ -153,7 +144,7 @@ export class Light9Fader extends LitElem } const U = this.graph.U(); const prev = this.value; - const v: number = (ev.target as any).valueAsNumber; + const v: number = ev.detail.value; this.value = parseFloat(v.toPrecision(3)); // rewrite pls if (this.value == prev) { return; diff --git a/light9/fade/Light9Fader.ts b/light9/fade/Light9Fader.ts new file mode 100644 --- /dev/null +++ b/light9/fade/Light9Fader.ts @@ -0,0 +1,139 @@ +import debug from "debug"; +import { css, html, LitElement, PropertyValueMap } from "lit"; +import { customElement, property, query } from "lit/decorators.js"; + +import { clamp } from "../web/floating_color_picker"; +const log = debug("fade"); + +class Drag { + constructor(public startDragPxY: number, public startDragValue: number) {} +} + +@customElement("light9-fader") +export class Light9Fader extends LitElement { + static styles = [ + css` + :host { + display: inline-block; + border: 2px gray inset; + background: #000; + height: 250px; + } + #handle { + background: gray; + border: 5px gray outset; + position: relative; + left: 0; + right: -25px; + } + `, + ]; + + @property() value: number = 0; + + @query("#handle") handleEl!: HTMLElement; + + troughHeight = 250 - 2 - 2 - 5 - 5; + handleHeight = 20; + + drag?: Drag; + unmutedValue: number = 1; + + render() { + return html`

`; + } + + protected update(changedProperties: PropertyValueMap | Map): void { + super.update(changedProperties); + if (changedProperties.has("value")) { + this.value= clamp(this.value, 0, 1) + this.dispatchEvent(new CustomEvent("change", { detail: { value: this.value } })); + } + } + + protected updated(_changedProperties: PropertyValueMap | Map): void { + super.updated(_changedProperties); + const y = this.sliderTopY(this.value); + this.handleEl.style.top = y + "px"; + } + + protected firstUpdated(_changedProperties: PropertyValueMap | Map): void { + super.firstUpdated(_changedProperties); + this.handleEl.style.height = this.handleHeight + "px"; + this.events(); + } + + events() { + const hand = this.handleEl; + hand.addEventListener("mousedown", (ev: MouseEvent) => { + ev.stopPropagation(); + if (ev.buttons == 1) { + this.drag = new Drag(ev.clientY, this.value); + } else if (ev.buttons == 2) { + this.onRmb(); + } + }); + this.addEventListener("mousedown", (ev: MouseEvent) => { + ev.stopPropagation(); + if (ev.buttons == 1) { + this.value = this.sliderValue(ev.offsetY); + this.drag = new Drag(ev.clientY, this.value); + } else if (ev.buttons == 2) { + // RMB in trough + this.onRmb(); + } + }); + + this.addEventListener("contextmenu", (event) => { + event.preventDefault(); + }); + + this.addEventListener("wheel", (ev: WheelEvent) => { + ev.preventDefault(); + this.value += ev.deltaY / 120 * -.05; + }); + + const maybeDrag = (ev: MouseEvent) => { + if (ev.buttons != 1) return; + if (this.drag === undefined) return; + ev.stopPropagation(); + this.onMouseDrag(ev.clientY - this.drag.startDragPxY!); + }; + hand.addEventListener("mousemove", maybeDrag); + this.addEventListener("mousemove", maybeDrag); + window.addEventListener("mousemove", maybeDrag); + + hand.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); + this.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); + window.addEventListener("mouseup", this.onMouseUpAnywhere.bind(this)); + } + onRmb() { + if (this.value > 0.1) { + // mute + this.unmutedValue = this.value; + this.value = 0; + } else { + // unmute + this.value = this.unmutedValue; + } + } + onMouseDrag(dy: number) { + if (this.drag === undefined) throw "unexpected"; + this.value = this.drag.startDragValue - dy / this.troughHeight; + } + + onMouseUpAnywhere() { + this.drag = undefined; + } + + sliderTopY(value: number): number { + const usableY = this.troughHeight - this.handleHeight; + const yAdj = this.handleHeight / 2 - 5 - 2; + return (1 - value) * usableY + yAdj; + } + sliderValue(offsetY: number): number { + const usableY = this.troughHeight - this.handleHeight; + const yAdj = this.handleHeight / 2 - 5 - 2; + return clamp(1 - (offsetY - yAdj) / usableY, 0, 1); + } +}