From 779cb259cef9a4674128a27ff30c45c452579135 Mon Sep 17 00:00:00 2001 From: MostlyK <135974627+MostlyKIGuess@users.noreply.github.com> Date: Wed, 15 Jan 2025 00:23:07 +0530 Subject: [PATCH 1/2] RhythmRuler: wheel navigation for number selection --- js/widgets/rhythmruler.js | 95 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 6 deletions(-) diff --git a/js/widgets/rhythmruler.js b/js/widgets/rhythmruler.js index 47b92761fe..ca79f69094 100644 --- a/js/widgets/rhythmruler.js +++ b/js/widgets/rhythmruler.js @@ -20,7 +20,7 @@ TONEBPM, Singer, _, delayExecution, docById, calcNoteValueToDisplay, platformColor, beginnerMode, last, EIGHTHNOTEWIDTH, nearestBeat, rationalToFraction, DRUMNAMES, - VOICENAMES, EFFECTSNAMES + VOICENAMES, EFFECTSNAMES, wheelnav, slicePath */ /* Globals location @@ -560,15 +560,98 @@ class RhythmRuler { * @private * @returns {void} */ - this._dissectNumber.oninput = () => { - // Put a limit on the size (2 <--> 128). - this._dissectNumber.onmouseout = () => { - this._dissectNumber.value = Math.max(this._dissectNumber.value, 2); + const that = this; + this._dissectNumber.onclick = (event) => { + const values = activity.beginnerMode ? [2, 3, 4] : [2, 3, 4, 5, 7]; + + const menuDiv = docById('wheelDivptm'); + menuDiv.innerHTML = ''; + + menuDiv.style.display = ''; + const x = event.clientX - 50; + const y = event.clientY - 50; + menuDiv.style.position = 'absolute'; + menuDiv.style.left = Math.min(activity.canvas.width - 200, Math.max(0, x)) + 'px'; + menuDiv.style.top = Math.min(activity.canvas.height - 250, Math.max(0, y)) + 'px'; + + const wheelNav = new wheelnav('wheelDivptm', null, 200, 200); + wheelNav.colors = platformColor.wheelcolors; + wheelNav.slicePathFunction = slicePath().DonutSlice; + wheelNav.slicePathCustom = slicePath().DonutSliceCustomization(); + wheelNav.sliceSelectedPathCustom = wheelNav.slicePathCustom; + wheelNav.sliceInitPathCustom = wheelNav.slicePathCustom; + wheelNav.clickModeRotate = false; + + const exitMenu = () => { + menuDiv.style.display = 'none'; + document.removeEventListener('click', handleOutside); + if (wheelNav) { + wheelNav.removeWheel(); + } }; - this._dissectNumber.value = Math.max(Math.min(this._dissectNumber.value, 128), 2); + // Click outside to close + const handleOutside = (e) => { + if (!menuDiv.contains(e.target) && e.target !== that._dissectNumber) { + exitMenu(); + } + }; + setTimeout(() => { + document.addEventListener('click', handleOutside); + }, 0); + + // Configure center button for close + wheelNav.centerButton = true; + wheelNav.centerButtonRadius = 25; + wheelNav.centerButtonHover = true; + wheelNav.centerButtonClickable = true; + wheelNav.centerButtonCallback = exitMenu; + wheelNav.centerButtonContent = '×'; + + const labels = values.map(v => v.toString()); + wheelNav.initWheel(labels); + wheelNav.createWheel(); + + // Add click handlers for numbers + for (let i = 0; i < values.length; i++) { + wheelNav.navItems[i].navigateFunction = () => { + that._dissectNumber.value = values[i]; + that._update(); + exitMenu(); + }; + } + // manual entry + const inputDiv = document.createElement('div'); + inputDiv.style.position = 'absolute'; + inputDiv.style.top = '50%'; + inputDiv.style.left = '50%'; + inputDiv.style.transform = 'translate(-50%, -50%)'; + const input = document.createElement('input'); + input.type = 'number'; + input.min = '2'; + input.max = '128'; + input.value = that._dissectNumber.value; + + input.oninput = () => { + if (input.value.length > 3) { + input.value = input.value.slice(0, 3); + } + // Ensure value is between 2-128 + let value = parseInt(input.value); + if (value < 2) input.value = '2'; + if (value > 128) input.value = '128'; + }; + input.onchange = () => { + that._dissectNumber.value = input.value; + that._update(); + exitMenu(); + }; + inputDiv.appendChild(input); + menuDiv.appendChild(inputDiv); }; + // Remove mouseout handler + this._dissectNumber.onmouseout = null; /** * Event handler for the click event of the undo button. * Undoes the last action. From 0b91ffa2ee9fb8d16f7e026bd8f6bea7183e04b9 Mon Sep 17 00:00:00 2001 From: MostlyK <135974627+MostlyKIGuess@users.noreply.github.com> Date: Mon, 20 Jan 2025 20:10:11 +0530 Subject: [PATCH 2/2] menu removal on click --- js/widgets/rhythmruler.js | 69 +++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/js/widgets/rhythmruler.js b/js/widgets/rhythmruler.js index ca79f69094..3b90e698a1 100644 --- a/js/widgets/rhythmruler.js +++ b/js/widgets/rhythmruler.js @@ -563,33 +563,35 @@ class RhythmRuler { const that = this; this._dissectNumber.onclick = (event) => { const values = activity.beginnerMode ? [2, 3, 4] : [2, 3, 4, 5, 7]; - + const menuDiv = docById('wheelDivptm'); menuDiv.innerHTML = ''; - + menuDiv.style.display = ''; const x = event.clientX - 50; const y = event.clientY - 50; menuDiv.style.position = 'absolute'; menuDiv.style.left = Math.min(activity.canvas.width - 200, Math.max(0, x)) + 'px'; menuDiv.style.top = Math.min(activity.canvas.height - 250, Math.max(0, y)) + 'px'; - - const wheelNav = new wheelnav('wheelDivptm', null, 200, 200); + + const wheelNav = new wheelnav('wheelDivptm', null, 150, 150); wheelNav.colors = platformColor.wheelcolors; wheelNav.slicePathFunction = slicePath().DonutSlice; wheelNav.slicePathCustom = slicePath().DonutSliceCustomization(); wheelNav.sliceSelectedPathCustom = wheelNav.slicePathCustom; wheelNav.sliceInitPathCustom = wheelNav.slicePathCustom; wheelNav.clickModeRotate = false; + wheelNav.navItemsSize = 30; const exitMenu = () => { menuDiv.style.display = 'none'; document.removeEventListener('click', handleOutside); + document.removeEventListener('keydown', handleKeydown); if (wheelNav) { wheelNav.removeWheel(); } }; - + // Click outside to close const handleOutside = (e) => { if (!menuDiv.contains(e.target) && e.target !== that._dissectNumber) { @@ -599,27 +601,7 @@ class RhythmRuler { setTimeout(() => { document.addEventListener('click', handleOutside); }, 0); - - // Configure center button for close - wheelNav.centerButton = true; - wheelNav.centerButtonRadius = 25; - wheelNav.centerButtonHover = true; - wheelNav.centerButtonClickable = true; - wheelNav.centerButtonCallback = exitMenu; - wheelNav.centerButtonContent = '×'; - - const labels = values.map(v => v.toString()); - wheelNav.initWheel(labels); - wheelNav.createWheel(); - - // Add click handlers for numbers - for (let i = 0; i < values.length; i++) { - wheelNav.navItems[i].navigateFunction = () => { - that._dissectNumber.value = values[i]; - that._update(); - exitMenu(); - }; - } + // manual entry const inputDiv = document.createElement('div'); inputDiv.style.position = 'absolute'; @@ -631,7 +613,7 @@ class RhythmRuler { input.min = '2'; input.max = '128'; input.value = that._dissectNumber.value; - + input.oninput = () => { if (input.value.length > 3) { input.value = input.value.slice(0, 3); @@ -641,13 +623,44 @@ class RhythmRuler { if (value < 2) input.value = '2'; if (value > 128) input.value = '128'; }; + input.onchange = () => { that._dissectNumber.value = input.value; - that._update(); exitMenu(); }; inputDiv.appendChild(input); menuDiv.appendChild(inputDiv); + + // enter key project can't run + const handleKeydown = (e) => { + if (e.key === 'Enter') { + // console.log('enter'); + e.preventDefault(); + input.blur(); + exitMenu(); + } + }; + document.addEventListener('keydown', handleKeydown); + + // Configure center button for close + wheelNav.centerButton = true; + wheelNav.centerButtonRadius = 25; + wheelNav.centerButtonHover = true; + wheelNav.centerButtonClickable = true; + wheelNav.centerButtonCallback = exitMenu; + wheelNav.centerButtonContent = '×'; + + const labels = values.map(v => v.toString()); + wheelNav.initWheel(labels); + wheelNav.createWheel(); + + // Add click handlers for numbers + for (let i = 0; i < values.length; i++) { + wheelNav.navItems[i].navigateFunction = () => { + that._dissectNumber.value = values[i]; + exitMenu(); + }; + } }; // Remove mouseout handler