// This is a vanillajs implementation of Houdini's number input widgets. // It basically popup a visual sensitivity slider of steps to use as incr/decr // TODO: Convert it to IWidget // import styles from "./style.module.css"; function getValidNumber(numberInput) { let num = isNaN(numberInput.value) || numberInput.value === '' ? 0 : parseFloat(numberInput.value) return num } /** * Number input widgets */ export class NumberInputWidget { constructor(containerId, numberOfInputs = 1, isDebug = false) { this.container = document.getElementById(containerId) this.numberOfInputs = numberOfInputs this.currentInput = null // Store the currently active input this.threshold = 30 this.mouseSensitivityMultiplier = 0.05 this.debug = isDebug //- states this.initialMouseX this.lastMouseX this.activeStep = 1 this.accumulatedDelta = 0 this.stepLocked = false this.thresholdExceeded = false this.isDragging = false const styleTagId = 'mtb-constant-style' let styleTag = document.head.querySelector(`#${styleTagId}`) if (!styleTag) { styleTag = document.createElement('style') styleTag.type = 'text/css' styleTag.id = styleTagId styleTag.innerHTML = ` .${containerId}{ margin-top: 20px; margin-bottom: 20px; } .sensitivity-menu { display: none; position: absolute; /* Additional styling */ } .sensitivity-menu .step { cursor: pointer; padding: 0.5em; /* Add more styling as needed */ } .sensitivity-menu { font-family: monospace; background: var(--bg-color); border: 1px solid var(--fg-color); /* Highlight for the active step */ } .number-input { background: var(--bg-color); color: var(--fg-color) } .sensitivity-menu .step.active { background-color:var(--drag-text); /* Highlight for the active step */ } .sensitivity-menu .step.locked { background-color: #f00; /* Change to your preferred color for the locked state */ } #debug-container { transform: translateX(50%); width: 50%; text-align: center; font-family: monospace; } ` document.head.appendChild(styleTag) } this.createWidgetElements() this.initializeEventListeners() } setLabel(str) { this.label.textContent = str } setValue(...values) { if (values.length !== this.numberInputs.length) { console.error('Number of values does not match the number of inputs.') console.error( `You provided ${values.length} but the input want ${this.numberInputs.length}`, { values }, ) return } // Set each input value this.numberInputs.forEach((input, index) => { input.value = values[index] }) } getValue() { const value = [] this.numberInputs.forEach((input, index) => { value.push(Number.parseFloat(input.value) || 0.0) }) return value } resetValues() { for (const input of numberInputs) { input.value = 0 } this.onChange?.(this.getValue()) } createWidgetElements() { this.label = document.createElement('label') this.label.textContent = 'Control All:' this.label.className = 'widget-label' this.container.appendChild(this.label) this.label.addEventListener('mousedown', (event) => { if (event.button === 1) { this.currentInput = null this.handleMouseDown(event) } }) this.label.addEventListener('contextmenu', (event) => { event.preventDefault() this.resetValues() }) this.numberInputs = [] // create linked inputs for (let i = 0; i < this.numberOfInputs; i++) { const numberInput = document.createElement('input') numberInput.type = 'number' numberInput.className = 'number-input' //styles.numberInput; //"number-input"; numberInput.step = 'any' this.container.appendChild(numberInput) this.numberInputs.push(numberInput) numberInput.addEventListener('mousedown', (event) => { if (event.button === 1) { this.currentInput = numberInput this.handleMouseDown(event) } }) } this.sensitivityMenu = document.createElement('div') this.sensitivityMenu.className = 'sensitivity-menu' //styles.sensitivityMenu; //"sensitivity-menu"; this.container.appendChild(this.sensitivityMenu) // create steps const stepsValues = [0.001, 0.01, 0.1, 1, 10, 100] stepsValues.forEach((value) => { const step = document.createElement('div') step.className = 'step' //styles.step //"step"; step.dataset.step = value step.textContent = value.toString() this.sensitivityMenu.appendChild(step) }) this.steps = this.sensitivityMenu.getElementsByClassName('step') //styles.step) if (this.debug) { this.debugContainer = document.createElement('div') this.debugContainer.id = 'debug-container' //styles.debugContainer //"debugContainer"; document.body.appendChild(this.debugContainer) } } showSensitivityMenu(pageX, pageY) { this.sensitivityMenu.style.display = 'block' this.sensitivityMenu.style.left = `${pageX}px` this.sensitivityMenu.style.top = `${pageY}px` this.initialMouseX = pageX this.lastMouseX = pageX this.isDragging = true this.thresholdExceeded = false this.stepLocked = false this.updateDebugInfo() } updateDebugInfo() { if (this.debug) { this.debugContainer.innerHTML = `