aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js235
-rw-r--r--modules/restart.py23
-rw-r--r--modules/shared.py9
-rw-r--r--modules/ui_extensions.py11
-rw-r--r--webui.bat2
-rwxr-xr-xwebui.sh1
6 files changed, 144 insertions, 137 deletions
diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js
index 2a2ed999..4ecb3d36 100644
--- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js
+++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js
@@ -1,121 +1,125 @@
-// Helper functions
-// Get active tab
-function getActiveTab(elements, all = false) {
- const tabs = elements.img2imgTabs.querySelectorAll("button");
+onUiLoaded(async() => {
+ const elementIDs = {
+ img2imgTabs: "#mode_img2img .tab-nav",
+ inpaint: "#img2maskimg",
+ inpaintSketch: "#inpaint_sketch",
+ rangeGroup: "#img2img_column_size",
+ sketch: "#img2img_sketch",
+ };
+ const tabNameToElementId = {
+ "Inpaint sketch": elementIDs.inpaintSketch,
+ "Inpaint": elementIDs.inpaint,
+ "Sketch": elementIDs.sketch,
+ };
+
+ // Helper functions
+ // Get active tab
+ function getActiveTab(elements, all = false) {
+ const tabs = elements.img2imgTabs.querySelectorAll("button");
- if (all) return tabs;
+ if (all) return tabs;
- for (let tab of tabs) {
- if (tab.classList.contains("selected")) {
- return tab;
+ for (let tab of tabs) {
+ if (tab.classList.contains("selected")) {
+ return tab;
+ }
}
}
-}
-// Get tab ID
-function getTabId(elements, elementIDs) {
- const activeTab = getActiveTab(elements);
- const tabIdLookup = {
- "Sketch": elementIDs.sketch,
- "Inpaint sketch": elementIDs.inpaintSketch,
- "Inpaint": elementIDs.inpaint
- };
- return tabIdLookup[activeTab.innerText];
-}
-
-// 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);
+ // Get tab ID
+ function getTabId(elements) {
+ const activeTab = getActiveTab(elements);
+ return tabNameToElementId[activeTab.innerText];
+ }
+
+ // Wait until opts loaded
+ async function waitForOpts() {
+ for (;;) {
+ if (window.opts && Object.keys(window.opts).length) {
+ return window.opts;
}
- }, 100);
- });
-}
-
-// Check is hotkey valid
-function isSingleLetter(value) {
- return (
- typeof value === "string" && value.length === 1 && /[a-z]/i.test(value)
- );
-}
+ await new Promise(resolve => setTimeout(resolve, 100));
+ }
+ }
-// Create hotkeyConfig from opts
-function createHotkeyConfig(defaultHotkeysConfig, hotkeysConfigOpts) {
- const result = {};
- const usedKeys = new Set();
+ // Check is hotkey valid
+ function isSingleLetter(value) {
+ return (
+ typeof value === "string" && value.length === 1 && /[a-z]/i.test(value)
+ );
+ }
- 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];
+ // 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;
-}
+ return result;
+ }
-/**
- * The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio.
- * If the image display property is set to 'none', the mask breaks. To fix this, the function
- * temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds
- * to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on
- * very long images.
- */
+ /**
+ * The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio.
+ * If the image display property is set to 'none', the mask breaks. To fix this, the function
+ * temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds
+ * to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on
+ * very long images.
+ */
+ function restoreImgRedMask(elements) {
+ const mainTabId = getTabId(elements);
-function restoreImgRedMask(elements, elementIDs) {
- const mainTabId = getTabId(elements, elementIDs);
+ if (!mainTabId) return;
- if (!mainTabId) return;
+ const mainTab = gradioApp().querySelector(mainTabId);
+ const img = mainTab.querySelector("img");
+ const imageARPreview = gradioApp().querySelector("#imageARPreview");
- const mainTab = gradioApp().querySelector(mainTabId);
- const img = mainTab.querySelector("img");
- const imageARPreview = gradioApp().querySelector("#imageARPreview");
+ if (!img || !imageARPreview) return;
- if (!img || !imageARPreview) return;
+ imageARPreview.style.transform = "";
+ if (parseFloat(mainTab.style.width) > 865) {
+ const transformString = mainTab.style.transform;
+ const scaleMatch = transformString.match(/scale\(([-+]?[0-9]*\.?[0-9]+)\)/);
+ let zoom = 1; // default zoom
- imageARPreview.style.transform = "";
- if (parseFloat(mainTab.style.width) > 865) {
- const transformString = mainTab.style.transform;
- const scaleMatch = transformString.match(/scale\(([-+]?[0-9]*\.?[0-9]+)\)/);
- let zoom = 1; // default zoom
+ if (scaleMatch && scaleMatch[1]) {
+ zoom = Number(scaleMatch[1]);
+ }
- if (scaleMatch && scaleMatch[1]) {
- zoom = Number(scaleMatch[1]);
+ imageARPreview.style.transformOrigin = "0 0";
+ imageARPreview.style.transform = `scale(${zoom})`;
}
- imageARPreview.style.transformOrigin = "0 0";
- imageARPreview.style.transform = `scale(${zoom})`;
- }
-
- if (img.style.display !== "none") return;
+ if (img.style.display !== "none") return;
- img.style.display = "block";
+ img.style.display = "block";
- setTimeout(() => {
- img.style.display = "none";
- }, 400);
-}
+ setTimeout(() => {
+ img.style.display = "none";
+ }, 400);
+ }
-// Main
-onUiLoaded(async() => {
const hotkeysConfigOpts = await waitForOpts();
// Default config
@@ -137,38 +141,22 @@ onUiLoaded(async() => {
let mouseX, mouseY;
let activeElement;
- const elementIDs = {
- sketch: "#img2img_sketch",
- inpaint: "#img2maskimg",
- inpaintSketch: "#inpaint_sketch",
- img2imgTabs: "#mode_img2img .tab-nav",
- rangeGroup: "#img2img_column_size"
- };
-
- async function getElements() {
- const elements = await Promise.all(
- Object.values(elementIDs).map(id => gradioApp().querySelector(id))
- );
- return Object.fromEntries(
- Object.keys(elementIDs).map((key, index) => [key, elements[index]])
- );
- }
-
- const elements = await getElements();
+ const elements = Object.fromEntries(Object.keys(elementIDs).map((id) => [
+ id,
+ gradioApp().querySelector(elementIDs[id]),
+ ]));
const elemData = {};
// Apply functionality to the range inputs. Restore redmask and correct for long images.
- const rangeInputs = elements.rangeGroup ? elements.rangeGroup.querySelectorAll("input") :
+ const rangeInputs = elements.rangeGroup ? Array.from(elements.rangeGroup.querySelectorAll("input")) :
[
gradioApp().querySelector("#img2img_width input[type='range']"),
gradioApp().querySelector("#img2img_height input[type='range']")
];
- rangeInputs.forEach(input => {
- if (input) {
- input.addEventListener("input", () => restoreImgRedMask(elements, elementIDs));
- }
- });
+ for (const input of rangeInputs) {
+ input?.addEventListener("input", () => restoreImgRedMask(elements));
+ }
function applyZoomAndPan(elemId) {
const targetElement = gradioApp().querySelector(elemId);
@@ -223,12 +211,11 @@ onUiLoaded(async() => {
action: "Move canvas"
}
];
- hotkeys.forEach(function(hotkey) {
+ for (const hotkey of hotkeys) {
const p = document.createElement("p");
- p.innerHTML =
- "<b>" + hotkey.key + "</b>" + " - " + hotkey.action;
+ p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`;
tooltipContent.appendChild(p);
- });
+ }
// Add information and content elements to the tooltip element
tooltip.appendChild(info);
diff --git a/modules/restart.py b/modules/restart.py
new file mode 100644
index 00000000..18eacaf3
--- /dev/null
+++ b/modules/restart.py
@@ -0,0 +1,23 @@
+import os
+from pathlib import Path
+
+from modules.paths_internal import script_path
+
+
+def is_restartable() -> bool:
+ """
+ Return True if the webui is restartable (i.e. there is something watching to restart it with)
+ """
+ return bool(os.environ.get('SD_WEBUI_RESTART'))
+
+
+def restart_program() -> None:
+ """creates file tmp/restart and immediately stops the process, which webui.bat/webui.sh interpret as a command to start webui again"""
+
+ (Path(script_path) / "tmp" / "restart").touch()
+
+ stop_program()
+
+
+def stop_program() -> None:
+ os._exit(0)
diff --git a/modules/shared.py b/modules/shared.py
index 2bd7c6ec..c9ee2dd1 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -853,12 +853,3 @@ def walk_files(path, allowed_extensions=None):
continue
yield os.path.join(root, filename)
-
-
-def restart_program():
- """creates file tmp/restart and immediately stops the process, which webui.bat/webui.sh interpret as a command to start webui again"""
-
- with open(os.path.join(script_path, "tmp", "restart"), "w"):
- pass
-
- os._exit(0)
diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py
index 1ae516d7..4379a641 100644
--- a/modules/ui_extensions.py
+++ b/modules/ui_extensions.py
@@ -11,7 +11,7 @@ import html
import shutil
import errno
-from modules import extensions, shared, paths, config_states, errors
+from modules import extensions, shared, paths, config_states, errors, restart
from modules.paths_internal import config_states_dir
from modules.call_queue import wrap_gradio_gpu_call
@@ -49,7 +49,11 @@ def apply_and_restart(disable_list, update_list, disable_all):
shared.opts.disabled_extensions = disabled
shared.opts.disable_all_extensions = disable_all
shared.opts.save(shared.config_filename)
- shared.restart_program()
+
+ if restart.is_restartable():
+ restart.restart_program()
+ else:
+ restart.stop_program()
def save_config_state(name):
@@ -509,7 +513,8 @@ def create_ui():
with gr.TabItem("Installed", id="installed"):
with gr.Row(elem_id="extensions_installed_top"):
- apply = gr.Button(value="Apply and restart UI", variant="primary")
+ apply_label = ("Apply and restart UI" if restart.is_restartable() else "Apply and quit")
+ apply = gr.Button(value=apply_label, variant="primary")
check = gr.Button(value="Check for updates")
extensions_disable_all = gr.Radio(label="Disable all extensions", choices=["none", "extra", "all"], value=shared.opts.disable_all_extensions, elem_id="extensions_disable_all")
extensions_disabled_list = gr.Text(elem_id="extensions_disabled_list", visible=False).style(container=False)
diff --git a/webui.bat b/webui.bat
index 961fc7d4..42e7d517 100644
--- a/webui.bat
+++ b/webui.bat
@@ -3,7 +3,7 @@
if not defined PYTHON (set PYTHON=python)
if not defined VENV_DIR (set "VENV_DIR=%~dp0%venv")
-
+set SD_WEBUI_RESTART=tmp/restart
set ERROR_REPORTING=FALSE
mkdir tmp 2>NUL
diff --git a/webui.sh b/webui.sh
index c407b3ef..6c48e969 100755
--- a/webui.sh
+++ b/webui.sh
@@ -204,6 +204,7 @@ prepare_tcmalloc() {
}
KEEP_GOING=1
+export SD_WEBUI_RESTART=tmp/restart
while [[ "$KEEP_GOING" -eq "1" ]]; do
if [[ ! -z "${ACCELERATE}" ]] && [ ${ACCELERATE}="True" ] && [ -x "$(command -v accelerate)" ]; then
printf "\n%s\n" "${delimiter}"