Merge pull request #10902 from daswer123/dev
Improvement for zoom builtin extension
This commit is contained in:
commit
08109b9bc0
|
@ -14,13 +14,73 @@ function getActiveTab(elements, all = false) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait until opts loaded
|
||||||
|
async function waitForOpts() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const checkInterval = setInterval(() => {
|
||||||
|
if (window.opts && Object.keys(window.opts).length !== 0) {
|
||||||
|
clearInterval(checkInterval);
|
||||||
|
resolve(window.opts);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check is hotkey valid
|
||||||
|
function isSingleLetter(value) {
|
||||||
|
return (
|
||||||
|
typeof value === "string" && value.length === 1 && /[a-z]/i.test(value)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create hotkeyConfig from opts
|
||||||
|
function createHotkeyConfig(defaultHotkeysConfig, hotkeysConfigOpts) {
|
||||||
|
const result = {};
|
||||||
|
const usedKeys = new Set();
|
||||||
|
|
||||||
|
for (const key in defaultHotkeysConfig) {
|
||||||
|
if (typeof hotkeysConfigOpts[key] === "boolean") {
|
||||||
|
result[key] = hotkeysConfigOpts[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
hotkeysConfigOpts[key] &&
|
||||||
|
isSingleLetter(hotkeysConfigOpts[key]) &&
|
||||||
|
!usedKeys.has(hotkeysConfigOpts[key].toUpperCase())
|
||||||
|
) {
|
||||||
|
// If the property passed the test and has not yet been used, add 'Key' before it and save it
|
||||||
|
result[key] = "Key" + hotkeysConfigOpts[key].toUpperCase();
|
||||||
|
usedKeys.add(hotkeysConfigOpts[key].toUpperCase());
|
||||||
|
} else {
|
||||||
|
// If the property does not pass the test or has already been used, we keep the default value
|
||||||
|
console.error(
|
||||||
|
`Hotkey: ${hotkeysConfigOpts[key]} for ${key} is repeated and conflicts with another hotkey or is not 1 letter. The default hotkey is used: ${defaultHotkeysConfig[key][3]}`
|
||||||
|
);
|
||||||
|
result[key] = defaultHotkeysConfig[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main
|
||||||
onUiLoaded(async() => {
|
onUiLoaded(async() => {
|
||||||
const hotkeysConfig = {
|
const hotkeysConfigOpts = await waitForOpts();
|
||||||
resetZoom: "KeyR",
|
|
||||||
fitToScreen: "KeyS",
|
// Default config
|
||||||
moveKey: "KeyF",
|
const defaultHotkeysConfig = {
|
||||||
overlap: "KeyO"
|
canvas_hotkey_reset: "KeyR",
|
||||||
|
canvas_hotkey_fullscreen: "KeyS",
|
||||||
|
canvas_hotkey_move: "KeyF",
|
||||||
|
canvas_hotkey_overlap: "KeyO",
|
||||||
|
canvas_show_tooltip: true,
|
||||||
|
canvas_swap_controls: false
|
||||||
};
|
};
|
||||||
|
// swap the actions for ctr + wheel and shift + wheel
|
||||||
|
const hotkeysConfig = createHotkeyConfig(
|
||||||
|
defaultHotkeysConfig,
|
||||||
|
hotkeysConfigOpts
|
||||||
|
);
|
||||||
|
|
||||||
let isMoving = false;
|
let isMoving = false;
|
||||||
let mouseX, mouseY;
|
let mouseX, mouseY;
|
||||||
|
@ -48,6 +108,68 @@ onUiLoaded(async() => {
|
||||||
let [zoomLevel, panX, panY] = [1, 0, 0];
|
let [zoomLevel, panX, panY] = [1, 0, 0];
|
||||||
let fullScreenMode = false;
|
let fullScreenMode = false;
|
||||||
|
|
||||||
|
// Create tooltip
|
||||||
|
function createTooltip() {
|
||||||
|
const toolTipElemnt =
|
||||||
|
targetElement.querySelector(".image-container");
|
||||||
|
const tooltip = document.createElement("div");
|
||||||
|
tooltip.className = "tooltip";
|
||||||
|
|
||||||
|
// Creating an item of information
|
||||||
|
const info = document.createElement("i");
|
||||||
|
info.className = "tooltip-info";
|
||||||
|
info.textContent = "";
|
||||||
|
|
||||||
|
// Create a container for the contents of the tooltip
|
||||||
|
const tooltipContent = document.createElement("div");
|
||||||
|
tooltipContent.className = "tooltip-content";
|
||||||
|
|
||||||
|
// Add info about hotkets
|
||||||
|
const zoomKey = hotkeysConfig.canvas_swap_controls ? "Ctrl" : "Shift";
|
||||||
|
const adjustKey = hotkeysConfig.canvas_swap_controls ? "Shift" : "Ctrl";
|
||||||
|
|
||||||
|
const hotkeys = [
|
||||||
|
{key: `${zoomKey} + wheel`, action: "Zoom canvas"},
|
||||||
|
{key: `${adjustKey} + wheel`, action: "Adjust brush size"},
|
||||||
|
{
|
||||||
|
key: hotkeysConfig.canvas_hotkey_reset.charAt(
|
||||||
|
hotkeysConfig.canvas_hotkey_reset.length - 1
|
||||||
|
),
|
||||||
|
action: "Reset zoom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: hotkeysConfig.canvas_hotkey_fullscreen.charAt(
|
||||||
|
hotkeysConfig.canvas_hotkey_fullscreen.length - 1
|
||||||
|
),
|
||||||
|
action: "Fullscreen mode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: hotkeysConfig.canvas_hotkey_move.charAt(
|
||||||
|
hotkeysConfig.canvas_hotkey_move.length - 1
|
||||||
|
),
|
||||||
|
action: "Move canvas"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
hotkeys.forEach(function(hotkey) {
|
||||||
|
const p = document.createElement("p");
|
||||||
|
p.innerHTML =
|
||||||
|
"<b>" + hotkey.key + "</b>" + " - " + hotkey.action;
|
||||||
|
tooltipContent.appendChild(p);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add information and content elements to the tooltip element
|
||||||
|
tooltip.appendChild(info);
|
||||||
|
tooltip.appendChild(tooltipContent);
|
||||||
|
|
||||||
|
// Add a hint element to the target element
|
||||||
|
toolTipElemnt.appendChild(tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Show tool tip if setting enable
|
||||||
|
if (hotkeysConfig.canvas_show_tooltip) {
|
||||||
|
createTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
// In the course of research, it was found that the tag img is very harmful when zooming and creates white canvases. This hack allows you to almost never think about this problem, it has no effect on webui.
|
// In the course of research, it was found that the tag img is very harmful when zooming and creates white canvases. This hack allows you to almost never think about this problem, it has no effect on webui.
|
||||||
function fixCanvas() {
|
function fixCanvas() {
|
||||||
const activeTab = getActiveTab(elements).textContent.trim();
|
const activeTab = getActiveTab(elements).textContent.trim();
|
||||||
|
@ -159,7 +281,10 @@ onUiLoaded(async() => {
|
||||||
|
|
||||||
// Change the zoom level based on user interaction
|
// Change the zoom level based on user interaction
|
||||||
function changeZoomLevel(operation, e) {
|
function changeZoomLevel(operation, e) {
|
||||||
if (e.shiftKey) {
|
if (
|
||||||
|
(!hotkeysConfig.canvas_swap_controls && e.shiftKey) ||
|
||||||
|
(hotkeysConfig.canvas_swap_controls && e.ctrlKey)
|
||||||
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
let zoomPosX, zoomPosY;
|
let zoomPosX, zoomPosY;
|
||||||
|
@ -262,7 +387,8 @@ onUiLoaded(async() => {
|
||||||
targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`;
|
targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`;
|
||||||
|
|
||||||
// Get scrollbar width to right-align the image
|
// Get scrollbar width to right-align the image
|
||||||
const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
|
const scrollbarWidth =
|
||||||
|
window.innerWidth - document.documentElement.clientWidth;
|
||||||
|
|
||||||
// Get element and screen dimensions
|
// Get element and screen dimensions
|
||||||
const elementWidth = targetElement.offsetWidth;
|
const elementWidth = targetElement.offsetWidth;
|
||||||
|
@ -312,10 +438,9 @@ onUiLoaded(async() => {
|
||||||
// Handle keydown events
|
// Handle keydown events
|
||||||
function handleKeyDown(event) {
|
function handleKeyDown(event) {
|
||||||
const hotkeyActions = {
|
const hotkeyActions = {
|
||||||
[hotkeysConfig.resetZoom]: resetZoom,
|
[hotkeysConfig.canvas_hotkey_reset]: resetZoom,
|
||||||
[hotkeysConfig.overlap]: toggleOverlap,
|
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
|
||||||
[hotkeysConfig.fitToScreen]: fitToScreen
|
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen
|
||||||
// [hotkeysConfig.moveKey] : moveCanvas,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const action = hotkeyActions[event.code];
|
const action = hotkeyActions[event.code];
|
||||||
|
@ -369,7 +494,11 @@ onUiLoaded(async() => {
|
||||||
changeZoomLevel(operation, e);
|
changeZoomLevel(operation, e);
|
||||||
|
|
||||||
// Handle brush size adjustment with ctrl key pressed
|
// Handle brush size adjustment with ctrl key pressed
|
||||||
if (e.ctrlKey || e.metaKey) {
|
if (
|
||||||
|
(hotkeysConfig.canvas_swap_controls && e.shiftKey) ||
|
||||||
|
(!hotkeysConfig.canvas_swap_controls &&
|
||||||
|
(e.ctrlKey || e.metaKey))
|
||||||
|
) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
// Increase or decrease brush size based on scroll direction
|
// Increase or decrease brush size based on scroll direction
|
||||||
|
@ -377,20 +506,19 @@ onUiLoaded(async() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
// Handle the move event for pan functionality. Updates the panX and panY variables and applies the new transform to the target element.
|
||||||
* Handle the move event for pan functionality. Updates the panX and panY variables and applies the new transform to the target element.
|
|
||||||
* @param {MouseEvent} e - The mouse event.
|
|
||||||
*/
|
|
||||||
function handleMoveKeyDown(e) {
|
function handleMoveKeyDown(e) {
|
||||||
if (e.code === hotkeysConfig.moveKey) {
|
if (e.code === hotkeysConfig.canvas_hotkey_move) {
|
||||||
if (!e.ctrlKey && !e.metaKey) {
|
if (!e.ctrlKey && !e.metaKey && isKeyDownHandlerAttached) {
|
||||||
|
e.preventDefault();
|
||||||
|
document.activeElement.blur();
|
||||||
isMoving = true;
|
isMoving = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMoveKeyUp(e) {
|
function handleMoveKeyUp(e) {
|
||||||
if (e.code === hotkeysConfig.moveKey) {
|
if (e.code === hotkeysConfig.canvas_hotkey_move) {
|
||||||
isMoving = false;
|
isMoving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,6 +550,11 @@ onUiLoaded(async() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevents sticking to the mouse
|
||||||
|
window.onblur = function() {
|
||||||
|
isMoving = false;
|
||||||
|
};
|
||||||
|
|
||||||
gradioApp().addEventListener("mousemove", handleMoveByKey);
|
gradioApp().addEventListener("mousemove", handleMoveByKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
from modules import shared
|
||||||
|
|
||||||
|
shared.options_templates.update(shared.options_section(('canvas_hotkey', "Canvas Hotkeys"), {
|
||||||
|
"canvas_hotkey_move": shared.OptionInfo("F", "Moving the canvas"),
|
||||||
|
"canvas_hotkey_fullscreen": shared.OptionInfo("S", "Fullscreen Mode, maximizes the picture so that it fits into the screen and stretches it to its full width "),
|
||||||
|
"canvas_hotkey_reset": shared.OptionInfo("R", "Reset zoom and canvas positon"),
|
||||||
|
"canvas_hotkey_overlap": shared.OptionInfo("O", "Toggle overlap ( Technical button, neededs for testing )"),
|
||||||
|
"canvas_show_tooltip": shared.OptionInfo(True, "Enable tooltip on the canvas"),
|
||||||
|
"canvas_swap_controls": shared.OptionInfo(False, "Swap hotkey combinations for Zoom and Adjust brush resize"),
|
||||||
|
}))
|
|
@ -0,0 +1,63 @@
|
||||||
|
.tooltip-info {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
cursor: help;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-info::after {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 2px;
|
||||||
|
height: 7px;
|
||||||
|
background-color: white;
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-info::before {
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
width: 2px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip-content {
|
||||||
|
display: none;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 15px;
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 10px;
|
||||||
|
width: 250px;
|
||||||
|
font-size: 16px;
|
||||||
|
opacity: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
||||||
|
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip:hover .tooltip-content {
|
||||||
|
display: block;
|
||||||
|
animation: fadeIn 0.5s;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {opacity: 0;}
|
||||||
|
to {opacity: 1;}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue