diff options
Diffstat (limited to 'scripts/gui-common/widget-set.js')
-rw-r--r-- | scripts/gui-common/widget-set.js | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/scripts/gui-common/widget-set.js b/scripts/gui-common/widget-set.js new file mode 100644 index 0000000..b515831 --- /dev/null +++ b/scripts/gui-common/widget-set.js @@ -0,0 +1,319 @@ +/** + * JSDoc types + */ + +/** + * @typedef {"button" | "toggle" | "checkbox" | "slider" | "color-temp" | "color-light" | "color-wheel" | "thermostat" | "scrubber"} DescType + */ + +/** + * @typedef OSmButtonProps + * @property {string} [text] + * @property {*} [tv] + * @property {*} [fv] + */ + +/** + * @typedef OSmToggleProps + * @property {string} [text] + * @property {*} [tv] + * @property {*} [fv] + */ + +/** + * @typedef OSmSliderProps + * @property {number} min + * @property {number} max + * @property {number} [step] + * @property {number} [precision] + * @property {boolean} [percent] + */ + +/** + * @typedef OSmThermostatProps + * @property {number} gague + * @property {number} [deviation] + * @property {Color} [color_cold] + * @property {Color} [color_temperate] + * @property {Color} [color_warm] + * @property {number} [ct] + * @property {number} [tw] + */ + +/** + * @typedef OSmScrubberProps + * @property {number} max + * @property {number} min + * @property {number} step + * @property {number} [zones] + * @property {number} [speed] + * @property {number} [spring] + */ + +/** + * @typedef {OSmButtonProps | OSmToggleProps | OSmSliderProps | OSmThermostatProps | OSmScrubberProps} OSmAnyProps + */ + +/** + * @typedef {Object} DescBase + * @property {DescType} type + * @property {string} name + */ + +/** + * @typedef {DescBase & {type: "button", props: OSmButtonProps, state: never}} DescButton + */ + +/** + * @typedef {DescBase & {type: "toggle" | "checkbox", props: OSmToggleProps, state: boolean}} DescToggle + */ + +/** + * @typedef {DescBase & {type: "slider", props: OSmSliderProps, state: number}} DescSlider + */ + +/** + * @typedef {DescBase & {type: "color-temp", props: never, state: number}} DescColorTemp + */ + +/** + * @typedef {DescBase & {type: "color-light", props: never, state: number}} DescColorLight + */ + +/** + * @typedef {DescBase & {type: "color-wheel", props: never, state: Color}} DescColorWheel + */ + +/** + * @typedef {DescBase & {type: "thermostat", props: OSmThermostatProps, state: number}} DescThermostat + */ + +/** + * @typedef {DescBase & {type: "scrubber", props: OSmScrubberProps, state: number}} DescScrubber + */ + +/** + * @typedef {DescButton | DescToggle | DescSlider | DescColorTemp | DescColorLight | DescColorWheel | DescThermostat | DescScrubber} DescAny + */ + +class WidgetSet extends EventTarget{ + + #name = ""; + + /** @type {{[key: string]: Widget}} */ + widgets = {}; + + /** + * + * @param {DescAny[]} desc + * @param {string} name + */ + constructor(desc, name) + { + super(); + + this.#name = name; + this.#parse_desc(desc); + + for (let i in this.widgets) + { + this.widgets[i].addEventListener("change", this.#change.bind(this)); + } + } + + + /** + * @param {DescButton} desc + * @returns {WidgetButton} + */ + static parse_button(desc) + { + let merge = {...{tv: true, fv: false, text: ""}, ...desc.props}; + let out = new WidgetButton(merge.tv, merge.fv); + out.setId("name", desc.name); + out.element.innerText = merge.text; + return out; + } + + /** + * @param {DescToggle} desc + * @returns {WidgetToggle} + */ + static parse_toggle(desc) + { + let merge = {...{tv: true, fv: false, text: ""}, ...desc.props}; + let out; + + if (desc.type == "checkbox") + out = new WidgetCheckbox(desc.state ? merge.tv : merge.fv, merge.tv, merge.fv); + else + { + out = new WidgetToggle(desc.state ? merge.tv : merge.fv, merge.tv, merge.fv); + out.element.innerText = merge.text; + } + out.setId("name", desc.name); + + return out; + } + + /** + * @param {DescSlider} desc + * @returns {WidgetSlider} + */ + static parse_slider(desc) + { + let merge = {...{step: 0.1, precision: 1, percent: false}, ...desc.props}; + let out = new WidgetSlider(desc.state, merge.min, merge.max, merge.step, merge.precision, merge.percent); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorLight} desc + * @returns {WidgetColorLight} + */ + static parse_color_light(desc) + { + let out = new WidgetColorLight(Math.max(Math.min(desc.state, 1), 0)); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorTemp} desc + * @returns {WidgetColorTemp} + */ + static parse_color_temp(desc) + { + let out = new WidgetColorTemp(Math.max(Math.min(desc.state, 6000), 2700)); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescColorWheel} desc + * @returns {WidgetColorWheel} + */ + static parse_color_wheel(desc) + { + let value = new Color(...desc.state.channels); + let out = new WidgetColorWheel(value); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescThermostat} desc + * @returns {WidgetThermostat} + */ + static parse_thermostat(desc) + { + let merge = {...{ + deviation: 7, + color_cold: Color.from_rgb(0, 133, 255), + color_temperate: Color.from_rgb(18, 229, 82), + color_warm: Color.from_rgb(255, 149, 0), + ct: -2, + tw: 2, + }, ...desc.props}; + + let cc = new Color(...merge.color_cold.channels); + let ct = new Color(...merge.color_temperate.channels); + let cw = new Color(...merge.color_warm.channels); + + let out = new WidgetThermostat(desc.state, merge.gague, merge.deviation, cc, ct, cw, merge.ct, merge.tw); + out.setId("name", desc.name); + return out; + } + + /** + * @param {DescScrubber} desc + * @returns {WidgetScrubber} + */ + static parse_scrubber(desc) + { + let merge = {...{ + zones: 2, + speed: 300, + spring: 1.4 + }, ...desc.props}; + + let out = new WidgetScrubber(desc.state, merge.max, merge.min, merge.step, merge.zones, merge.speed, merge.spring); + out.setId("name", desc.name); + return out; + } + + /** + * + * @param {DescAny[]} desc + */ + #parse_desc (desc) + { + for (let i of desc) + { + let out; + switch (i.type) + { + case "button": + out = WidgetSet.parse_button(i); + break; + case "checkbox": + case "toggle": + out = WidgetSet.parse_toggle(i); + break; + case "slider": + out = WidgetSet.parse_slider(i); + break; + case "color-light": + out = WidgetSet.parse_color_light(i); + break; + case "color-temp": + out = WidgetSet.parse_color_temp(i); + break; + case "color-wheel": + out = WidgetSet.parse_color_wheel(i); + break; + case "thermostat": + out = WidgetSet.parse_thermostat(i); + break; + case "scrubber": + out = WidgetSet.parse_scrubber(i); + break; + } + this.widgets[i.name] = out; + } + } + + /** + * + * @param {CustomEvent} e + */ + #change(e) + { + /** + * @type {{widget: Widget, changed: string}} + */ + let d = e.detail; + + let detail = { + set: this.#name, + name: d.widget.get("name"), + changed: d.changed, + value: d.widget.get(d.changed) + }; + + this.dispatchEvent(new CustomEvent("change", {detail: detail})); + } + + /** + * + * @param {HTMLElement} el + */ + apply_to(el) + { + for (let i in this.widgets) + { + el.appendChild(this.widgets[i].element); + } + } +}
\ No newline at end of file |