From 147c3c00a24f7099f531473efe0f1bad22b6ffee Mon Sep 17 00:00:00 2001 From: DJ Cross Date: Tue, 30 Jan 2024 11:27:59 +1300 Subject: [PATCH] 7 support multiselect (#18) * Add multiselect using shift click and batch shift/change fill effect * Add key deselection and finer grain movement/resizing * Move right click menu to left hand side when there is not enough space --- README.md | 2 +- js/keyboard.js | 2 +- js/keymenu.js | 153 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 122 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 452ec5e..de9b7bc 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Pressure-sensitive display for the analogue values of your Wooting keyboard! Vis ### Customisation and Presets Woot-verlay is made to be extremely customisable. Right-click on keys to rename, change the fill direction or delete them. -Drag the keys to shift them around. Grab the green or orange dotted edges of a key to resize. +Drag the keys to shift them around. Grab the green or orange dotted edges of a key to resize. Shift click to multi select.
Presets are available to save and import. They can be found [here in the project wiki!](https://github.com/DjCrqss/Woot-verlay/wiki/Presets) diff --git a/js/keyboard.js b/js/keyboard.js index 0174496..0ca5035 100644 --- a/js/keyboard.js +++ b/js/keyboard.js @@ -50,7 +50,7 @@ function buildKey(curKey) { curLabel.textContent = curKey.label; // make key draggable and listen to other mouse events - dragElement(curDiv); + keyInteract(curDiv); buildOptions(); } diff --git a/js/keymenu.js b/js/keymenu.js index 5e86eff..87d2117 100644 --- a/js/keymenu.js +++ b/js/keymenu.js @@ -2,12 +2,22 @@ const menuDialog = document.getElementById("keyOptionDialog"); const renameInput = document.getElementById("keyLabel"); -var activeKey; + +var activeKey; // current key being interacted with for single select and for right click menu positioning +var selectedKeys = new Set(); // list of keys selected with shift or box select + // show menu function showOptions() { menuDialog.style.display = "flex"; - menuDialog.style.top = parseInt(activeKey.style.top) + 8 + "px"; - menuDialog.style.left = parseInt(activeKey.style.left) + activeKey.clientWidth + 20 + "px"; + menuDialog.style.top = parseInt(activeKey.style.top) + 8 - window.scrollY + "px"; + + // if key is too close to the right side of the screen, show menu on the left + if (parseInt(activeKey.style.left) + activeKey.clientWidth + menuDialog.offsetWidth > window.innerWidth) { + menuDialog.style.left = parseInt(activeKey.style.left) - menuDialog.clientWidth - window.scrollX + "px"; + } else { + menuDialog.style.left = parseInt(activeKey.style.left) + activeKey.clientWidth + 20 - window.scrollX + "px"; + } + if(activeKey != null) { renameInput.value = activeKey.getElementsByClassName('label')[0].innerHTML; } @@ -16,9 +26,10 @@ function showOptions() { // update direction of key object function updateKeySettings(direction) { if (activeKey != null) { - var progress = activeKey.getElementsByClassName('progress')[0]; - progress.className = "progress"; - progress.classList.add(direction); + selectedKeys.forEach(key => { + key.element.getElementsByClassName('progress')[0].className = "progress"; + key.element.getElementsByClassName('progress')[0].classList.add(direction); + }); } saveState(); } @@ -34,42 +45,88 @@ function updateKeyLabel(event){ // hide menu document.addEventListener("click", function (event) { - if (activeKey != null && !menuDialog.contains(event.target)) { + if (activeKey != null && !menuDialog.contains(event.target) && !activeKey.contains(event.target) + && ![...selectedKeys].some(x => x.element.contains(event.target)) && !event.shiftKey){ activeKey.style.backgroundColor = ""; activeKey = null; - hideDialog(); + deselect(); } }); +// add listener for CTRL + A +// document.addEventListener("keydown", function (event) { +// if (event.ctrlKey && event.key === 'a') { +// event.preventDefault(); +// // select all keys +// keyboard.childNodes.forEach(key => { +// select(key); +// }); +// } +// }); + + function hideDialog() { menuDialog.style.display = "none"; } async function removeKey() { if (activeKey != null) { - activeKey.style.opacity = 0; - activeKey.style.backgroundColor = "#925555"; hideDialog(); + selectedKeys.forEach(key => { + key.element.style.opacity = 0; + key.element.style.backgroundColor = "#925555"; + }); + await new Promise(resolve => setTimeout(resolve, 500)); - try { keyboard.removeChild(activeKey); } catch (exception) { } + try { + selectedKeys.forEach(key => { + keyboard.removeChild(key.element); + }); + } catch (exception) { } activeKey = null; + deselect(); saveState(); } } +async function select(elmnt){ + // if not already in selected keys, add to list + if(![...selectedKeys].some(x => x.element == elmnt)){ + selectedKeys.add({ + element: elmnt, + x: parseInt(elmnt.style.left), + y: parseInt(elmnt.style.top), + oldPosX: 0, + oldPosY: 0, + width: elmnt.clientWidth, + height: elmnt.clientHeight + }); + } + + activeKey = elmnt; + elmnt.style.backgroundColor = "var(--wooting-yellow)"; +} +async function deselect(){ + selectedKeys.forEach(key => { + key.element.style.backgroundColor = ""; + }); + selectedKeys.clear(); + hideDialog(); +} + // all functions related to dragging and resizing a key -function dragElement(elmnt) { +function keyInteract(elmnt) { // current position - var x = parseInt(elmnt.style.left); - var y = parseInt(elmnt.style.top); + var x = 0; + var y = 0; // curent size - var width = elmnt.clientWidth; - var height = elmnt.clientHeight; + var width = 0; + var height = 0; // previous mouse position var oldPosX = 0; var oldPosY = 0; - elmnt.onmousedown = dragMouseDown; + elmnt.onmousedown = mouseDown; elmnt.onmousemove = showResize; async function showResize(e){ @@ -84,32 +141,48 @@ function dragElement(elmnt) { } } - async function dragMouseDown(e) { + async function mouseDown(e) { e = e || window.event; e.preventDefault(); - // get the mouse cursor position at startup + // update initial values + x = parseInt(elmnt.style.left); + y = parseInt(elmnt.style.top); oldPosX = e.clientX; oldPosY = e.clientY; - document.onmouseup = closeDragElement; + width = elmnt.clientWidth; + height = elmnt.clientHeight; - // call a function whenever the cursor moves - if (e.button === 2) { // show options on left click - if(activeKey != null) { - activeKey.style.backgroundColor = ""; + document.onmouseup = mouseUp; + + + if (e.shiftKey && e.button === 0) { + // add to selection on shift click + if(![...selectedKeys].some(x => x.element == elmnt)){ + select(elmnt); + } else { + // remove from selection on shift click + selectedKeys.delete([...selectedKeys].find(x => x.element == elmnt)); + elmnt.style.backgroundColor = ""; } - activeKey = elmnt; - activeKey.style.backgroundColor = "var(--wooting-yellow)"; + } + // deselect if not shift click + else if(activeKey != null && ![...selectedKeys].some(x => x.element == elmnt)) { + deselect(); + } + + if (e.button === 2) { // show options on left click + select(elmnt); showOptions(); } else if(e.clientX > parseInt(elmnt.style.left) + elmnt.offsetWidth - 5 && e.clientY > parseInt(elmnt.style.top) + elmnt.offsetHeight - 5){ // resize both when dragging bottom right corner document.onmousemove = elementResizeBoth; - }else if ((e.clientX > parseInt(elmnt.style.left) + elmnt.offsetWidth - 5)) { // resize width when dragging right side + } else if ((e.clientX > parseInt(elmnt.style.left) + elmnt.offsetWidth - 5)) { // resize width when dragging right side document.onmousemove = elementResizeWidth; } else if (e.clientY > parseInt(elmnt.style.top) + elmnt.offsetHeight - 5) { // resize height when dragging bottom document.onmousemove = elementResizeHeight; } else { // move on drag document.onmousemove = elementDrag; } - + } @@ -164,18 +237,32 @@ function dragElement(elmnt) { e = e || window.event; e.preventDefault(); // calculate the new cursor position: - x += (e.clientX - oldPosX); - y += (e.clientY - oldPosY); - // set the element's new position: + + xDiff = e.clientX - oldPosX; + yDiff = e.clientY - oldPosY; + + x += xDiff; + y += yDiff; elmnt.style.top = snapGrid(y) + "px"; elmnt.style.left = snapGrid(x) + "px"; + + selectedKeys.forEach(key => { + // if(key.element == elmnt) return; + key.x += xDiff; + key.y += yDiff; + key.element.style.top = snapGrid(key.y) + "px"; + key.element.style.left = snapGrid(key.x) + "px"; + key.oldPosX = e.clientX; + key.oldPosY = e.clientY; + }); + // set old values oldPosX = e.clientX; oldPosY = e.clientY; } - function closeDragElement() { + function mouseUp() { // stop moving when mouse button is released: document.onmouseup = null; document.onmousemove = null; @@ -185,7 +272,7 @@ function dragElement(elmnt) { } function snapGrid(num) { - return Math.ceil(num / 6) * 6; + return Math.ceil(num / 4) * 4; }