Enhancement: options showIf

This commit is contained in:
Ladd 2026-01-04 13:29:19 -06:00
parent 4eec03dd1f
commit 54ed2838f7
4 changed files with 103 additions and 19 deletions

View File

@ -1,2 +1,38 @@
export function makeUtilityButton() {
// `items` is an array of which `item` is a member
// `item` must let us read/write property `hidden`
// `parentEl` is the containing element for `itemEl`
// `itemEl` is the
export function show({items, item, parentEl, itemEl}) {
if (items.length < 2) {
parentEl.appendChild(itemEl);
return;
}
// To determine placement,
// Start with our index in the toolbar tools;
// iterate through toolbar tools before this one,
// and subtract hidden ones from the index.
let countHidden = 0;
let index = items.indexOf(item);
for (let i = 0; i < index; i++) {
const sibling = items[i];
if (sibling.hidden) countHidden += 1;
}
index -= countHidden;
// Now we need to find our place.
// Add to parent using insertBefore.
let idx = 0;
let nextEl = parentEl.firstChild;
while (idx < index) {
nextEl = nextEl.nextSibling;
idx += 1;
}
parentEl.insertBefore(itemEl, nextEl);
item.hidden = false;
}
export function hide({item, parentEl, itemEl}) {
parentEl.removeChild(itemEl);
item.hidden = true;
}

View File

@ -8,9 +8,9 @@ export const simOptions = {
velocity: ['Velocity Vectors', 'boolean', true],
acceleration: ['Accel Vectors', 'boolean', true],
traces: ['Path Traces', 'boolean', true],
dashedTraces: ['Dashed', 'boolean', false, {tall: true, hideUnless: 'display.traces'}],
velocityScale: ['Velocity<br>Vec Scale', 'number', 80, {hideUnless: 'display.velocity'}],
accelerationScale: ['Accel<br>Vec Scale', 'number', 800, {hideUnless: 'display.acceleration'}],
dashedTraces: ['Dashed', 'boolean', false, {tall: true, showIf: 'display.traces'}],
velocityScale: ['Velocity<br>Vec Scale', 'number', 80, {showIf: 'display.velocity'}],
accelerationScale: ['Accel<br>Vec Scale', 'number', 800, {showIf: 'display.acceleration'}],
zoomVectors: ['Zoom Vectors', 'boolean', true]
},
compensate: {

View File

@ -9,6 +9,7 @@ import {
export class Tool {
container = undefined;
sim = undefined;
hidden = false;
constructor() {
const div = document.createElement('div');

View File

@ -1,45 +1,92 @@
// Options picker
import {
TOOL_INFO_CLASSNAME,
OPTION_GROUP_CLASSNAME,
WIDE_CLASSNAME,
TALL_CLASSNAME,
TOOL_INFO_CLASSNAME,
WIDE_CLASSNAME,
} from '../config.js';
import { Tool } from '../tool.js';
import {Tool} from '../tool.js';
import {show, hide} from '../helper.js';
export class OptionsTool extends Tool {
sections = undefined;
sectionNames = undefined;
groups = {};
constructor(sections) {
constructor(sectionNames) {
super();
this.sections = sections;
this.sectionNames = sectionNames;
}
setContainer(container) {
super.setContainer(container);
for (const sectionName of this.sections) {
const option = this.sim.options.getSection(sectionName);
const item = this.visitItem(option);
// Initialize
for (const sectionName of this.sectionNames) {
const group = this.sim.options.getSection(sectionName);
const item = this.visitItem(group);
this.div.appendChild(item);
}
}
// For now, `showIf` must be the name of a boolean property, with optional negation
shouldShow(option) {
if (option.showIf === undefined) return true;
const {name, value} = this.deconstructOption(option.showIf);
return this.sim.getOption(name) === value;
}
deconstructOption(showIf) {
let name = showIf;
let value = true;
if (name.startsWith('!')) {
value = false;
name = name.slice(1);
}
return {name, value};
}
visitItem(item, path) {
path = [path, item.name].filter(x => !!x).join('.');
switch (item.type) {
case 'group': {
const group = document.createElement('div');
group.classList.add(OPTION_GROUP_CLASSNAME);
const groupEl = document.createElement('div');
groupEl.classList.add(OPTION_GROUP_CLASSNAME);
const group = {groupEl, items: []};
this.groups[path] = group;
if (item.title) {
const heading = document.createElement('h3');
heading.innerHTML = item.title;
group.appendChild(heading);
groupEl.appendChild(heading);
groupEl.items.push({itemEl: heading});
}
for (const next of item.items) {
const child = this.visitItem(next, path);
group.appendChild(child);
const optionEl = this.visitItem(next, path);
// const option = {itemEl: optionEl};
group.items.push(next);
if (this.shouldShow(next)) {
groupEl.appendChild(optionEl);
}
if (next.showIf) {
const {name} = this.deconstructOption(next.showIf);
this.sim.onOptionSet(name, () => {
if (this.shouldShow(next)) {
show({
items: group.items,
item: next,
parentEl: groupEl,
itemEl: optionEl,
});
} else {
hide({
item: next,
parentEl: groupEl,
itemEl: optionEl,
});
}
});
}
}
return group;
return groupEl;
}
case 'boolean': {
const button = document.createElement('button');