diff --git a/extensions-builtin/Lora/extra_networks_lora.py b/extensions-builtin/Lora/extra_networks_lora.py index ba2945c6..005ff32c 100644 --- a/extensions-builtin/Lora/extra_networks_lora.py +++ b/extensions-builtin/Lora/extra_networks_lora.py @@ -6,9 +6,14 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): def __init__(self): super().__init__('lora') + self.errors = {} + """mapping of network names to the number of errors the network had during operation""" + def activate(self, p, params_list): additional = shared.opts.sd_lora + self.errors.clear() + if additional != "None" and additional in networks.available_networks and not any(x for x in params_list if x.items[0] == additional): p.all_prompts = [x + f"" for x in p.all_prompts] params_list.append(extra_networks.ExtraNetworkParams(items=[additional, shared.opts.extra_networks_default_multiplier])) @@ -56,4 +61,7 @@ class ExtraNetworkLora(extra_networks.ExtraNetwork): p.extra_generation_params["Lora hashes"] = ", ".join(network_hashes) def deactivate(self, p): - pass + if self.errors: + p.comment("Networks with errors: " + ", ".join(f"{k} ({v})" for k, v in self.errors.items())) + + self.errors.clear() diff --git a/extensions-builtin/Lora/lora_patches.py b/extensions-builtin/Lora/lora_patches.py new file mode 100644 index 00000000..59859e6f --- /dev/null +++ b/extensions-builtin/Lora/lora_patches.py @@ -0,0 +1,31 @@ +import torch + +import networks +from modules import patches + + +class LoraPatches: + def __init__(self): + self.Linear_forward = patches.patch(__name__, torch.nn.Linear, 'forward', networks.network_Linear_forward) + self.Linear_load_state_dict = patches.patch(__name__, torch.nn.Linear, '_load_from_state_dict', networks.network_Linear_load_state_dict) + self.Conv2d_forward = patches.patch(__name__, torch.nn.Conv2d, 'forward', networks.network_Conv2d_forward) + self.Conv2d_load_state_dict = patches.patch(__name__, torch.nn.Conv2d, '_load_from_state_dict', networks.network_Conv2d_load_state_dict) + self.GroupNorm_forward = patches.patch(__name__, torch.nn.GroupNorm, 'forward', networks.network_GroupNorm_forward) + self.GroupNorm_load_state_dict = patches.patch(__name__, torch.nn.GroupNorm, '_load_from_state_dict', networks.network_GroupNorm_load_state_dict) + self.LayerNorm_forward = patches.patch(__name__, torch.nn.LayerNorm, 'forward', networks.network_LayerNorm_forward) + self.LayerNorm_load_state_dict = patches.patch(__name__, torch.nn.LayerNorm, '_load_from_state_dict', networks.network_LayerNorm_load_state_dict) + self.MultiheadAttention_forward = patches.patch(__name__, torch.nn.MultiheadAttention, 'forward', networks.network_MultiheadAttention_forward) + self.MultiheadAttention_load_state_dict = patches.patch(__name__, torch.nn.MultiheadAttention, '_load_from_state_dict', networks.network_MultiheadAttention_load_state_dict) + + def undo(self): + self.Linear_forward = patches.undo(__name__, torch.nn.Linear, 'forward') + self.Linear_load_state_dict = patches.undo(__name__, torch.nn.Linear, '_load_from_state_dict') + self.Conv2d_forward = patches.undo(__name__, torch.nn.Conv2d, 'forward') + self.Conv2d_load_state_dict = patches.undo(__name__, torch.nn.Conv2d, '_load_from_state_dict') + self.GroupNorm_forward = patches.undo(__name__, torch.nn.GroupNorm, 'forward') + self.GroupNorm_load_state_dict = patches.undo(__name__, torch.nn.GroupNorm, '_load_from_state_dict') + self.LayerNorm_forward = patches.undo(__name__, torch.nn.LayerNorm, 'forward') + self.LayerNorm_load_state_dict = patches.undo(__name__, torch.nn.LayerNorm, '_load_from_state_dict') + self.MultiheadAttention_forward = patches.undo(__name__, torch.nn.MultiheadAttention, 'forward') + self.MultiheadAttention_load_state_dict = patches.undo(__name__, torch.nn.MultiheadAttention, '_load_from_state_dict') + diff --git a/extensions-builtin/Lora/network.py b/extensions-builtin/Lora/network.py index 8ecfa29a..d8e8dfb7 100644 --- a/extensions-builtin/Lora/network.py +++ b/extensions-builtin/Lora/network.py @@ -1,3 +1,4 @@ +from __future__ import annotations import os from collections import namedtuple import enum @@ -132,7 +133,7 @@ class NetworkModule: return 1.0 - def finalize_updown(self, updown, orig_weight, output_shape): + def finalize_updown(self, updown, orig_weight, output_shape, ex_bias=None): if self.bias is not None: updown = updown.reshape(self.bias.shape) updown += self.bias.to(orig_weight.device, dtype=orig_weight.dtype) @@ -144,7 +145,10 @@ class NetworkModule: if orig_weight.size().numel() == updown.size().numel(): updown = updown.reshape(orig_weight.shape) - return updown * self.calc_scale() * self.multiplier() + if ex_bias is not None: + ex_bias = ex_bias * self.multiplier() + + return updown * self.calc_scale() * self.multiplier(), ex_bias def calc_updown(self, target): raise NotImplementedError() diff --git a/extensions-builtin/Lora/network_full.py b/extensions-builtin/Lora/network_full.py index 109b4c2c..bf6930e9 100644 --- a/extensions-builtin/Lora/network_full.py +++ b/extensions-builtin/Lora/network_full.py @@ -14,9 +14,14 @@ class NetworkModuleFull(network.NetworkModule): super().__init__(net, weights) self.weight = weights.w.get("diff") + self.ex_bias = weights.w.get("diff_b") def calc_updown(self, orig_weight): output_shape = self.weight.shape updown = self.weight.to(orig_weight.device, dtype=orig_weight.dtype) + if self.ex_bias is not None: + ex_bias = self.ex_bias.to(orig_weight.device, dtype=orig_weight.dtype) + else: + ex_bias = None - return self.finalize_updown(updown, orig_weight, output_shape) + return self.finalize_updown(updown, orig_weight, output_shape, ex_bias) diff --git a/extensions-builtin/Lora/network_norm.py b/extensions-builtin/Lora/network_norm.py new file mode 100644 index 00000000..ce450158 --- /dev/null +++ b/extensions-builtin/Lora/network_norm.py @@ -0,0 +1,28 @@ +import network + + +class ModuleTypeNorm(network.ModuleType): + def create_module(self, net: network.Network, weights: network.NetworkWeights): + if all(x in weights.w for x in ["w_norm", "b_norm"]): + return NetworkModuleNorm(net, weights) + + return None + + +class NetworkModuleNorm(network.NetworkModule): + def __init__(self, net: network.Network, weights: network.NetworkWeights): + super().__init__(net, weights) + + self.w_norm = weights.w.get("w_norm") + self.b_norm = weights.w.get("b_norm") + + def calc_updown(self, orig_weight): + output_shape = self.w_norm.shape + updown = self.w_norm.to(orig_weight.device, dtype=orig_weight.dtype) + + if self.b_norm is not None: + ex_bias = self.b_norm.to(orig_weight.device, dtype=orig_weight.dtype) + else: + ex_bias = None + + return self.finalize_updown(updown, orig_weight, output_shape, ex_bias) diff --git a/extensions-builtin/Lora/networks.py b/extensions-builtin/Lora/networks.py index 17cbe1bb..96f935b2 100644 --- a/extensions-builtin/Lora/networks.py +++ b/extensions-builtin/Lora/networks.py @@ -1,12 +1,15 @@ +import logging import os import re +import lora_patches import network import network_lora import network_hada import network_ia3 import network_lokr import network_full +import network_norm import torch from typing import Union @@ -19,6 +22,7 @@ module_types = [ network_ia3.ModuleTypeIa3(), network_lokr.ModuleTypeLokr(), network_full.ModuleTypeFull(), + network_norm.ModuleTypeNorm(), ] @@ -31,6 +35,8 @@ suffix_conversion = { "resnets": { "conv1": "in_layers_2", "conv2": "out_layers_3", + "norm1": "in_layers_0", + "norm2": "out_layers_0", "time_emb_proj": "emb_layers_1", "conv_shortcut": "skip_connection", } @@ -190,11 +196,19 @@ def load_network(name, network_on_disk): net.modules[key] = net_module if keys_failed_to_match: - print(f"Failed to match keys when loading network {network_on_disk.filename}: {keys_failed_to_match}") + logging.debug(f"Network {network_on_disk.filename} didn't match keys: {keys_failed_to_match}") return net +def purge_networks_from_memory(): + while len(networks_in_memory) > shared.opts.lora_in_memory_limit and len(networks_in_memory) > 0: + name = next(iter(networks_in_memory)) + networks_in_memory.pop(name, None) + + devices.torch_gc() + + def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=None): already_loaded = {} @@ -212,15 +226,19 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No failed_to_load_networks = [] - for i, name in enumerate(names): + for i, (network_on_disk, name) in enumerate(zip(networks_on_disk, names)): net = already_loaded.get(name, None) - network_on_disk = networks_on_disk[i] - if network_on_disk is not None: + if net is None: + net = networks_in_memory.get(name) + if net is None or os.path.getmtime(network_on_disk.filename) > net.mtime: try: net = load_network(name, network_on_disk) + + networks_in_memory.pop(name, None) + networks_in_memory[name] = net except Exception as e: errors.display(e, f"loading network {network_on_disk.filename}") continue @@ -231,7 +249,7 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No if net is None: failed_to_load_networks.append(name) - print(f"Couldn't find network with name {name}") + logging.info(f"Couldn't find network with name {name}") continue net.te_multiplier = te_multipliers[i] if te_multipliers else 1.0 @@ -240,23 +258,38 @@ def load_networks(names, te_multipliers=None, unet_multipliers=None, dyn_dims=No loaded_networks.append(net) if failed_to_load_networks: - sd_hijack.model_hijack.comments.append("Failed to find networks: " + ", ".join(failed_to_load_networks)) + sd_hijack.model_hijack.comments.append("Networks not found: " + ", ".join(failed_to_load_networks)) + + purge_networks_from_memory() -def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.MultiheadAttention]): +def network_restore_weights_from_backup(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, torch.nn.MultiheadAttention]): weights_backup = getattr(self, "network_weights_backup", None) + bias_backup = getattr(self, "network_bias_backup", None) - if weights_backup is None: + if weights_backup is None and bias_backup is None: return - if isinstance(self, torch.nn.MultiheadAttention): - self.in_proj_weight.copy_(weights_backup[0]) - self.out_proj.weight.copy_(weights_backup[1]) + if weights_backup is not None: + if isinstance(self, torch.nn.MultiheadAttention): + self.in_proj_weight.copy_(weights_backup[0]) + self.out_proj.weight.copy_(weights_backup[1]) + else: + self.weight.copy_(weights_backup) + + if bias_backup is not None: + if isinstance(self, torch.nn.MultiheadAttention): + self.out_proj.bias.copy_(bias_backup) + else: + self.bias.copy_(bias_backup) else: - self.weight.copy_(weights_backup) + if isinstance(self, torch.nn.MultiheadAttention): + self.out_proj.bias = None + else: + self.bias = None -def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.MultiheadAttention]): +def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn.GroupNorm, torch.nn.LayerNorm, torch.nn.MultiheadAttention]): """ Applies the currently selected set of networks to the weights of torch layer self. If weights already have this particular set of networks applied, does nothing. @@ -271,7 +304,10 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn wanted_names = tuple((x.name, x.te_multiplier, x.unet_multiplier, x.dyn_dim) for x in loaded_networks) weights_backup = getattr(self, "network_weights_backup", None) - if weights_backup is None: + if weights_backup is None and wanted_names != (): + if current_names != (): + raise RuntimeError("no backup weights found and current weights are not unchanged") + if isinstance(self, torch.nn.MultiheadAttention): weights_backup = (self.in_proj_weight.to(devices.cpu, copy=True), self.out_proj.weight.to(devices.cpu, copy=True)) else: @@ -279,21 +315,41 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn self.network_weights_backup = weights_backup + bias_backup = getattr(self, "network_bias_backup", None) + if bias_backup is None: + if isinstance(self, torch.nn.MultiheadAttention) and self.out_proj.bias is not None: + bias_backup = self.out_proj.bias.to(devices.cpu, copy=True) + elif getattr(self, 'bias', None) is not None: + bias_backup = self.bias.to(devices.cpu, copy=True) + else: + bias_backup = None + self.network_bias_backup = bias_backup + if current_names != wanted_names: network_restore_weights_from_backup(self) for net in loaded_networks: module = net.modules.get(network_layer_name, None) if module is not None and hasattr(self, 'weight'): - with torch.no_grad(): - updown = module.calc_updown(self.weight) + try: + with torch.no_grad(): + updown, ex_bias = module.calc_updown(self.weight) - if len(self.weight.shape) == 4 and self.weight.shape[1] == 9: - # inpainting model. zero pad updown to make channel[1] 4 to 9 - updown = torch.nn.functional.pad(updown, (0, 0, 0, 0, 0, 5)) + if len(self.weight.shape) == 4 and self.weight.shape[1] == 9: + # inpainting model. zero pad updown to make channel[1] 4 to 9 + updown = torch.nn.functional.pad(updown, (0, 0, 0, 0, 0, 5)) - self.weight += updown - continue + self.weight += updown + if ex_bias is not None and hasattr(self, 'bias'): + if self.bias is None: + self.bias = torch.nn.Parameter(ex_bias) + else: + self.bias += ex_bias + except RuntimeError as e: + logging.debug(f"Network {net.name} layer {network_layer_name}: {e}") + extra_network_lora.errors[net.name] = extra_network_lora.errors.get(net.name, 0) + 1 + + continue module_q = net.modules.get(network_layer_name + "_q_proj", None) module_k = net.modules.get(network_layer_name + "_k_proj", None) @@ -301,21 +357,33 @@ def network_apply_weights(self: Union[torch.nn.Conv2d, torch.nn.Linear, torch.nn module_out = net.modules.get(network_layer_name + "_out_proj", None) if isinstance(self, torch.nn.MultiheadAttention) and module_q and module_k and module_v and module_out: - with torch.no_grad(): - updown_q = module_q.calc_updown(self.in_proj_weight) - updown_k = module_k.calc_updown(self.in_proj_weight) - updown_v = module_v.calc_updown(self.in_proj_weight) - updown_qkv = torch.vstack([updown_q, updown_k, updown_v]) - updown_out = module_out.calc_updown(self.out_proj.weight) + try: + with torch.no_grad(): + updown_q, _ = module_q.calc_updown(self.in_proj_weight) + updown_k, _ = module_k.calc_updown(self.in_proj_weight) + updown_v, _ = module_v.calc_updown(self.in_proj_weight) + updown_qkv = torch.vstack([updown_q, updown_k, updown_v]) + updown_out, ex_bias = module_out.calc_updown(self.out_proj.weight) - self.in_proj_weight += updown_qkv - self.out_proj.weight += updown_out - continue + self.in_proj_weight += updown_qkv + self.out_proj.weight += updown_out + if ex_bias is not None: + if self.out_proj.bias is None: + self.out_proj.bias = torch.nn.Parameter(ex_bias) + else: + self.out_proj.bias += ex_bias + + except RuntimeError as e: + logging.debug(f"Network {net.name} layer {network_layer_name}: {e}") + extra_network_lora.errors[net.name] = extra_network_lora.errors.get(net.name, 0) + 1 + + continue if module is None: continue - print(f'failed to calculate network weights for layer {network_layer_name}') + logging.debug(f"Network {net.name} layer {network_layer_name}: couldn't find supported operation") + extra_network_lora.errors[net.name] = extra_network_lora.errors.get(net.name, 0) + 1 self.network_current_names = wanted_names @@ -342,7 +410,7 @@ def network_forward(module, input, original_forward): if module is None: continue - y = module.forward(y, input) + y = module.forward(input, y) return y @@ -354,44 +422,74 @@ def network_reset_cached_weight(self: Union[torch.nn.Conv2d, torch.nn.Linear]): def network_Linear_forward(self, input): if shared.opts.lora_functional: - return network_forward(self, input, torch.nn.Linear_forward_before_network) + return network_forward(self, input, originals.Linear_forward) network_apply_weights(self) - return torch.nn.Linear_forward_before_network(self, input) + return originals.Linear_forward(self, input) def network_Linear_load_state_dict(self, *args, **kwargs): network_reset_cached_weight(self) - return torch.nn.Linear_load_state_dict_before_network(self, *args, **kwargs) + return originals.Linear_load_state_dict(self, *args, **kwargs) def network_Conv2d_forward(self, input): if shared.opts.lora_functional: - return network_forward(self, input, torch.nn.Conv2d_forward_before_network) + return network_forward(self, input, originals.Conv2d_forward) network_apply_weights(self) - return torch.nn.Conv2d_forward_before_network(self, input) + return originals.Conv2d_forward(self, input) def network_Conv2d_load_state_dict(self, *args, **kwargs): network_reset_cached_weight(self) - return torch.nn.Conv2d_load_state_dict_before_network(self, *args, **kwargs) + return originals.Conv2d_load_state_dict(self, *args, **kwargs) + + +def network_GroupNorm_forward(self, input): + if shared.opts.lora_functional: + return network_forward(self, input, originals.GroupNorm_forward) + + network_apply_weights(self) + + return originals.GroupNorm_forward(self, input) + + +def network_GroupNorm_load_state_dict(self, *args, **kwargs): + network_reset_cached_weight(self) + + return originals.GroupNorm_load_state_dict(self, *args, **kwargs) + + +def network_LayerNorm_forward(self, input): + if shared.opts.lora_functional: + return network_forward(self, input, originals.LayerNorm_forward) + + network_apply_weights(self) + + return originals.LayerNorm_forward(self, input) + + +def network_LayerNorm_load_state_dict(self, *args, **kwargs): + network_reset_cached_weight(self) + + return originals.LayerNorm_load_state_dict(self, *args, **kwargs) def network_MultiheadAttention_forward(self, *args, **kwargs): network_apply_weights(self) - return torch.nn.MultiheadAttention_forward_before_network(self, *args, **kwargs) + return originals.MultiheadAttention_forward(self, *args, **kwargs) def network_MultiheadAttention_load_state_dict(self, *args, **kwargs): network_reset_cached_weight(self) - return torch.nn.MultiheadAttention_load_state_dict_before_network(self, *args, **kwargs) + return originals.MultiheadAttention_load_state_dict(self, *args, **kwargs) def list_available_networks(): @@ -459,9 +557,14 @@ def infotext_pasted(infotext, params): params["Prompt"] += "\n" + "".join(added) +originals: lora_patches.LoraPatches = None + +extra_network_lora = None + available_networks = {} available_network_aliases = {} loaded_networks = [] +networks_in_memory = {} available_network_hash_lookup = {} forbidden_network_aliases = {} diff --git a/extensions-builtin/Lora/scripts/lora_script.py b/extensions-builtin/Lora/scripts/lora_script.py index cd28afc9..ef23968c 100644 --- a/extensions-builtin/Lora/scripts/lora_script.py +++ b/extensions-builtin/Lora/scripts/lora_script.py @@ -1,57 +1,30 @@ import re -import torch import gradio as gr from fastapi import FastAPI import network import networks import lora # noqa:F401 +import lora_patches import extra_networks_lora import ui_extra_networks_lora from modules import script_callbacks, ui_extra_networks, extra_networks, shared + def unload(): - torch.nn.Linear.forward = torch.nn.Linear_forward_before_network - torch.nn.Linear._load_from_state_dict = torch.nn.Linear_load_state_dict_before_network - torch.nn.Conv2d.forward = torch.nn.Conv2d_forward_before_network - torch.nn.Conv2d._load_from_state_dict = torch.nn.Conv2d_load_state_dict_before_network - torch.nn.MultiheadAttention.forward = torch.nn.MultiheadAttention_forward_before_network - torch.nn.MultiheadAttention._load_from_state_dict = torch.nn.MultiheadAttention_load_state_dict_before_network + networks.originals.undo() def before_ui(): ui_extra_networks.register_page(ui_extra_networks_lora.ExtraNetworksPageLora()) - extra_network = extra_networks_lora.ExtraNetworkLora() - extra_networks.register_extra_network(extra_network) - extra_networks.register_extra_network_alias(extra_network, "lyco") + networks.extra_network_lora = extra_networks_lora.ExtraNetworkLora() + extra_networks.register_extra_network(networks.extra_network_lora) + extra_networks.register_extra_network_alias(networks.extra_network_lora, "lyco") -if not hasattr(torch.nn, 'Linear_forward_before_network'): - torch.nn.Linear_forward_before_network = torch.nn.Linear.forward - -if not hasattr(torch.nn, 'Linear_load_state_dict_before_network'): - torch.nn.Linear_load_state_dict_before_network = torch.nn.Linear._load_from_state_dict - -if not hasattr(torch.nn, 'Conv2d_forward_before_network'): - torch.nn.Conv2d_forward_before_network = torch.nn.Conv2d.forward - -if not hasattr(torch.nn, 'Conv2d_load_state_dict_before_network'): - torch.nn.Conv2d_load_state_dict_before_network = torch.nn.Conv2d._load_from_state_dict - -if not hasattr(torch.nn, 'MultiheadAttention_forward_before_network'): - torch.nn.MultiheadAttention_forward_before_network = torch.nn.MultiheadAttention.forward - -if not hasattr(torch.nn, 'MultiheadAttention_load_state_dict_before_network'): - torch.nn.MultiheadAttention_load_state_dict_before_network = torch.nn.MultiheadAttention._load_from_state_dict - -torch.nn.Linear.forward = networks.network_Linear_forward -torch.nn.Linear._load_from_state_dict = networks.network_Linear_load_state_dict -torch.nn.Conv2d.forward = networks.network_Conv2d_forward -torch.nn.Conv2d._load_from_state_dict = networks.network_Conv2d_load_state_dict -torch.nn.MultiheadAttention.forward = networks.network_MultiheadAttention_forward -torch.nn.MultiheadAttention._load_from_state_dict = networks.network_MultiheadAttention_load_state_dict +networks.originals = lora_patches.LoraPatches() script_callbacks.on_model_loaded(networks.assign_network_names_to_compvis_modules) script_callbacks.on_script_unloaded(unload) @@ -65,6 +38,7 @@ shared.options_templates.update(shared.options_section(('extra_networks', "Extra "lora_add_hashes_to_infotext": shared.OptionInfo(True, "Add Lora hashes to infotext"), "lora_show_all": shared.OptionInfo(False, "Always show all networks on the Lora page").info("otherwise, those detected as for incompatible version of Stable Diffusion will be hidden"), "lora_hide_unknown_for_versions": shared.OptionInfo([], "Hide networks of unknown versions for model versions", gr.CheckboxGroup, {"choices": ["SD1", "SD2", "SDXL"]}), + "lora_in_memory_limit": shared.OptionInfo(0, "Number of Lora networks to keep cached in memory", gr.Number, {"precision": 0}), })) @@ -121,3 +95,5 @@ def infotext_pasted(infotext, d): script_callbacks.on_infotext_pasted(infotext_pasted) + +shared.opts.onchange("lora_in_memory_limit", networks.purge_networks_from_memory) diff --git a/extensions-builtin/Lora/ui_edit_user_metadata.py b/extensions-builtin/Lora/ui_edit_user_metadata.py index 2ca997f7..c7011909 100644 --- a/extensions-builtin/Lora/ui_edit_user_metadata.py +++ b/extensions-builtin/Lora/ui_edit_user_metadata.py @@ -70,6 +70,7 @@ class LoraUserMetadataEditor(ui_extra_networks_user_metadata.UserMetadataEditor) metadata = item.get("metadata") or {} keys = { + 'ss_output_name': "Output name:", 'ss_sd_model_name': "Model:", 'ss_clip_skip': "Clip skip:", 'ss_network_module': "Kohya module:", @@ -167,7 +168,7 @@ class LoraUserMetadataEditor(ui_extra_networks_user_metadata.UserMetadataEditor) random_prompt = gr.Textbox(label='Random prompt', lines=4, max_lines=4, interactive=False) with gr.Column(scale=1, min_width=120): - generate_random_prompt = gr.Button('Generate').style(full_width=True, size="lg") + generate_random_prompt = gr.Button('Generate', size="lg", scale=1) self.edit_notes = gr.TextArea(label='Notes', lines=4) diff --git a/extensions-builtin/Lora/ui_extra_networks_lora.py b/extensions-builtin/Lora/ui_extra_networks_lora.py index 1311b2f4..55409a78 100644 --- a/extensions-builtin/Lora/ui_extra_networks_lora.py +++ b/extensions-builtin/Lora/ui_extra_networks_lora.py @@ -25,9 +25,10 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): item = { "name": name, "filename": lora_on_disk.filename, - "preview": self.find_preview(path) if self.find_preview(path) else './file=html/card-no-preview.png', + "shorthash": lora_on_disk.shorthash, + "preview": self.find_preview(path), "description": self.find_description(path), - "search_term": self.search_terms_from_path(lora_on_disk.filename), + "search_term": self.search_terms_from_path(lora_on_disk.filename) + " " + (lora_on_disk.hash or ""), "local_preview": f"{path}.{shared.opts.samples_format}", "metadata": lora_on_disk.metadata, "sort_keys": {'default': index, **self.get_sort_keys(lora_on_disk.filename)}, @@ -67,7 +68,7 @@ class ExtraNetworksPageLora(ui_extra_networks.ExtraNetworksPage): def list_items(self): for index, name in enumerate(networks.available_networks): item = self.create_item(name, index) - + if item is not None: yield item diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 30199dcd..45c7600a 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -12,8 +12,22 @@ onUiLoaded(async() => { "Sketch": elementIDs.sketch }; + // Helper functions // Get active tab + + /** + * Waits for an element to be present in the DOM. + */ + const waitForElement = (id) => new Promise(resolve => { + const checkForElement = () => { + const element = document.querySelector(id); + if (element) return resolve(element); + setTimeout(checkForElement, 100); + }; + checkForElement(); + }); + function getActiveTab(elements, all = false) { const tabs = elements.img2imgTabs.querySelectorAll("button"); @@ -34,7 +48,7 @@ onUiLoaded(async() => { // Wait until opts loaded async function waitForOpts() { - for (;;) { + for (; ;) { if (window.opts && Object.keys(window.opts).length) { return window.opts; } @@ -42,6 +56,11 @@ onUiLoaded(async() => { } } + // Detect whether the element has a horizontal scroll bar + function hasHorizontalScrollbar(element) { + return element.scrollWidth > element.clientWidth; + } + // Function for defining the "Ctrl", "Shift" and "Alt" keys function isModifierKey(event, key) { switch (key) { @@ -201,7 +220,8 @@ onUiLoaded(async() => { canvas_hotkey_overlap: "KeyO", canvas_disabled_functions: [], canvas_show_tooltip: true, - canvas_blur_prompt: false + canvas_auto_expand: true, + canvas_blur_prompt: false, }; const functionMap = { @@ -249,7 +269,7 @@ onUiLoaded(async() => { input?.addEventListener("input", () => restoreImgRedMask(elements)); } - function applyZoomAndPan(elemId) { + function applyZoomAndPan(elemId, isExtension = true) { const targetElement = gradioApp().querySelector(elemId); if (!targetElement) { @@ -361,6 +381,12 @@ onUiLoaded(async() => { panY: 0 }; + if (isExtension) { + targetElement.style.overflow = "hidden"; + } + + targetElement.isZoomed = false; + fixCanvas(); targetElement.style.transform = `scale(${elemData[elemId].zoomLevel}) translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px)`; @@ -371,8 +397,27 @@ onUiLoaded(async() => { toggleOverlap("off"); fullScreenMode = false; + const closeBtn = targetElement.querySelector("button[aria-label='Remove Image']"); + if (closeBtn) { + closeBtn.addEventListener("click", resetZoom); + } + + if (canvas && isExtension) { + const parentElement = targetElement.closest('[id^="component-"]'); + if ( + canvas && + parseFloat(canvas.style.width) > parentElement.offsetWidth && + parseFloat(targetElement.style.width) > parentElement.offsetWidth + ) { + fitToElement(); + return; + } + + } + if ( canvas && + !isExtension && parseFloat(canvas.style.width) > 865 && parseFloat(targetElement.style.width) > 865 ) { @@ -381,9 +426,6 @@ onUiLoaded(async() => { } targetElement.style.width = ""; - if (canvas) { - targetElement.style.height = canvas.style.height; - } } // Toggle the zIndex of the target element between two values, allowing it to overlap or be overlapped by other elements @@ -439,7 +481,7 @@ onUiLoaded(async() => { // Update the zoom level and pan position of the target element based on the values of the zoomLevel, panX and panY variables function updateZoom(newZoomLevel, mouseX, mouseY) { - newZoomLevel = Math.max(0.5, Math.min(newZoomLevel, 15)); + newZoomLevel = Math.max(0.1, Math.min(newZoomLevel, 15)); elemData[elemId].panX += mouseX - (mouseX * newZoomLevel) / elemData[elemId].zoomLevel; @@ -450,6 +492,10 @@ onUiLoaded(async() => { targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${newZoomLevel})`; toggleOverlap("on"); + if (isExtension) { + targetElement.style.overflow = "visible"; + } + return newZoomLevel; } @@ -472,10 +518,12 @@ onUiLoaded(async() => { fullScreenMode = false; elemData[elemId].zoomLevel = updateZoom( elemData[elemId].zoomLevel + - (operation === "+" ? delta : -delta), + (operation === "+" ? delta : -delta), zoomPosX - targetElement.getBoundingClientRect().left, zoomPosY - targetElement.getBoundingClientRect().top ); + + targetElement.isZoomed = true; } } @@ -489,10 +537,19 @@ onUiLoaded(async() => { //Reset Zoom targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`; + let parentElement; + + if (isExtension) { + parentElement = targetElement.closest('[id^="component-"]'); + } else { + parentElement = targetElement.parentElement; + } + + // Get element and screen dimensions const elementWidth = targetElement.offsetWidth; const elementHeight = targetElement.offsetHeight; - const parentElement = targetElement.parentElement; + const screenWidth = parentElement.clientWidth; const screenHeight = parentElement.clientHeight; @@ -545,8 +602,12 @@ onUiLoaded(async() => { if (!canvas) return; - if (canvas.offsetWidth > 862) { - targetElement.style.width = canvas.offsetWidth + "px"; + if (canvas.offsetWidth > 862 || isExtension) { + targetElement.style.width = (canvas.offsetWidth + 2) + "px"; + } + + if (isExtension) { + targetElement.style.overflow = "visible"; } if (fullScreenMode) { @@ -648,8 +709,48 @@ onUiLoaded(async() => { mouseY = e.offsetY; } + // Simulation of the function to put a long image into the screen. + // We detect if an image has a scroll bar or not, make a fullscreen to reveal the image, then reduce it to fit into the element. + // We hide the image and show it to the user when it is ready. + + targetElement.isExpanded = false; + function autoExpand() { + const canvas = document.querySelector(`${elemId} canvas[key="interface"]`); + if (canvas) { + if (hasHorizontalScrollbar(targetElement) && targetElement.isExpanded === false) { + targetElement.style.visibility = "hidden"; + setTimeout(() => { + fitToScreen(); + resetZoom(); + targetElement.style.visibility = "visible"; + targetElement.isExpanded = true; + }, 10); + } + } + } + targetElement.addEventListener("mousemove", getMousePosition); + //observers + // Creating an observer with a callback function to handle DOM changes + const observer = new MutationObserver((mutationsList, observer) => { + for (let mutation of mutationsList) { + // If the style attribute of the canvas has changed, by observation it happens only when the picture changes + if (mutation.type === 'attributes' && mutation.attributeName === 'style' && + mutation.target.tagName.toLowerCase() === 'canvas') { + targetElement.isExpanded = false; + setTimeout(resetZoom, 10); + } + } + }); + + // Apply auto expand if enabled + if (hotkeysConfig.canvas_auto_expand) { + targetElement.addEventListener("mousemove", autoExpand); + // Set up an observer to track attribute changes + observer.observe(targetElement, {attributes: true, childList: true, subtree: true}); + } + // Handle events only inside the targetElement let isKeyDownHandlerAttached = false; @@ -754,6 +855,11 @@ onUiLoaded(async() => { if (isMoving && elemId === activeElement) { updatePanPosition(e.movementX, e.movementY); targetElement.style.pointerEvents = "none"; + + if (isExtension) { + targetElement.style.overflow = "visible"; + } + } else { targetElement.style.pointerEvents = "auto"; } @@ -764,13 +870,93 @@ onUiLoaded(async() => { isMoving = false; }; + // Checks for extension + function checkForOutBox() { + const parentElement = targetElement.closest('[id^="component-"]'); + if (parentElement.offsetWidth < targetElement.offsetWidth && !targetElement.isExpanded) { + resetZoom(); + targetElement.isExpanded = true; + } + + if (parentElement.offsetWidth < targetElement.offsetWidth && elemData[elemId].zoomLevel == 1) { + resetZoom(); + } + + if (parentElement.offsetWidth < targetElement.offsetWidth && targetElement.offsetWidth * elemData[elemId].zoomLevel > parentElement.offsetWidth && elemData[elemId].zoomLevel < 1 && !targetElement.isZoomed) { + resetZoom(); + } + } + + if (isExtension) { + targetElement.addEventListener("mousemove", checkForOutBox); + } + + + window.addEventListener('resize', (e) => { + resetZoom(); + + if (isExtension) { + targetElement.isExpanded = false; + targetElement.isZoomed = false; + } + }); + gradioApp().addEventListener("mousemove", handleMoveByKey); + + } - applyZoomAndPan(elementIDs.sketch); - applyZoomAndPan(elementIDs.inpaint); - applyZoomAndPan(elementIDs.inpaintSketch); + applyZoomAndPan(elementIDs.sketch, false); + applyZoomAndPan(elementIDs.inpaint, false); + applyZoomAndPan(elementIDs.inpaintSketch, false); // Make the function global so that other extensions can take advantage of this solution - window.applyZoomAndPan = applyZoomAndPan; + const applyZoomAndPanIntegration = async(id, elementIDs) => { + const mainEl = document.querySelector(id); + if (id.toLocaleLowerCase() === "none") { + for (const elementID of elementIDs) { + const el = await waitForElement(elementID); + if (!el) break; + applyZoomAndPan(elementID); + } + return; + } + + if (!mainEl) return; + mainEl.addEventListener("click", async() => { + for (const elementID of elementIDs) { + const el = await waitForElement(elementID); + if (!el) break; + applyZoomAndPan(elementID); + } + }, {once: true}); + }; + + window.applyZoomAndPan = applyZoomAndPan; // Only 1 elements, argument elementID, for example applyZoomAndPan("#txt2img_controlnet_ControlNet_input_image") + + window.applyZoomAndPanIntegration = applyZoomAndPanIntegration; // for any extension + + /* + The function `applyZoomAndPanIntegration` takes two arguments: + + 1. `id`: A string identifier for the element to which zoom and pan functionality will be applied on click. + If the `id` value is "none", the functionality will be applied to all elements specified in the second argument without a click event. + + 2. `elementIDs`: An array of string identifiers for elements. Zoom and pan functionality will be applied to each of these elements on click of the element specified by the first argument. + If "none" is specified in the first argument, the functionality will be applied to each of these elements without a click event. + + Example usage: + applyZoomAndPanIntegration("#txt2img_controlnet", ["#txt2img_controlnet_ControlNet_input_image"]); + In this example, zoom and pan functionality will be applied to the element with the identifier "txt2img_controlnet_ControlNet_input_image" upon clicking the element with the identifier "txt2img_controlnet". + */ + + // More examples + // Add integration with ControlNet txt2img One TAB + // applyZoomAndPanIntegration("#txt2img_controlnet", ["#txt2img_controlnet_ControlNet_input_image"]); + + // Add integration with ControlNet txt2img Tabs + // applyZoomAndPanIntegration("#txt2img_controlnet",Array.from({ length: 10 }, (_, i) => `#txt2img_controlnet_ControlNet-${i}_input_image`)); + + // Add integration with Inpaint Anything + // applyZoomAndPanIntegration("None", ["#ia_sam_image", "#ia_sel_mask"]); }); diff --git a/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py b/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py index 380176ce..2d8d2d1c 100644 --- a/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py +++ b/extensions-builtin/canvas-zoom-and-pan/scripts/hotkey_config.py @@ -9,6 +9,7 @@ shared.options_templates.update(shared.options_section(('canvas_hotkey', "Canvas "canvas_hotkey_reset": shared.OptionInfo("R", "Reset zoom and canvas positon"), "canvas_hotkey_overlap": shared.OptionInfo("O", "Toggle overlap").info("Technical button, neededs for testing"), "canvas_show_tooltip": shared.OptionInfo(True, "Enable tooltip on the canvas"), + "canvas_auto_expand": shared.OptionInfo(True, "Automatically expands an image that does not fit completely in the canvas area, similar to manually pressing the S and R buttons"), "canvas_blur_prompt": shared.OptionInfo(False, "Take the focus off the prompt when working with a canvas"), "canvas_disabled_functions": shared.OptionInfo(["Overlap"], "Disable function that you don't use", gr.CheckboxGroup, {"choices": ["Zoom","Adjust brush size", "Moving canvas","Fullscreen","Reset Zoom","Overlap"]}), })) diff --git a/extensions-builtin/canvas-zoom-and-pan/style.css b/extensions-builtin/canvas-zoom-and-pan/style.css index 6bcc9570..5d8054e6 100644 --- a/extensions-builtin/canvas-zoom-and-pan/style.css +++ b/extensions-builtin/canvas-zoom-and-pan/style.css @@ -61,3 +61,6 @@ to {opacity: 1;} } +.styler { + overflow:inherit !important; +} \ No newline at end of file diff --git a/extensions-builtin/extra-options-section/scripts/extra_options_section.py b/extensions-builtin/extra-options-section/scripts/extra_options_section.py index a05e10d8..983f87ff 100644 --- a/extensions-builtin/extra-options-section/scripts/extra_options_section.py +++ b/extensions-builtin/extra-options-section/scripts/extra_options_section.py @@ -1,5 +1,7 @@ +import math + import gradio as gr -from modules import scripts, shared, ui_components, ui_settings +from modules import scripts, shared, ui_components, ui_settings, generation_parameters_copypaste from modules.ui_components import FormColumn @@ -19,18 +21,38 @@ class ExtraOptionsSection(scripts.Script): def ui(self, is_img2img): self.comps = [] self.setting_names = [] + self.infotext_fields = [] + extra_options = shared.opts.extra_options_img2img if is_img2img else shared.opts.extra_options_txt2img + + mapping = {k: v for v, k in generation_parameters_copypaste.infotext_to_setting_name_mapping} with gr.Blocks() as interface: - with gr.Accordion("Options", open=False) if shared.opts.extra_options_accordion and shared.opts.extra_options else gr.Group(), gr.Row(): - for setting_name in shared.opts.extra_options: - with FormColumn(): - comp = ui_settings.create_setting_component(setting_name) + with gr.Accordion("Options", open=False) if shared.opts.extra_options_accordion and extra_options else gr.Group(): - self.comps.append(comp) - self.setting_names.append(setting_name) + row_count = math.ceil(len(extra_options) / shared.opts.extra_options_cols) + + for row in range(row_count): + with gr.Row(): + for col in range(shared.opts.extra_options_cols): + index = row * shared.opts.extra_options_cols + col + if index >= len(extra_options): + break + + setting_name = extra_options[index] + + with FormColumn(): + comp = ui_settings.create_setting_component(setting_name) + + self.comps.append(comp) + self.setting_names.append(setting_name) + + setting_infotext_name = mapping.get(setting_name) + if setting_infotext_name is not None: + self.infotext_fields.append((comp, setting_infotext_name)) def get_settings_values(): - return [ui_settings.get_value_for_setting(key) for key in self.setting_names] + res = [ui_settings.get_value_for_setting(key) for key in self.setting_names] + return res[0] if len(res) == 1 else res interface.load(fn=get_settings_values, inputs=[], outputs=self.comps, queue=False, show_progress=False) @@ -43,6 +65,10 @@ class ExtraOptionsSection(scripts.Script): shared.options_templates.update(shared.options_section(('ui', "User interface"), { - "extra_options": shared.OptionInfo([], "Options in main UI", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in txt2img/img2img interfaces").needs_restart(), - "extra_options_accordion": shared.OptionInfo(False, "Place options in main UI into an accordion") + "extra_options_txt2img": shared.OptionInfo([], "Options in main UI - txt2img", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in txt2img interfaces").needs_reload_ui(), + "extra_options_img2img": shared.OptionInfo([], "Options in main UI - img2img", ui_components.DropdownMulti, lambda: {"choices": list(shared.opts.data_labels.keys())}).js("info", "settingsHintsShowQuicksettings").info("setting entries that also appear in img2img interfaces").needs_reload_ui(), + "extra_options_cols": shared.OptionInfo(1, "Options in main UI - number of columns", gr.Number, {"precision": 0}).needs_reload_ui(), + "extra_options_accordion": shared.OptionInfo(False, "Options in main UI - place into an accordion").needs_reload_ui() })) + + diff --git a/extensions-builtin/mobile/javascript/mobile.js b/extensions-builtin/mobile/javascript/mobile.js index 12cae4b7..652f07ac 100644 --- a/extensions-builtin/mobile/javascript/mobile.js +++ b/extensions-builtin/mobile/javascript/mobile.js @@ -20,7 +20,13 @@ function reportWindowSize() { var button = gradioApp().getElementById(tab + '_generate_box'); var target = gradioApp().getElementById(currentlyMobile ? tab + '_results' : tab + '_actions_column'); target.insertBefore(button, target.firstElementChild); + + gradioApp().getElementById(tab + '_results').classList.toggle('mobile', currentlyMobile); } } window.addEventListener("resize", reportWindowSize); + +onUiLoaded(function() { + reportWindowSize(); +}); diff --git a/extensions-builtin/sd_theme_editor/install.py b/extensions-builtin/sd_theme_editor/install.py deleted file mode 100644 index 5416cb0a..00000000 --- a/extensions-builtin/sd_theme_editor/install.py +++ /dev/null @@ -1 +0,0 @@ -import launch diff --git a/extensions-builtin/sd_theme_editor/javascript/ui_theme.js b/extensions-builtin/sd_theme_editor/javascript/ui_theme.js deleted file mode 100644 index 1f065568..00000000 --- a/extensions-builtin/sd_theme_editor/javascript/ui_theme.js +++ /dev/null @@ -1,435 +0,0 @@ -function hexToRgb(color) { - let hex = color[0] === "#" ? color.slice(1) : color; - let c; - - // expand the short hex by doubling each character, fc0 -> ffcc00 - if (hex.length !== 6) { - hex = (() => { - const result = []; - for (c of Array.from(hex)) { - result.push(`${c}${c}`); - } - return result; - })().join(""); - } - const colorStr = hex.match(/#?(.{2})(.{2})(.{2})/).slice(1); - const rgb = colorStr.map((col) => parseInt(col, 16)); - rgb.push(1); - return rgb; -} - -function rgbToHsl(rgb) { - const r = rgb[0] / 255; - const g = rgb[1] / 255; - const b = rgb[2] / 255; - - const max = Math.max(r, g, b); - const min = Math.min(r, g, b); - const diff = max - min; - const add = max + min; - - const hue = - min === max - ? 0 - : r === max - ? ((60 * (g - b)) / diff + 360) % 360 - : g === max - ? (60 * (b - r)) / diff + 120 - : (60 * (r - g)) / diff + 240; - - const lum = 0.5 * add; - - const sat = - lum === 0 ? 0 : lum === 1 ? 1 : lum <= 0.5 ? diff / add : diff / (2 - add); - - const h = Math.round(hue); - const s = Math.round(sat * 100); - const l = Math.round(lum * 100); - const a = rgb[3] || 1; - - return [h, s, l, a]; -} - -function hexToHsl(color) { - const rgb = hexToRgb(color); - const hsl = rgbToHsl(rgb); - return "hsl(" + hsl[0] + "deg " + hsl[1] + "% " + hsl[2] + "%)"; -} - -function hslToHex(h, s, l) { - l /= 100; - const a = (s * Math.min(l, 1 - l)) / 100; - const f = (n) => { - const k = (n + h / 30) % 12; - const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return Math.round(255 * Math.max(0, Math.min(color, 1))) - .toString(16) - .padStart(2, "0"); // convert to Hex and prefix "0" if needed - }; - return `#${f(0)}${f(8)}${f(4)}`; -} - -function hsl2rgb(h, s, l) { - let a = s * Math.min(l, 1 - l); - let f = (n, k = (n + h / 30) % 12) => - l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); - return [f(0), f(8), f(4)]; -} - -function invertColor(hex) { - if (hex.indexOf("#") === 0) { - hex = hex.slice(1); - } - // convert 3-digit hex to 6-digits. - if (hex.length === 3) { - hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]; - } - if (hex.length !== 6) { - throw new Error("Invalid HEX color."); - } - // invert color components - var r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16), - g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16), - b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16); - // pad each with zeros and return - return "#" + padZero(r) + padZero(g) + padZero(b); -} - -function padZero(str, len) { - len = len || 2; - var zeros = new Array(len).join("0"); - return (zeros + str).slice(-len); -} - -function getValsWrappedIn(str, c1, c2) { - var rg = new RegExp("(?<=\\" + c1 + ")(.*?)(?=\\" + c2 + ")", "g"); - return str.match(rg); -} - -let styleobj = {}; -let hslobj = {}; -let isColorsInv; - -const toHSLArray = (hslStr) => hslStr.match(/\d+/g).map(Number); - -function offsetColorsHSV(ohsl) { - let inner_styles = ""; - - for (const key in styleobj) { - let keyVal = styleobj[key]; - - if (keyVal.indexOf("#") != -1 || keyVal.indexOf("hsl") != -1) { - let colcomp = gradioApp().querySelector("#" + key + " input"); - if (colcomp) { - let hsl; - - if (keyVal.indexOf("#") != -1) { - keyVal = keyVal.replace(/\s+/g, ""); - //inv ? keyVal = invertColor(keyVal) : 0; - if (isColorsInv) { - keyVal = invertColor(keyVal); - styleobj[key] = keyVal; - } - hsl = rgbToHsl(hexToRgb(keyVal)); - } else { - if (isColorsInv) { - let c = toHSLArray(keyVal); - let hex = hslToHex(c[0], c[1], c[2]); - keyVal = invertColor(hex); - styleobj[key] = keyVal; - hsl = rgbToHsl(hexToRgb(keyVal)); - } else { - hsl = toHSLArray(keyVal); - } - } - - let h = (parseInt(hsl[0]) + parseInt(ohsl[0])) % 360; - let s = parseInt(hsl[1]) + parseInt(ohsl[1]); - let l = parseInt(hsl[2]) + parseInt(ohsl[2]); - - let hex = hslToHex( - h, - Math.min(Math.max(s, 0), 100), - Math.min(Math.max(l, 0), 100) - ); - - colcomp.value = hex; - - hslobj[key] = "hsl(" + h + "deg " + s + "% " + l + "%)"; - inner_styles += key + ":" + hslobj[key] + ";"; - } - } else { - inner_styles += key + ":" + styleobj[key] + ";"; - } - } - - isColorsInv = false; - - const preview_styles = gradioApp().querySelector("#preview-styles"); - preview_styles.innerHTML = ":root {" + inner_styles + "}"; - preview_styles.innerHTML += - "@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}"; - - const vars_textarea = gradioApp().querySelector("#theme_vars textarea"); - vars_textarea.value = inner_styles; - - const inputEvent = new Event("input"); - Object.defineProperty(inputEvent, "target", { value: vars_textarea }); - vars_textarea.dispatchEvent(inputEvent); -} - -function updateTheme(vars) { - let inner_styles = ""; - - for (let i = 0; i < vars.length - 1; i++) { - let key = vars[i].split(":"); - let id = key[0].replace(/\s+/g, ""); - let val = key[1].trim(); - - styleobj[id] = val; - inner_styles += id + ":" + val + ";"; - - gradioApp() - .querySelectorAll("#" + id + " input") - .forEach((elem) => { - if (val.indexOf("hsl") != -1) { - let hsl = toHSLArray(val); - let hex = hslToHex(hsl[0], hsl[1], hsl[2]); - elem.value = hex; - } else { - elem.value = val.split("px")[0]; - } - }); - } - - const preview_styles = gradioApp().querySelector("#preview-styles"); - - if (preview_styles) { - preview_styles.innerHTML = ":root {" + inner_styles + "}"; - preview_styles.innerHTML += - "@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}"; - } else { - const r = gradioApp(); - const style = document.createElement("style"); - style.id = "preview-styles"; - style.innerHTML = ":root {" + inner_styles + "}"; - style.innerHTML += - "@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}"; - r.appendChild(style); - } - - const vars_textarea = gradioApp().querySelector("#theme_vars textarea"); - const css_textarea = gradioApp().querySelector("#theme_css textarea"); - - vars_textarea.value = inner_styles; - css_textarea.value = css_textarea.value; - - //console.log(Object); - - const vEvent = new Event("input"); - const cEvent = new Event("input"); - Object.defineProperty(vEvent, "target", { value: vars_textarea }); - Object.defineProperty(cEvent, "target", { value: css_textarea }); - vars_textarea.dispatchEvent(vEvent); - css_textarea.dispatchEvent(cEvent); -} - -function applyTheme() { - console.log("apply"); -} - -function initTheme() { - const current_style = gradioApp().querySelector(".gradio-container > style"); - //console.log(current_style); - //const head = document.head; - //head.appendChild(current_style); - - const css_styles = current_style.innerHTML.split( - "/*BREAKPOINT_CSS_CONTENT*/" - ); - let init_css_vars = css_styles[0].split("}")[0].split("{")[1]; - init_css_vars = init_css_vars.replace(/\n|\r/g, ""); - - let init_vars = init_css_vars.split(";"); - let vars = init_vars; - - //console.log(vars); - - const vars_textarea = gradioApp().querySelector("#theme_vars textarea"); - const css_textarea = gradioApp().querySelector("#theme_css textarea"); - //const result_textarea = gradioApp().querySelector('#theme_result textarea'); - vars_textarea.value = init_css_vars; - css_textarea.value = - "/*BREAKPOINT_CSS_CONTENT*/" + css_styles[1] + "/*BREAKPOINT_CSS_CONTENT*/"; - - updateTheme(vars); - - //vars_textarea.addEventListener("change", function(e) { - //e.preventDefault(); - //e.stopPropagation(); - //vars = vars_textarea.value.split(";"); - //console.log(e); - //updateTheme(vars); - - //}) - - const preview_styles = gradioApp().querySelector("#preview-styles"); - let intervalChange; - - gradioApp() - .querySelectorAll("#ui_theme_settings input") - .forEach((elem) => { - elem.addEventListener("input", function (e) { - let celem = e.currentTarget; - let val = e.currentTarget.value; - let curr_val; - - switch (e.currentTarget.type) { - case "range": - celem = celem.parentElement; - val = e.currentTarget.value + "px"; - break; - case "color": - celem = celem.parentElement.parentElement; - val = e.currentTarget.value; - break; - case "number": - celem = celem.parentElement.parentElement.parentElement; - val = e.currentTarget.value + "px"; - break; - } - - styleobj[celem.id] = val; - - //console.log(styleobj); - - if (intervalChange != null) clearInterval(intervalChange); - intervalChange = setTimeout(() => { - let inner_styles = ""; - - for (const key in styleobj) { - inner_styles += key + ":" + styleobj[key] + ";"; - } - - vars = inner_styles.split(";"); - preview_styles.innerHTML = ":root {" + inner_styles + "}"; - preview_styles.innerHTML += - "@media only screen and (max-width: 860px) {:root{--ae-outside-gap-size: var(--ae-mobile-outside-gap-size);--ae-inside-padding-size: var(--ae-mobile-inside-padding-size);}}"; - - vars_textarea.value = inner_styles; - const vEvent = new Event("input"); - Object.defineProperty(vEvent, "target", { value: vars_textarea }); - vars_textarea.dispatchEvent(vEvent); - - offsetColorsHSV(hsloffset); - }, 1000); - }); - }); - - const reset_btn = gradioApp().getElementById("theme_reset_btn"); - reset_btn.addEventListener("click", function (e) { - e.preventDefault(); - e.stopPropagation(); - gradioApp() - .querySelectorAll("#ui_theme_hsv input") - .forEach((elem) => { - elem.value = 0; - }); - hsloffset = [0, 0, 0]; - updateTheme(init_vars); - }); - - /* - const apply_btn = gradioApp().getElementById('theme_apply_btn'); - apply_btn.addEventListener("click", function(e) { - e.preventDefault(); - e.stopPropagation(); - init_css_vars = vars_textarea.value.replace(/\n|\r/g, ""); - vars_textarea.value = init_css_vars; - - init_vars = init_css_vars.split(";"); - vars = init_vars; - updateTheme(vars); - }) - */ - - let intervalCheck; - function dropDownOnChange() { - if (init_css_vars != vars_textarea.value) { - clearInterval(intervalCheck); - init_css_vars = vars_textarea.value.replace(/\n|\r/g, ""); - vars_textarea.value = init_css_vars; - init_vars = init_css_vars.split(";"); - vars = init_vars; - updateTheme(vars); - } - } - - const drop_down = gradioApp().querySelector("#themes_drop_down"); - drop_down.addEventListener("click", function (e) { - if (intervalCheck != null) clearInterval(intervalCheck); - intervalCheck = setInterval(dropDownOnChange, 100); - //console.log("ok"); - }); - - let hsloffset = [0, 0, 0]; - - const hue = gradioApp() - .querySelectorAll("#theme_hue input") - .forEach((elem) => { - elem.addEventListener("change", function (e) { - e.preventDefault(); - e.stopPropagation(); - hsloffset[0] = e.currentTarget.value; - offsetColorsHSV(hsloffset); - }); - }); - - const sat = gradioApp() - .querySelectorAll("#theme_sat input") - .forEach((elem) => { - elem.addEventListener("change", function (e) { - e.preventDefault(); - e.stopPropagation(); - hsloffset[1] = e.currentTarget.value; - offsetColorsHSV(hsloffset); - }); - }); - - const brt = gradioApp() - .querySelectorAll("#theme_brt input") - .forEach((elem) => { - elem.addEventListener("change", function (e) { - e.preventDefault(); - e.stopPropagation(); - hsloffset[2] = e.currentTarget.value; - offsetColorsHSV(hsloffset); - }); - }); - - const inv_btn = gradioApp().getElementById("theme_invert_btn"); - inv_btn.addEventListener("click", function (e) { - e.preventDefault(); - e.stopPropagation(); - isColorsInv = !isColorsInv; - offsetColorsHSV(hsloffset); - }); -} - -function observeGradioApp() { - const observer = new MutationObserver(() => { - const block = gradioApp().getElementById("tab_ui_theme"); - if (block) { - observer.disconnect(); - - setTimeout(() => { - initTheme(); - }, "500"); - } - }); - observer.observe(gradioApp(), { childList: true, subtree: true }); -} - -document.addEventListener("DOMContentLoaded", () => { - observeGradioApp(); -}); diff --git a/extensions-builtin/sd_theme_editor/scripts/ui_theme.py b/extensions-builtin/sd_theme_editor/scripts/ui_theme.py deleted file mode 100644 index 3a2c8a2b..00000000 --- a/extensions-builtin/sd_theme_editor/scripts/ui_theme.py +++ /dev/null @@ -1,177 +0,0 @@ -import os -import shutil -from pathlib import Path -import gradio as gr -import modules.scripts as scripts -from modules import script_callbacks, shared - -basedir = scripts.basedir() -webui_dir = Path(basedir).parents[1] - -themes_folder = os.path.join(basedir, "themes") -javascript_folder = os.path.join(basedir, "javascript") -webui_style_path = os.path.join(webui_dir, "style.css") - -def get_files(folder, file_filter=[], file_list=[], split=False): - file_list = [file_name if not split else os.path.splitext(file_name)[0] for file_name in os.listdir(folder) if os.path.isfile(os.path.join(folder, file_name)) and file_name not in file_filter] - return file_list - - -def on_ui_tabs(): - - with gr.Blocks(analytics_enabled=False) as ui_theme: - with gr.Row(): - with gr.Column(): - with gr.Row(): - themes_dropdown = gr.Dropdown(label="Themes", elem_id="themes_drop_down", interactive=True, choices=get_files(themes_folder,[".css, .txt"]), type="value") - save_as_filename = gr.Text(label="Save / Save as") - with gr.Row(): - reset_button = gr.Button(elem_id="theme_reset_btn", value="Reset", variant="primary") - #apply_button = gr.Button(elem_id="theme_apply_btn", value="Apply", variant="primary") - save_button = gr.Button(value="Save", variant="primary") - #delete_button = gr.Button(value="Delete", variant="primary") - - #with gr.Accordion(label="Debug View", open=True): - with gr.Row(elem_id="theme_hidden"): - vars_text = gr.Textbox(label="Vars", elem_id="theme_vars", show_label=True, lines=7, interactive=False, visible=True) - css_text = gr.Textbox(label="Css", elem_id="theme_css", show_label=True, lines=7, interactive=False, visible=True) - #result_text = gr.Text(elem_id="theme_result", interactive=False, visible=False) - with gr.Column(elem_id="theme_overflow_container"): - with gr.Accordion(label="Theme Color adjustments", open=True): - with gr.Row(): - with gr.Column(scale=6, elem_id="ui_theme_hsv"): - gr.Slider(elem_id="theme_hue", label='Hue', minimum=0, maximum=360, step=1) - gr.Slider(elem_id="theme_sat", label='Saturation', minimum=-100, maximum=100, step=1, value=0, interactive=True) - gr.Slider(elem_id="theme_brt", label='Lightness', minimum=-50, maximum=50, step=1, value=0, interactive=True) - - gr.Button(elem_id="theme_invert_btn", value="Invert", variant="primary") - - - with gr.Row(elem_id="ui_theme_settings"): - with gr.Column(): - with gr.Column(): - with gr.Accordion(label="Main", open=True): - gr.ColorPicker(elem_id="--ae-main-bg-color", interactive=True, label="Background color") - gr.ColorPicker(elem_id="--ae-primary-color", label="Primary color") - - with gr.Accordion(label="Focus", open=True): - gr.ColorPicker(elem_id="--ae-textarea-focus-color", label="Textarea color") - gr.ColorPicker(elem_id="--ae-input-focus-color", label="Input color") - - with gr.Accordion(label="Spacing", open=True): - gr.Slider(elem_id="--ae-outside-gap-size", label='Gap size', minimum=1, maximum=16, step=1, interactive=True) - gr.Slider(elem_id="--ae-inside-padding-size", label='Padding size', minimum=1, maximum=16, step=1, interactive=True) - - with gr.Accordion(label="Spacing (Mobile)", open=True): - gr.Slider(elem_id="--ae-mobile-outside-gap-size", label='Mobile Gap size', minimum=1, maximum=16, step=1, interactive=True) - gr.Slider(elem_id="--ae-mobile-inside-padding-size", label='Mobile Padding size', minimum=1, maximum=16, step=1, interactive=True) - - with gr.Accordion(label="Panel", open=True): - gr.ColorPicker(elem_id="--ae-label-color", label="Label color") - gr.ColorPicker(elem_id="--ae-frame-bg-color", label="Frame Background color") - gr.ColorPicker(elem_id="--ae-panel-bg-color", label="Background color") - gr.ColorPicker(elem_id="--ae-panel-border-color", label="Border color") - gr.Slider(elem_id="--ae-panel-border-radius", label='Border radius', minimum=0, maximum=16, step=1) - - gr.ColorPicker(elem_id="--ae-input-color", label="Input text color") - gr.ColorPicker(elem_id="--ae-input-bg-color", label="Input background color") - gr.ColorPicker(elem_id="--ae-input-border-color", label="Input border color") - with gr.Column(): - with gr.Row(elem_id="theme_sub-panel"): - - with gr.Accordion(label="SubPanel", open=True): - gr.ColorPicker(elem_id="--ae-subgroup-bg-color", label="Subgoup background color") - #gr.ColorPicker(elem_id="--ae-subgroup-label-color", label="Label color", value="#000000") - gr.ColorPicker(elem_id="--ae-subpanel-bg-color", label="Background color") - gr.ColorPicker(elem_id="--ae-subpanel-border-color", label="Border color") - gr.Slider(elem_id="--ae-subpanel-border-radius", label='Border radius', minimum=0, maximum=16, step=1) - - gr.ColorPicker(elem_id="--ae-subgroup-input-color", label="Input text color") - gr.ColorPicker(elem_id="--ae-subgroup-input-bg-color", label="Input background color") - gr.ColorPicker(elem_id="--ae-subgroup-input-border-color", label="Input border color") - - with gr.Row(): - with gr.Column(): - with gr.Accordion(label="Navigation menu", open=True): - gr.ColorPicker(elem_id="--ae-nav-bg-color", label="Background color") - gr.ColorPicker(elem_id="--ae-nav-color", label="Text color") - gr.ColorPicker(elem_id="--ae-nav-hover-color", label="Hover color") - - with gr.Accordion(label="Icon", open=True): - gr.ColorPicker(elem_id="--ae-icon-color", label="Color") - gr.ColorPicker(elem_id="--ae-icon-hover-color", label="Hover color") - - with gr.Accordion(label="Other", open=True): - gr.ColorPicker(elem_id="--ae-text-color", label="Text color") - gr.ColorPicker(elem_id="--ae-placeholder-color", label="Placeholder color") - gr.ColorPicker(elem_id="--ae-cancel-color", label="Cancel/Interrupt color") - - with gr.Accordion(label="Modal", open=True): - gr.ColorPicker(elem_id="--ae-modal-bg-color", label="Background color") - gr.ColorPicker(elem_id="--ae-modal-icon-color", label="Icon color") - - - - def save_theme( vars_text, css_text, filename): - style_data= ":root{" + vars_text + "}" + css_text - with open(os.path.join(themes_folder, f"{filename}.css"), 'w', encoding="utf-8") as file: - file.write(vars_text) - file.close() - with open(webui_style_path, 'w', encoding="utf-8") as file: - file.write(style_data) - file.close() - themes_dropdown.choices=get_files(themes_folder,[".css, .txt"]) - return gr.update(choices=themes_dropdown.choices, value=f"{filename}.css") - - def open_theme(filename, css_text): - with open(os.path.join(themes_folder, f"{filename}"), 'r') as file: - vars_text=file.read() - no_ext=filename.rsplit('.', 1)[0] - #save_theme( vars_text, css_text, no_ext) - # shared.state.interrupt() - # shared.state.need_restart = True - return [vars_text, no_ext] - - # def delete_theme(filename): - # try: - # os.remove(os.path.join(themes_folder, filename)) - # except FileNotFoundError: - # pass - - # delete_button.click( - # fn = lambda: delete_theme() - # ) - - save_button.click( - fn=save_theme, - inputs=[vars_text, css_text, save_as_filename], - outputs=themes_dropdown - ) - - themes_dropdown.change( - fn=open_theme, - #_js = "applyTheme", - inputs=[themes_dropdown, css_text], - outputs=[vars_text, save_as_filename] - ) - - # apply_button.click( - # fn=None, - # _js = "applyTheme" - # ) - - # vars_text.change( - # fn=None, - # _js = "applyTheme", - # inputs=[], - # outputs=[vars_text, css_text] - # ) - - - - - return (ui_theme, 'Theme', 'ui_theme'), - - - -script_callbacks.on_ui_tabs(on_ui_tabs) \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/style.css b/extensions-builtin/sd_theme_editor/style.css deleted file mode 100644 index 51f33101..00000000 --- a/extensions-builtin/sd_theme_editor/style.css +++ /dev/null @@ -1,113 +0,0 @@ -#theme_menu { - z-index: 9999; - background-color: var(--ae-input-bg-color); - position: relative; - width: 38px; - height: 38px; - border-radius: 100%; - cursor: pointer; - min-width: unset; - max-width: 38px; - align-self: center; -} - -#theme_menu::before { - content: " "; - display: inline-block; - -webkit-mask-size: cover; - mask-size: cover; - background-color: var(--ae-icon-color); - width: var(--ae-icon-size); - height: var(--ae-icon-size); - -webkit-mask: url(./file=html/svg/contrast-drop-2-line.svg) no-repeat 50% 50%; - mask: url(./file=html/svg/contrast-drop-2-line.svg) no-repeat 50% 50%; - cursor: pointer; - position: relative; - left: 50%; - top: 50%; - transform: translate(-50%, -50%) scale(1); -} - -#theme_menu.fixed, -#theme_menu:hover { - background-color: var(--ae-icon-color); -} - -#theme_menu.fixed::before, -#theme_menu:hover::before { - background-color: var(--ae-icon-hover-color); -} - -#theme_overflow_container { - overflow-y: auto; - height: calc( - 100vh - var(--ae-top-header-height) - (var(--ae-outside-gap-size) * 2) - - (var(--ae-inside-padding-size) * 4) - 96px - ); - overflow-x: hidden; -} - -#tab_ui_theme.open { - transform: translateX(0); - box-shadow: rgba(0, 0, 0, 0.4) -30px 0 30px -30px; -} - -#tab_ui_theme.aside { - display: block !important; -} - -#tab_ui_theme.aside { - position: fixed; - top: var(--ae-top-header-height); - width: 90%; - right: 0; - height: calc(100% - var(--ae-top-header-height)); - max-width: 480px; - z-index: 9999; - transform: translateX(100%); - transition: all 0.25s ease 0s; - box-shadow: rgba(0, 0, 0, 0) -30px 0 30px -30px; - padding: calc(1rem - var(--ae-outside-gap-size)); - background-color: var(--ae-main-bg-color) !important; -} -#tab_ui_theme.aside.open { - transform: translateX(0); - box-shadow: rgba(0, 0, 0, 0.4) -30px 0 30px -30px; -} - -#theme_hidden, -#setting_ui_header_tabs .theme, -#setting_ui_hidden_tabs .theme { - display: none !important; -} - -#tab_ui_theme [id*="color"] label { - display: flex; - align-items: center; - pointer-events: none; -} -#tab_ui_theme [id*="color"] label span { - min-width: 50% !important; -} -#tab_ui_theme [id*="color"] label input { - flex-grow: 1; - pointer-events: all; - cursor: pointer; -} - -#settings_ui_theme > div > div { - flex-direction: row; - flex-wrap: wrap; -} -#settings_ui_theme > div > div > div { - max-width: 30%; -} - -#tab_ui_theme > div { - padding: 16px !important; - padding-top: 0 !important; -} - -#ui_theme_hsv + button { - min-width: unset; -} diff --git a/extensions-builtin/sd_theme_editor/themes/Golde.css b/extensions-builtin/sd_theme_editor/themes/Golde.css deleted file mode 100644 index 55250596..00000000 --- a/extensions-builtin/sd_theme_editor/themes/Golde.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(99deg 11% 8%);--ae-primary-color:hsl(44deg 63% 55%);--ae-input-bg-color:hsl(106deg 8% 12%);--ae-input-border-color:hsl(104deg 9% 32%);--ae-panel-bg-color:hsl(104deg 9% 20%);--ae-panel-border-color:hsl(104deg 9% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(99deg 11% 8%);--ae-subgroup-input-bg-color:hsl(99deg 11% 8%);--ae-subgroup-input-border-color:hsl(104deg 9% 32%);--ae-subpanel-bg-color:hsl(106deg 8% 12%);--ae-subpanel-border-color:hsl(104deg 9% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(56deg 30% 36%);--ae-input-focus-color:hsl(44deg 63% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(104deg 9% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(105deg 9% 77%);--ae-icon-hover-color:hsl(99deg 11% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(98deg 9% 4%);--ae-nav-color:hsl(105deg 9% 77%);--ae-nav-hover-color:hsl(98deg 9% 4%);--ae-input-color:hsl(44deg 63% 55%);--ae-label-color:hsl(105deg 9% 77%);--ae-subgroup-input-color:hsl(44deg 63% 55%);--ae-placeholder-color:hsl(104deg 9% 32%);--ae-text-color:hsl(105deg 9% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(108deg 8% 12%);--ae-modal-bg-color:hsl(96deg 12% 8%);--ae-modal-icon-color:hsl(44deg 63% 55%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/backup.css b/extensions-builtin/sd_theme_editor/themes/backup.css deleted file mode 100644 index f2537ed3..00000000 --- a/extensions-builtin/sd_theme_editor/themes/backup.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(168deg 96% 42%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(168deg 97% 41%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(0deg 84% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(168deg 96% 42%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(0deg 100% 100%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(168deg 97% 41%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css b/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css deleted file mode 100644 index 818b6d71..00000000 --- a/extensions-builtin/sd_theme_editor/themes/d-230-52-94.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(230deg 52% 4%);--ae-primary-color:hsl(38deg 148% 36%);--ae-input-bg-color:hsl(95deg 58% 7%);--ae-input-border-color:hsl(84deg 57% 24%);--ae-panel-bg-color:hsl(95deg 57% 11%);--ae-panel-border-color:hsl(84deg 57% 24%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(230deg 52% 4%);--ae-subgroup-input-bg-color:hsl(95deg 58% 7%);--ae-subgroup-input-border-color:hsl(84deg 57% 24%);--ae-subpanel-bg-color:hsl(90deg 56% 8%);--ae-subpanel-border-color:hsl(84deg 57% 24%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(80deg 55% 30%);--ae-input-focus-color:hsl(38deg 149% 35%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(230deg 136% 54%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(80deg 56% 74%);--ae-icon-hover-color:hsl(230deg 52% 4%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(230deg 52% 98%);--ae-nav-color:hsl(80deg 56% 74%);--ae-nav-hover-color:hsl(230deg 52% 98%);--ae-input-color:hsl(80deg 56% 74%);--ae-label-color:hsl(80deg 56% 74%);--ae-subgroup-input-color:hsl(230deg 152% 94%);--ae-placeholder-color:hsl(84deg 57% 24%);--ae-text-color:hsl(80deg 56% 74%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(94deg 60% 7%);--ae-modal-bg-color:hsl(229deg 52% 4%);--ae-modal-icon-color:hsl(38deg 100% 36%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/default.css b/extensions-builtin/sd_theme_editor/themes/default.css deleted file mode 100644 index b2131f91..00000000 --- a/extensions-builtin/sd_theme_editor/themes/default.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(168deg 97% 41%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(168deg 97% 41%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(0deg 84% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(168deg 97% 41%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(168deg 97% 41%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/default_cyan.css b/extensions-builtin/sd_theme_editor/themes/default_cyan.css deleted file mode 100644 index 3c1b32cd..00000000 --- a/extensions-builtin/sd_theme_editor/themes/default_cyan.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(199deg 60% 60%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(199deg 60% 60%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(357deg 50% 57%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(210deg 4% 80%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(199deg 60% 60%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/default_orange.css b/extensions-builtin/sd_theme_editor/themes/default_orange.css deleted file mode 100644 index 736775be..00000000 --- a/extensions-builtin/sd_theme_editor/themes/default_orange.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(0deg 0% 10%);--ae-primary-color:hsl(16deg 77% 60%);--ae-input-bg-color:hsl(225deg 6% 13%);--ae-input-border-color:hsl(214deg 5% 30%);--ae-panel-bg-color:hsl(225deg 5% 17%);--ae-panel-border-color:hsl(214deg 5% 30%);--ae-panel-border-radius:8px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(225deg 6% 13%);--ae-subgroup-input-border-color:hsl(214deg 5% 30%);--ae-subpanel-bg-color:hsl(220deg 4% 14%);--ae-subpanel-border-color:hsl(214deg 5% 30%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(16deg 77% 60%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(193deg 54% 55%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(210deg 4% 80%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(210deg 4% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(210deg 4% 80%);--ae-subgroup-input-color:hsl(210deg 4% 80%);--ae-placeholder-color:hsl(214deg 5% 30%);--ae-text-color:hsl(210deg 4% 80%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(225deg 6% 13%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(16deg 77% 60%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/fun.css b/extensions-builtin/sd_theme_editor/themes/fun.css deleted file mode 100644 index 23d77ece..00000000 --- a/extensions-builtin/sd_theme_editor/themes/fun.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(76deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(296deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(305deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(76deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(76deg 96% 55%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/minimal.css b/extensions-builtin/sd_theme_editor/themes/minimal.css deleted file mode 100644 index 279de7ae..00000000 --- a/extensions-builtin/sd_theme_editor/themes/minimal.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(0deg 0% 8%);--ae-primary-color:hsl(168deg 96% 42%);--ae-input-bg-color:hsl(0deg 0% 10%);--ae-input-border-color:hsl(0deg 0% 10%);--ae-panel-bg-color:hsl(0deg 0% 17%);--ae-panel-border-color:hsl(0deg 0% 17%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-bg-color:hsl(0deg 0% 10%);--ae-subgroup-input-border-color:hsl(0deg 0% 10%);--ae-subpanel-bg-color:hsl(0deg 0% 14%);--ae-subpanel-border-color:hsl(0deg 0% 15%);--ae-subpanel-border-radius:4px;--ae-textarea-focus-color:hsl(0deg 0% 36%);--ae-input-focus-color:hsl(168deg 97% 41%);--ae-outside-gap-size:1px;--ae-inside-padding-size:5px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(0deg 84% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(168deg 96% 42%);--ae-icon-hover-color:hsl(0deg 0% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(0deg 0% 4%);--ae-nav-color:hsl(0deg 0% 80%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(210deg 4% 80%);--ae-label-color:hsl(0deg 0% 65%);--ae-subgroup-input-color:hsl(0deg 100% 100%);--ae-placeholder-color:hsl(0deg 0% 30%);--ae-text-color:hsl(0deg 0% 80%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(0deg 0% 14%);--ae-modal-bg-color:hsl(0deg 0% 10%);--ae-modal-icon-color:hsl(168deg 97% 41%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/minimal_orange.css b/extensions-builtin/sd_theme_editor/themes/minimal_orange.css deleted file mode 100644 index ef2de97b..00000000 --- a/extensions-builtin/sd_theme_editor/themes/minimal_orange.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(210deg 28% 8%);--ae-primary-color:hsl(18deg 124% 42%);--ae-input-bg-color:hsl(210deg 28% 10%);--ae-input-border-color:hsl(210deg 28% 10%);--ae-panel-bg-color:hsl(210deg 28% 17%);--ae-panel-border-color:hsl(210deg 28% 17%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(210deg 28% 10%);--ae-subgroup-input-bg-color:hsl(210deg 28% 10%);--ae-subgroup-input-border-color:hsl(210deg 28% 10%);--ae-subpanel-bg-color:hsl(210deg 28% 14%);--ae-subpanel-border-color:hsl(210deg 28% 15%);--ae-subpanel-border-radius:4px;--ae-textarea-focus-color:hsl(210deg 28% 36%);--ae-input-focus-color:hsl(18deg 125% 41%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(210deg 112% 60%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(18deg 124% 42%);--ae-icon-hover-color:hsl(210deg 28% 10%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(210deg 28% 4%);--ae-nav-color:hsl(210deg 28% 80%);--ae-nav-hover-color:hsl(210deg 28% 4%);--ae-input-color:hsl(60deg 32% 80%);--ae-label-color:hsl(210deg 28% 65%);--ae-subgroup-input-color:hsl(210deg 128% 100%);--ae-placeholder-color:hsl(210deg 28% 30%);--ae-text-color:hsl(210deg 28% 80%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(210deg 28% 14%);--ae-modal-bg-color:hsl(210deg 28% 10%);--ae-modal-icon-color:hsl(18deg 125% 41%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/moonlight.css b/extensions-builtin/sd_theme_editor/themes/moonlight.css deleted file mode 100644 index 4f70e44c..00000000 --- a/extensions-builtin/sd_theme_editor/themes/moonlight.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(240deg 16% 6%);--ae-primary-color:hsl(222deg 75% 62%);--ae-input-bg-color:hsl(240deg 17% 8%);--ae-input-border-color:hsl(240deg 20% 16%);--ae-panel-bg-color:hsl(240deg 18% 12%);--ae-panel-border-color:hsl(240deg 16% 16%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(240deg 17% 8%);--ae-subgroup-input-bg-color:hsl(240deg 17% 8%);--ae-subgroup-input-border-color:hsl(240deg 20% 16%);--ae-subpanel-bg-color:hsl(240deg 18% 10%);--ae-subpanel-border-color:hsl(240deg 20% 16%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(222deg 75% 62%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(222deg 75% 62%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(222deg 75% 62%);--ae-icon-hover-color:hsl(240deg 18% 12%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(240deg 16% 6%);--ae-nav-color:hsl(185deg 66% 85%);--ae-nav-hover-color:hsl(0deg 0% 4%);--ae-input-color:hsl(185deg 66% 85%);--ae-label-color:hsl(185deg 66% 85%);--ae-subgroup-input-color:hsl(185deg 66% 85%);--ae-placeholder-color:hsl(240deg 20% 24%);--ae-text-color:hsl(185deg 66% 85%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(240deg 18% 10%);--ae-modal-bg-color:hsl(240deg 16% 6%);--ae-modal-icon-color:hsl(222deg 75% 62%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css b/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css deleted file mode 100644 index 1e497888..00000000 --- a/extensions-builtin/sd_theme_editor/themes/ogxBGreen.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(195deg 22% 8%);--ae-primary-color:hsl(159deg 96% 55%);--ae-input-bg-color:hsl(202deg 25% 12%);--ae-input-border-color:hsl(200deg 24% 32%);--ae-panel-bg-color:hsl(200deg 24% 20%);--ae-panel-border-color:hsl(200deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(195deg 22% 8%);--ae-subgroup-input-bg-color:hsl(200deg 24% 8%);--ae-subgroup-input-border-color:hsl(200deg 24% 32%);--ae-subpanel-bg-color:hsl(202deg 25% 12%);--ae-subpanel-border-color:hsl(200deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(152deg 3% 36%);--ae-input-focus-color:hsl(159deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(200deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(159deg 96% 55%);--ae-icon-hover-color:hsl(195deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(194deg 24% 4%);--ae-nav-color:hsl(201deg 24% 77%);--ae-nav-hover-color:hsl(194deg 24% 4%);--ae-input-color:hsl(159deg 96% 55%);--ae-label-color:hsl(201deg 24% 77%);--ae-subgroup-input-color:hsl(159deg 96% 55%);--ae-placeholder-color:hsl(200deg 24% 32%);--ae-text-color:hsl(201deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(200deg 25% 12%);--ae-modal-bg-color:hsl(193deg 22% 8%);--ae-modal-icon-color:hsl(159deg 96% 55%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/ogxCyan.css b/extensions-builtin/sd_theme_editor/themes/ogxCyan.css deleted file mode 100644 index 3ca6e23c..00000000 --- a/extensions-builtin/sd_theme_editor/themes/ogxCyan.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(198deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(198deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(198deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(198deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(198deg 96% 55%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css b/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css deleted file mode 100644 index 02b04e2d..00000000 --- a/extensions-builtin/sd_theme_editor/themes/ogxCyanInvert.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(73deg 22% 92%);--ae-primary-color:hsl(18deg 96% 45%);--ae-input-bg-color:hsl(80deg 25% 88%);--ae-input-border-color:hsl(78deg 24% 68%);--ae-panel-bg-color:hsl(78deg 24% 80%);--ae-panel-border-color:hsl(78deg 24% 68%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(73deg 22% 92%);--ae-subgroup-input-bg-color:hsl(73deg 22% 92%);--ae-subgroup-input-border-color:hsl(78deg 24% 68%);--ae-subpanel-bg-color:hsl(80deg 25% 88%);--ae-subpanel-border-color:hsl(78deg 24% 68%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(30deg 3% 64%);--ae-input-focus-color:hsl(18deg 96% 45%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(78deg 24% 68%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(79deg 24% 23%);--ae-icon-hover-color:hsl(73deg 22% 92%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(72deg 24% 96%);--ae-nav-color:hsl(79deg 24% 23%);--ae-nav-hover-color:hsl(72deg 24% 96%);--ae-input-color:hsl(18deg 96% 45%);--ae-label-color:hsl(79deg 24% 23%);--ae-subgroup-input-color:hsl(18deg 96% 45%);--ae-placeholder-color:hsl(78deg 24% 68%);--ae-text-color:hsl(79deg 24% 23%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:2px;--ae-frame-bg-color:hsl(80deg 25% 88%);--ae-modal-bg-color:hsl(73deg 22% 92%);--ae-modal-icon-color:hsl(18deg 96% 45%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/ogxGreen.css b/extensions-builtin/sd_theme_editor/themes/ogxGreen.css deleted file mode 100644 index 077e55e7..00000000 --- a/extensions-builtin/sd_theme_editor/themes/ogxGreen.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(149deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(149deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(149deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(149deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(253deg 22% 8%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/ogxRed.css b/extensions-builtin/sd_theme_editor/themes/ogxRed.css deleted file mode 100644 index 3d7d86a1..00000000 --- a/extensions-builtin/sd_theme_editor/themes/ogxRed.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(253deg 22% 8%);--ae-primary-color:hsl(347deg 96% 55%);--ae-input-bg-color:hsl(260deg 25% 12%);--ae-input-border-color:hsl(258deg 24% 32%);--ae-panel-bg-color:hsl(258deg 24% 20%);--ae-panel-border-color:hsl(258deg 24% 32%);--ae-panel-border-radius:4px;--ae-subgroup-bg-color:hsl(253deg 22% 8%);--ae-subgroup-input-bg-color:hsl(258deg 24% 8%);--ae-subgroup-input-border-color:hsl(258deg 24% 32%);--ae-subpanel-bg-color:hsl(260deg 25% 12%);--ae-subpanel-border-color:hsl(258deg 24% 32%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(347deg 96% 55%);--ae-outside-gap-size:8px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(258deg 24% 32%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(259deg 24% 77%);--ae-icon-hover-color:hsl(253deg 22% 8%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(252deg 24% 4%);--ae-nav-color:hsl(259deg 24% 77%);--ae-nav-hover-color:hsl(252deg 24% 4%);--ae-input-color:hsl(347deg 96% 55%);--ae-label-color:hsl(259deg 24% 77%);--ae-subgroup-input-color:hsl(347deg 96% 55%);--ae-placeholder-color:hsl(258deg 24% 32%);--ae-text-color:hsl(259deg 24% 77%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(260deg 25% 12%);--ae-modal-bg-color:hsl(253deg 22% 8%);--ae-modal-icon-color:hsl(347deg 96% 55%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/retrog.css b/extensions-builtin/sd_theme_editor/themes/retrog.css deleted file mode 100644 index 54839175..00000000 --- a/extensions-builtin/sd_theme_editor/themes/retrog.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(197deg 97% 14%);--ae-primary-color:hsl(27deg 99% 50%);--ae-input-bg-color:hsl(197deg 98% 16%);--ae-input-border-color:hsl(166deg 62% 33%);--ae-panel-bg-color:hsl(196deg 98% 18%);--ae-panel-border-color:hsl(166deg 62% 33%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(197deg 97% 14%);--ae-subgroup-input-bg-color:hsl(197deg 97% 14%);--ae-subgroup-input-border-color:hsl(166deg 62% 33%);--ae-subpanel-bg-color:hsl(197deg 98% 16%);--ae-subpanel-border-color:hsl(166deg 62% 33%);--ae-subpanel-border-radius:8px;--ae-textarea-focus-color:hsl(210deg 3% 36%);--ae-input-focus-color:hsl(222deg 75% 62%);--ae-outside-gap-size:6px;--ae-inside-padding-size:6px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(70deg 69% 54%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(27deg 99% 50%);--ae-icon-hover-color:hsl(196deg 98% 18%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(197deg 97% 14%);--ae-nav-color:hsl(70deg 69% 54%);--ae-nav-hover-color:hsl(197deg 97% 14%);--ae-input-color:hsl(70deg 69% 54%);--ae-label-color:hsl(70deg 69% 54%);--ae-subgroup-input-color:hsl(27deg 99% 50%);--ae-placeholder-color:hsl(166deg 62% 33%);--ae-text-color:hsl(185deg 66% 85%);--ae-mobile-outside-gap-size:3px;--ae-mobile-inside-padding-size:3px;--ae-frame-bg-color:hsl(197deg 98% 16%);--ae-modal-bg-color:hsl(197deg 97% 14%);--ae-modal-icon-color:hsl(27deg 99% 50%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/tron.css b/extensions-builtin/sd_theme_editor/themes/tron.css deleted file mode 100644 index 65c3248a..00000000 --- a/extensions-builtin/sd_theme_editor/themes/tron.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(185deg 75% 3%);--ae-primary-color:hsl(182deg 95% 51%);--ae-input-bg-color:hsl(185deg 73% 3%);--ae-input-border-color:hsl(185deg 72% 25%);--ae-panel-bg-color:hsl(180deg 76% 5%);--ae-panel-border-color:hsl(185deg 72% 25%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-border-color:hsl(185deg 72% 25%);--ae-subpanel-bg-color:hsl(185deg 73% 3%);--ae-subpanel-border-color:hsl(185deg 72% 25%);--ae-subpanel-border-radius:0px;--ae-textarea-focus-color:hsl(182deg 95% 51%);--ae-input-focus-color:hsl(182deg 95% 51%);--ae-outside-gap-size:2px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(182deg 95% 51%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(182deg 95% 51%);--ae-icon-hover-color:hsl(185deg 73% 3%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(185deg 73% 3%);--ae-nav-color:hsl(182deg 95% 75%);--ae-nav-hover-color:hsl(0deg 100% 50%);--ae-input-color:hsl(182deg 95% 75%);--ae-label-color:hsl(182deg 95% 75%);--ae-subgroup-input-color:hsl(182deg 95% 51%);--ae-placeholder-color:hsl(185deg 72% 25%);--ae-text-color:hsl(182deg 95% 75%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:8px;--ae-frame-bg-color:hsl(180deg 76% 5%);--ae-modal-bg-color:hsl(185deg 73% 3%);--ae-modal-icon-color:hsl(182deg 95% 51%); \ No newline at end of file diff --git a/extensions-builtin/sd_theme_editor/themes/tron2.css b/extensions-builtin/sd_theme_editor/themes/tron2.css deleted file mode 100644 index 98eeacbc..00000000 --- a/extensions-builtin/sd_theme_editor/themes/tron2.css +++ /dev/null @@ -1 +0,0 @@ ---ae-main-bg-color:hsl(185deg 75% 3%);--ae-primary-color:hsl(182deg 95% 51%);--ae-input-bg-color:hsl(184deg 89% 7%);--ae-input-border-color:hsl(185deg 72% 25%);--ae-panel-bg-color:hsl(185deg 73% 3%);--ae-panel-border-color:hsl(185deg 72% 25%);--ae-panel-border-radius:0px;--ae-subgroup-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-bg-color:hsl(185deg 73% 3%);--ae-subgroup-input-border-color:hsl(185deg 72% 25%);--ae-subpanel-bg-color:hsl(185deg 73% 3%);--ae-subpanel-border-color:hsl(185deg 72% 25%);--ae-subpanel-border-radius:0px;--ae-textarea-focus-color:hsl(182deg 95% 51%);--ae-input-focus-color:hsl(182deg 95% 51%);--ae-outside-gap-size:2px;--ae-inside-padding-size:8px;--ae-tool-button-size:34px;--ae-tool-button-radius:16px;--ae-generate-button-height:70px;--ae-cancel-color:hsl(182deg 95% 51%);--ae-max-padding:max(var(--ae-outside-gap-size),var(--ae-inside-padding-size));--ae-icon-color:hsl(182deg 95% 51%);--ae-icon-hover-color:hsl(185deg 73% 3%);--ae-icon-size:22px;--ae-nav-bg-color:hsl(185deg 73% 3%);--ae-nav-color:hsl(182deg 95% 75%);--ae-nav-hover-color:hsl(0deg 100% 50%);--ae-input-color:hsl(182deg 95% 75%);--ae-label-color:hsl(182deg 95% 75%);--ae-subgroup-input-color:hsl(182deg 95% 51%);--ae-placeholder-color:hsl(185deg 72% 25%);--ae-text-color:hsl(182deg 95% 75%);--ae-mobile-outside-gap-size:2px;--ae-mobile-inside-padding-size:8px;--ae-frame-bg-color:hsl(185deg 73% 3%); \ No newline at end of file diff --git a/html/200w.webp b/html/200w.webp deleted file mode 100644 index cd3782d0..00000000 Binary files a/html/200w.webp and /dev/null differ diff --git a/html/card-no-preview.png b/html/card-no-preview.png index a1cac2e0..e2beb269 100644 Binary files a/html/card-no-preview.png and b/html/card-no-preview.png differ diff --git a/html/extra-networks-card.html b/html/extra-networks-card.html index 0cf61664..39674666 100644 --- a/html/extra-networks-card.html +++ b/html/extra-networks-card.html @@ -1,18 +1,14 @@ -
-
- +
+ {background_image} +
{metadata_button} {edit_button} -
-
- - -
- {name} +
+
+
+
+ {name} {description}
-
diff --git a/html/favicon.ico b/html/favicon.ico deleted file mode 100644 index 0bdafb82..00000000 Binary files a/html/favicon.ico and /dev/null differ diff --git a/html/footer.html b/html/footer.html index 2418fd52..69b2372c 100644 --- a/html/footer.html +++ b/html/footer.html @@ -1,55 +1,15 @@ - +
+ API +  •  + Github +  •  + Gradio +  •  + Startup profile +  •  + Reload UI +
+
+
+{versions} +
diff --git a/html/spotlight.css b/html/spotlight.css deleted file mode 100644 index c5f52159..00000000 --- a/html/spotlight.css +++ /dev/null @@ -1,363 +0,0 @@ -:root{ - --primary-color:#ffffff; -} -#spotlight { - position: fixed; - top: -1px; - bottom: -1px; - width: 100%; - z-index: 99999; - color: #fff; - background-color: #000; - opacity: 0; - overflow: hidden; - user-select: none; - transition: opacity 0.2s ease-out; - font-family: Arial, sans-serif; - font-size: 16px; - font-weight: 400; - contain: strict; - touch-action: none; - pointer-events: none; -} -#spotlight.show { - opacity: 1; - transition: none; - pointer-events: auto; -} -#spotlight.white { - color: #212529; - background-color: #fff; -} -#spotlight.white .spl-spinner, -#spotlight.white .spl-prev, -#spotlight.white .spl-next, -#spotlight.white .spl-page ~ * { - filter: invert(1); -} -#spotlight.white .spl-progress { - background-color: rgba(0, 0, 0, 0.35); -} -#spotlight.white .spl-header, -#spotlight.white .spl-footer { - background-color: rgba(255, 255, 255, 0.65); -} -#spotlight.white .spl-button { - background: #212529; - color: #fff; -} -#spotlight .cover { - object-fit: cover; - height: 100%; - width: 100%; -} -#spotlight .contain { - object-fit: contain; - height: 100%; - width: 100%; -} -#spotlight .autofit { - object-fit: none; - width: auto; - height: auto; - max-height: none; - max-width: none; - transition: none; -} -.spl-track { - position: absolute; - width: 100%; - height: 100%; - contain: strict; -} -.spl-spinner { - position: absolute; - width: 100%; - height: 100%; - background-position: center; - background-repeat: no-repeat; - background-size: 42px; - opacity: 0; -} -.spl-spinner.spin { - background-image: url("svg/spotlight/preloader.svg"); - transition: opacity 0.2s linear 0.25s; - opacity: 1; -} -.spl-spinner.error { - background-image: url("svg/spotlight/error.svg"); - background-size: 128px; - transition: none; - opacity: 0.5; -} -.spl-scene { - position: absolute; - width: 100%; - height: 100%; - transition: transform 0.65s cubic-bezier(0.1, 1, 0.1, 1); - contain: layout size; - will-change: transform; -} -.spl-pane > * { - position: absolute; - width: auto; - height: auto; - max-width: 100%; - max-height: 100%; - left: 50%; - top: 50%; - margin: 0; - padding: 0; - border: 0; - transform: translate(-50%, -50%) scale(1); - transition: transform 0.65s cubic-bezier(0.3, 1, 0.3, 1), opacity 0.65s ease; - contain: layout style; - will-change: transform, opacity; - visibility: hidden; -} -.spl-pane { - position: absolute; - top: 0; - width: 100%; - height: 100%; - transition: transform 0.65s cubic-bezier(0.3, 1, 0.3, 1); - contain: layout size; - will-change: transform, contents; -} -.spl-pane.hide img { - display:none !important; -} -.spl-pane.hide { - background-size: 100%; - transition: background-size 0.65s cubic-bezier(0.3, 1, 0.3, 1) !important; - will-change: background-size !important; - transform: translate(0, 0) !important; -} -.spl-header { - position: absolute; - top: 0; - width: 100%; - height: 50px; - text-align: right; - background-color: rgba(0, 0, 0, 0.45); - transform: translateY(-100px); - transition: transform 0.35s ease; - overflow: hidden; - will-change: transform; -} -#spotlight.menu .spl-header, -.spl-header:hover { - transform: translateY(0); -} -.spl-header div { - display: inline-block; - vertical-align: middle; - white-space: nowrap; - width: 50px; - height: 50px; - opacity: 0.5; -} -.spl-progress { - position: absolute; - top: 0; - width: 100%; - height: 3px; - background-color: rgba(255, 255, 255, 0.45); - transform: translateX(-100%); - transition: transform linear; -} -.spl-footer { - position: absolute; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.45); - line-height: 20px; - padding: 20px 20px 0 20px; - padding-bottom: env(safe-area-inset-bottom, 0); - text-align: left; - font-size: 15px; - font-weight: 400; - transform: translateY(100%); - transition: transform 0.35s ease; - will-change: transform; -} -#spotlight.menu .spl-footer, -.spl-footer:hover { - transform: translateY(0); -} -.spl-title { - font-size: 22px; - margin-bottom: 20px; -} -.spl-description { - margin-bottom: 20px; -} -.spl-button { - display: inline-block; - background: #fff; - color: #000; - border-radius: 5px; - padding: 10px 20px; - margin-bottom: 20px; - cursor: pointer; -} -.spl-page { - float: left; - width: auto; - line-height: 50px; -} -.spl-page ~ * { - background-position: center; - background-repeat: no-repeat; - background-size: 21px; - float: right; -} -.spl-fullscreen { - background-color:var(--primary-color); - -webkit-mask: url("svg/fullscreen-line.svg") no-repeat 50% 50%; - mask: url("svg/fullscreen-line.svg") no-repeat 50% 50%; -} -.spl-fullscreen.on { - background-color:var(--primary-color); - -webkit-mask: url("svg/fullscreen-exit-line.svg") no-repeat 50% 50%; - mask: url("svg/fullscreen-exit-line.svg") no-repeat 50% 50%; -} -.spl-autofit { - background-color:var(--primary-color); - -webkit-mask: url("svg/aspect-ratio-line.svg") no-repeat 50% 50%; - mask: url("svg/aspect-ratio-line.svg") no-repeat 50% 50%; -} -.spl-zoom-out { - background-color:var(--primary-color); - -webkit-mask: url("svg/zoom-out-line.svg") no-repeat 50% 50%; - mask: url("svg/zoom-out-line.svg") no-repeat 50% 50%; - background-size: 22px; -} -.spl-zoom-in { - background-color:var(--primary-color); - -webkit-mask: url("svg/zoom-in-line.svg") no-repeat 50% 50%; - mask: url("svg/zoom-in-line.svg") no-repeat 50% 50%; - background-size: 22px; -} -.spl-download { - background-color:var(--primary-color); - -webkit-mask: url("svg/file-download-line.svg") no-repeat 50% 50%; - mask: url("svg/file-download-line.svg") no-repeat 50% 50%; - background-size: 20px; -} -.spl-theme { - background-image: url("svg/spotlight/theme.svg"); -} -.spl-play { - background-image: url("svg/spotlight/play.svg"); -} -.spl-play.on { - background-image: url("svg/spotlight/pause.svg"); - animation: pulsate 1s ease infinite; -} -.spl-close { - background-color:var(--primary-color); - -webkit-mask: url("svg/close-line.svg") no-repeat 50% 50%; - mask: url("svg/close-line.svg") no-repeat 50% 50%; -} -.spl-like{ - background-color:var(--primary-color); - -webkit-mask: url("svg/heart-line.svg") no-repeat 50% 50%; - mask: url("svg/heart-line.svg") no-repeat 50% 50%; - background-size: 22px; -} -.spl-like.on{ - background-color:var(--primary-color); - -webkit-mask: url("svg/heart-fill.svg") no-repeat 50% 50%; - mask: url("svg/heart-fill.svg") no-repeat 50% 50%; -} -.spl-tile{ - background-color:var(--primary-color); - -webkit-mask: url("svg/grid-line.svg") no-repeat 50% 50%; - mask: url("svg/grid-line.svg") no-repeat 50% 50%; - background-size: 22px; -} -.spl-tile.on{ - background-color:var(--primary-color); - -webkit-mask: url("svg/grid-fill.svg") no-repeat 50% 50%; - mask: url("svg/grid-fill.svg") no-repeat 50% 50%; -} - -.spl-prev, -.spl-next { - position: absolute; - top: 50%; - left: 20px; - width: 50px; - height: 50px; - opacity: 0.65; - background-color: rgba(0, 0, 0, 0.45); - border-radius: 100%; - cursor: pointer; - margin-top: -25px; - transform: translateX(-100px); - transition: transform 0.35s ease; - background-image: url("svg/spotlight/arrow.svg"); - background-position: center; - background-repeat: no-repeat; - background-size: 30px; - will-change: transform; -} -.spl-next { - left: auto; - right: 20px; - transform: translateX(100px) scaleX(-1); -} -#spotlight.menu .spl-prev { - transform: translateX(0); -} -#spotlight.menu .spl-next { - transform: translateX(0) scaleX(-1); -} -@media (hover: hover) { - .spl-page ~ div { - cursor: pointer; - transition: opacity 0.2s ease; - } - .spl-page ~ div:hover, - .spl-prev:hover, - .spl-next:hover { - opacity: 1; - } -} -@media (max-width: 500px) { - .spl-header div { - width: 44px; - } - .spl-footer .spl-title { - font-size: 20px; - } - .spl-footer { - font-size: 14px; - } - .spl-prev, - .spl-next { - width: 35px; - height: 35px; - margin-top: -17.5px; - background-size: 15px 15px; - } - .spl-spinner { - background-size: 30px 30px; - } -} -.hide-scrollbars { - overflow: hidden !important; -} -@keyframes pulsate { - 0% { - opacity: 1; - } - 50% { - opacity: 0.2; - } - 100% { - opacity: 1; - } -} \ No newline at end of file diff --git a/html/svg/add-box-line.svg b/html/svg/add-box-line.svg deleted file mode 100644 index dc56100a..00000000 --- a/html/svg/add-box-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/arrow-go-back-line.svg b/html/svg/arrow-go-back-line.svg deleted file mode 100644 index f01c233d..00000000 --- a/html/svg/arrow-go-back-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/artboard-line.svg b/html/svg/artboard-line.svg deleted file mode 100644 index 6998c0c1..00000000 --- a/html/svg/artboard-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/aspect-ratio-line.svg b/html/svg/aspect-ratio-line.svg deleted file mode 100644 index 855f9938..00000000 --- a/html/svg/aspect-ratio-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/ball-pen-line.svg b/html/svg/ball-pen-line.svg deleted file mode 100644 index e464a517..00000000 --- a/html/svg/ball-pen-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/bmc-logo2.svg b/html/svg/bmc-logo2.svg deleted file mode 100644 index 6766ec42..00000000 --- a/html/svg/bmc-logo2.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/html/svg/brush-line.svg b/html/svg/brush-line.svg deleted file mode 100644 index 6f8a957d..00000000 --- a/html/svg/brush-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/checkbox-blank-line.svg b/html/svg/checkbox-blank-line.svg deleted file mode 100644 index d6c2aa6d..00000000 --- a/html/svg/checkbox-blank-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/checkbox-indeterminate-line.svg b/html/svg/checkbox-indeterminate-line.svg deleted file mode 100644 index b4c69c05..00000000 --- a/html/svg/checkbox-indeterminate-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/clipboard-line.svg b/html/svg/clipboard-line.svg deleted file mode 100644 index 9ee97314..00000000 --- a/html/svg/clipboard-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/close-circle-line.svg b/html/svg/close-circle-line.svg deleted file mode 100644 index 90477e5f..00000000 --- a/html/svg/close-circle-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/close-line.svg b/html/svg/close-line.svg deleted file mode 100644 index e39564d9..00000000 --- a/html/svg/close-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/compass-4-line.svg b/html/svg/compass-4-line.svg deleted file mode 100644 index 7d894275..00000000 --- a/html/svg/compass-4-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/computer-fill.svg b/html/svg/computer-fill.svg deleted file mode 100644 index ea728890..00000000 --- a/html/svg/computer-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/contrast-drop-2-line.svg b/html/svg/contrast-drop-2-line.svg deleted file mode 100644 index abd8f3ea..00000000 --- a/html/svg/contrast-drop-2-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/cpu-fill.svg b/html/svg/cpu-fill.svg deleted file mode 100644 index fe016773..00000000 --- a/html/svg/cpu-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/cpu-line.svg b/html/svg/cpu-line.svg deleted file mode 100644 index 7d4922a1..00000000 --- a/html/svg/cpu-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/delete-bin-2-line.svg b/html/svg/delete-bin-2-line.svg deleted file mode 100644 index a6781f5a..00000000 --- a/html/svg/delete-bin-2-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/delete-bin-5-line.svg b/html/svg/delete-bin-5-line.svg deleted file mode 100644 index f0da62ec..00000000 --- a/html/svg/delete-bin-5-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/dice-1.svg b/html/svg/dice-1.svg deleted file mode 100644 index ece3905d..00000000 --- a/html/svg/dice-1.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/html/svg/download-line.svg b/html/svg/download-line.svg deleted file mode 100644 index 1d40a4fd..00000000 --- a/html/svg/download-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/drag-drop-line.svg b/html/svg/drag-drop-line.svg deleted file mode 100644 index d6d78a5b..00000000 --- a/html/svg/drag-drop-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/drag-move-2-fill.svg b/html/svg/drag-move-2-fill.svg deleted file mode 100644 index 80637b0e..00000000 --- a/html/svg/drag-move-2-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/file-download-line.svg b/html/svg/file-download-line.svg deleted file mode 100644 index 935f2ebe..00000000 --- a/html/svg/file-download-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/file-zip-line.svg b/html/svg/file-zip-line.svg deleted file mode 100644 index e5f83060..00000000 --- a/html/svg/file-zip-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/folder-open-line.svg b/html/svg/folder-open-line.svg deleted file mode 100644 index 94ef19f1..00000000 --- a/html/svg/folder-open-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/fullscreen-exit-line.svg b/html/svg/fullscreen-exit-line.svg deleted file mode 100644 index d3482777..00000000 --- a/html/svg/fullscreen-exit-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/fullscreen-line.svg b/html/svg/fullscreen-line.svg deleted file mode 100644 index 573526cb..00000000 --- a/html/svg/fullscreen-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/github-fill.svg b/html/svg/github-fill.svg deleted file mode 100644 index 206c5517..00000000 --- a/html/svg/github-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/gradio-fill.svg b/html/svg/gradio-fill.svg deleted file mode 100644 index c03c6b86..00000000 --- a/html/svg/gradio-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/html/svg/grid-fill.svg b/html/svg/grid-fill.svg deleted file mode 100644 index fef4a086..00000000 --- a/html/svg/grid-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/grid-line.svg b/html/svg/grid-line.svg deleted file mode 100644 index 0050582b..00000000 --- a/html/svg/grid-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/heart-add-fill.svg b/html/svg/heart-add-fill.svg deleted file mode 100644 index 8d7234bf..00000000 --- a/html/svg/heart-add-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/heart-fill.svg b/html/svg/heart-fill.svg deleted file mode 100644 index 91e44eea..00000000 --- a/html/svg/heart-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/heart-line.svg b/html/svg/heart-line.svg deleted file mode 100644 index 8591aeaf..00000000 --- a/html/svg/heart-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/image-icon.svg b/html/svg/image-icon.svg deleted file mode 100644 index 42b648af..00000000 --- a/html/svg/image-icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/image-update.svg b/html/svg/image-update.svg deleted file mode 100644 index 3abf12df..00000000 --- a/html/svg/image-update.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/html/svg/infinity-fill.svg b/html/svg/infinity-fill.svg deleted file mode 100644 index 7204f234..00000000 --- a/html/svg/infinity-fill.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - diff --git a/html/svg/information-fill.svg b/html/svg/information-fill.svg deleted file mode 100644 index 39111d4d..00000000 --- a/html/svg/information-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/information-line.svg b/html/svg/information-line.svg deleted file mode 100644 index 0983ccf9..00000000 --- a/html/svg/information-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/landscape-line.svg b/html/svg/landscape-line.svg deleted file mode 100644 index 69231da2..00000000 --- a/html/svg/landscape-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/magic-line.svg b/html/svg/magic-line.svg deleted file mode 100644 index 70442fa7..00000000 --- a/html/svg/magic-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/menu-4-fill.svg b/html/svg/menu-4-fill.svg deleted file mode 100644 index 5d06e79b..00000000 --- a/html/svg/menu-4-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/menu-add-fill.svg b/html/svg/menu-add-fill.svg deleted file mode 100644 index 21ee2c54..00000000 --- a/html/svg/menu-add-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/menu-line.svg b/html/svg/menu-line.svg deleted file mode 100644 index dfdfea1f..00000000 --- a/html/svg/menu-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/more-2-fill.svg b/html/svg/more-2-fill.svg deleted file mode 100644 index e67d22af..00000000 --- a/html/svg/more-2-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/paint-brush-line.svg b/html/svg/paint-brush-line.svg deleted file mode 100644 index e8b93deb..00000000 --- a/html/svg/paint-brush-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/pantone-line.svg b/html/svg/pantone-line.svg deleted file mode 100644 index d93296fe..00000000 --- a/html/svg/pantone-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/picture-in-picture-exit-line.svg b/html/svg/picture-in-picture-exit-line.svg deleted file mode 100644 index ad5e2f04..00000000 --- a/html/svg/picture-in-picture-exit-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/play-line.svg b/html/svg/play-line.svg deleted file mode 100644 index a967d730..00000000 --- a/html/svg/play-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/pulse-line.svg b/html/svg/pulse-line.svg deleted file mode 100644 index 4f8aa2bd..00000000 --- a/html/svg/pulse-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/question-answer-fill.svg b/html/svg/question-answer-fill.svg deleted file mode 100644 index fb6b6fdf..00000000 --- a/html/svg/question-answer-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/question-answer-line.svg b/html/svg/question-answer-line.svg deleted file mode 100644 index 29bc6899..00000000 --- a/html/svg/question-answer-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/recycle-line.svg b/html/svg/recycle-line.svg deleted file mode 100644 index 53988a91..00000000 --- a/html/svg/recycle-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/refresh-line.svg b/html/svg/refresh-line.svg deleted file mode 100644 index ff547244..00000000 --- a/html/svg/refresh-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/reply-fill.svg b/html/svg/reply-fill.svg deleted file mode 100644 index 54aade62..00000000 --- a/html/svg/reply-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/reply-line.svg b/html/svg/reply-line.svg deleted file mode 100644 index e1b88438..00000000 --- a/html/svg/reply-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/restart-fill.svg b/html/svg/restart-fill.svg deleted file mode 100644 index e57e15eb..00000000 --- a/html/svg/restart-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/rocket-fill.svg b/html/svg/rocket-fill.svg deleted file mode 100644 index bb4e93ff..00000000 --- a/html/svg/rocket-fill.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - diff --git a/html/svg/save-2-line.svg b/html/svg/save-2-line.svg deleted file mode 100644 index 1536631d..00000000 --- a/html/svg/save-2-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/save-3-line.svg b/html/svg/save-3-line.svg deleted file mode 100644 index ee5c0d65..00000000 --- a/html/svg/save-3-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/skip-forward-line.svg b/html/svg/skip-forward-line.svg deleted file mode 100644 index 24eebda3..00000000 --- a/html/svg/skip-forward-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/sort-asc.svg b/html/svg/sort-asc.svg deleted file mode 100644 index 96552675..00000000 --- a/html/svg/sort-asc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/sort-desc.svg b/html/svg/sort-desc.svg deleted file mode 100644 index a25ce6c2..00000000 --- a/html/svg/sort-desc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/arrow.svg b/html/svg/spotlight/arrow.svg deleted file mode 100644 index ba58879a..00000000 --- a/html/svg/spotlight/arrow.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/error.svg b/html/svg/spotlight/error.svg deleted file mode 100644 index fc950613..00000000 --- a/html/svg/spotlight/error.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/pause.svg b/html/svg/spotlight/pause.svg deleted file mode 100644 index 621b4fd6..00000000 --- a/html/svg/spotlight/pause.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/pixel.gif b/html/svg/spotlight/pixel.gif deleted file mode 100644 index 5bfd67a2..00000000 Binary files a/html/svg/spotlight/pixel.gif and /dev/null differ diff --git a/html/svg/spotlight/play.svg b/html/svg/spotlight/play.svg deleted file mode 100644 index 73191945..00000000 --- a/html/svg/spotlight/play.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/preloader.svg b/html/svg/spotlight/preloader.svg deleted file mode 100644 index 91a2fe3b..00000000 --- a/html/svg/spotlight/preloader.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/spotlight/theme.svg b/html/svg/spotlight/theme.svg deleted file mode 100644 index 6287d462..00000000 --- a/html/svg/spotlight/theme.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/stack-line.svg b/html/svg/stack-line.svg deleted file mode 100644 index 1bd316f6..00000000 --- a/html/svg/stack-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/stop-line.svg b/html/svg/stop-line.svg deleted file mode 100644 index 3c5290b7..00000000 --- a/html/svg/stop-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/t-box-fill.svg b/html/svg/t-box-fill.svg deleted file mode 100644 index 6b9e7293..00000000 --- a/html/svg/t-box-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/terminal-box-fill.svg b/html/svg/terminal-box-fill.svg deleted file mode 100644 index 776f80ae..00000000 --- a/html/svg/terminal-box-fill.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/terminal-box-line.svg b/html/svg/terminal-box-line.svg deleted file mode 100644 index 594c5296..00000000 --- a/html/svg/terminal-box-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/zoom-in-line.svg b/html/svg/zoom-in-line.svg deleted file mode 100644 index 48a29cd8..00000000 --- a/html/svg/zoom-in-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/html/svg/zoom-out-line.svg b/html/svg/zoom-out-line.svg deleted file mode 100644 index d85c8f20..00000000 --- a/html/svg/zoom-out-line.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js index fff1a992..2cf2d571 100644 --- a/javascript/aspectRatioOverlay.js +++ b/javascript/aspectRatioOverlay.js @@ -1,3 +1,4 @@ + let currentWidth = null; let currentHeight = null; let arFrameTimeout = setTimeout(function() {}, 0); diff --git a/javascript/badScaleChecker.js b/javascript/badScaleChecker.js deleted file mode 100644 index 625ad309..00000000 --- a/javascript/badScaleChecker.js +++ /dev/null @@ -1,108 +0,0 @@ -(function() { - var ignore = localStorage.getItem("bad-scale-ignore-it") == "ignore-it"; - - function getScale() { - var ratio = 0, - screen = window.screen, - ua = navigator.userAgent.toLowerCase(); - - if (window.devicePixelRatio !== undefined) { - ratio = window.devicePixelRatio; - } else if (~ua.indexOf('msie')) { - if (screen.deviceXDPI && screen.logicalXDPI) { - ratio = screen.deviceXDPI / screen.logicalXDPI; - } - } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) { - ratio = window.outerWidth / window.innerWidth; - } - - return ratio == 0 ? 0 : Math.round(ratio * 100); - } - - var showing = false; - - var div = document.createElement("div"); - div.style.position = "fixed"; - div.style.top = "0px"; - div.style.left = "0px"; - div.style.width = "100vw"; - div.style.backgroundColor = "firebrick"; - div.style.textAlign = "center"; - div.style.zIndex = 99; - - var b = document.createElement("b"); - b.innerHTML = 'Bad Scale: ??% '; - - div.appendChild(b); - - var note1 = document.createElement("p"); - note1.innerHTML = "Change your browser or your computer settings!"; - note1.title = 'Just make sure "computer-scale" * "browser-scale" = 100% ,\n' + - "you can keep your computer-scale and only change this page's scale,\n" + - "for example: your computer-scale is 125%, just use [\"CTRL\"+\"-\"] to make your browser-scale of this page to 80%."; - div.appendChild(note1); - - var note2 = document.createElement("p"); - note2.innerHTML = " Otherwise, it will cause this page to not function properly!"; - note2.title = "When you click \"Copy image to: [inpaint sketch]\" in some img2img's tab,\n" + - "if scale<100% the canvas will be invisible,\n" + - "else if scale>100% this page will take large amount of memory and CPU performance."; - div.appendChild(note2); - - var btn = document.createElement("button"); - btn.innerHTML = "Click here to ignore"; - - div.appendChild(btn); - - function tryShowTopBar(scale) { - if (showing) return; - - b.innerHTML = 'Bad Scale: ' + scale + '% '; - - var updateScaleTimer = setInterval(function() { - var newScale = getScale(); - b.innerHTML = 'Bad Scale: ' + newScale + '% '; - if (newScale == 100) { - var p = div.parentNode; - if (p != null) p.removeChild(div); - showing = false; - clearInterval(updateScaleTimer); - check(); - } - }, 999); - - btn.onclick = function() { - clearInterval(updateScaleTimer); - var p = div.parentNode; - if (p != null) p.removeChild(div); - ignore = true; - showing = false; - localStorage.setItem("bad-scale-ignore-it", "ignore-it"); - }; - - document.body.appendChild(div); - } - - function check() { - if (!ignore) { - var timer = setInterval(function() { - var scale = getScale(); - if (scale != 100 && !ignore) { - tryShowTopBar(scale); - clearInterval(timer); - } - if (ignore) { - clearInterval(timer); - } - }, 999); - } - } - - if (document.readyState != "complete") { - document.onreadystatechange = function() { - if (document.readyState != "complete") check(); - }; - } else { - check(); - } -})(); diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 8d3088cf..ccae242f 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -1,4 +1,4 @@ -/* + var contextMenuInit = function() { let eventListenerApplied = false; let menuSpecs = new Map(); @@ -174,4 +174,3 @@ var addContextMenuEventListener = initResponse[2]; //End example Context Menu Items onAfterUiUpdate(addContextMenuEventListener); -*/ diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js index 488ef41d..5803daea 100644 --- a/javascript/dragdrop.js +++ b/javascript/dragdrop.js @@ -1,109 +1,130 @@ // allows drag-dropping files into gradio image elements, and also pasting images from clipboard function isValidImageList(files) { - return ( - files && - files?.length === 1 && - ["image/png", "image/gif", "image/jpeg"].includes(files[0].type) - ); + return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type); } function dropReplaceImage(imgWrap, files) { - if (!isValidImageList(files)) { - return; - } - - const tmpFile = files[0]; - - imgWrap.querySelector('[aria-label="Clear"]')?.click(); - const callback = () => { - const fileInput = imgWrap.querySelector('input[type="file"]'); - if (fileInput) { - if (files.length === 0) { - files = new DataTransfer(); - files.items.add(tmpFile); - fileInput.files = files.files; - } else { - fileInput.files = files; - } - fileInput.dispatchEvent(new Event("change")); + if (!isValidImageList(files)) { + return; } - }; - if (imgWrap.closest("#pnginfo_image")) { - // special treatment for PNG Info tab, wait for fetch request to finish - const oldFetch = window.fetch; - window.fetch = async (input, options) => { - const response = await oldFetch(input, options); - if ("api/predict/" === input) { - const content = await response.text(); - window.fetch = oldFetch; - window.requestAnimationFrame(() => callback()); - return new Response(content, { - status: response.status, - statusText: response.statusText, - headers: response.headers, - }); - } - return response; + const tmpFile = files[0]; + + imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click(); + const callback = () => { + const fileInput = imgWrap.querySelector('input[type="file"]'); + if (fileInput) { + if (files.length === 0) { + files = new DataTransfer(); + files.items.add(tmpFile); + fileInput.files = files.files; + } else { + fileInput.files = files; + } + fileInput.dispatchEvent(new Event('change')); + } }; - } else { - window.requestAnimationFrame(() => callback()); - } + + if (imgWrap.closest('#pnginfo_image')) { + // special treatment for PNG Info tab, wait for fetch request to finish + const oldFetch = window.fetch; + window.fetch = async(input, options) => { + const response = await oldFetch(input, options); + if ('api/predict/' === input) { + const content = await response.text(); + window.fetch = oldFetch; + window.requestAnimationFrame(() => callback()); + return new Response(content, { + status: response.status, + statusText: response.statusText, + headers: response.headers + }); + } + return response; + }; + } else { + window.requestAnimationFrame(() => callback()); + } } -window.document.addEventListener("dragover", (e) => { - const target = e.composedPath()[0]; - const imgWrap = target.closest('[data-testid="image"]'); - if ( - !imgWrap && - target.placeholder && - target.placeholder.indexOf("Prompt") == -1 - ) { - return; - } - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = "copy"; +function eventHasFiles(e) { + if (!e.dataTransfer || !e.dataTransfer.files) return false; + if (e.dataTransfer.files.length > 0) return true; + if (e.dataTransfer.items.length > 0 && e.dataTransfer.items[0].kind == "file") return true; + + return false; +} + +function dragDropTargetIsPrompt(target) { + if (target?.placeholder && target?.placeholder.indexOf("Prompt") >= 0) return true; + if (target?.parentNode?.parentNode?.className?.indexOf("prompt") > 0) return true; + return false; +} + +window.document.addEventListener('dragover', e => { + const target = e.composedPath()[0]; + if (!eventHasFiles(e)) return; + + var targetImage = target.closest('[data-testid="image"]'); + if (!dragDropTargetIsPrompt(target) && !targetImage) return; + + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; }); -window.document.addEventListener("drop", (e) => { - const target = e.composedPath()[0]; - if (target.placeholder.indexOf("Prompt") == -1) { - return; - } - const imgWrap = target.closest('[data-testid="image"]'); - if (!imgWrap) { - return; - } - e.stopPropagation(); - e.preventDefault(); - const files = e.dataTransfer.files; - dropReplaceImage(imgWrap, files); +window.document.addEventListener('drop', e => { + const target = e.composedPath()[0]; + if (!eventHasFiles(e)) return; + if (dragDropTargetIsPrompt(target)) { + e.stopPropagation(); + e.preventDefault(); + + let prompt_target = get_tab_index('tabs') == 1 ? "img2img_prompt_image" : "txt2img_prompt_image"; + + const imgParent = gradioApp().getElementById(prompt_target); + const files = e.dataTransfer.files; + const fileInput = imgParent.querySelector('input[type="file"]'); + if (fileInput) { + fileInput.files = files; + fileInput.dispatchEvent(new Event('change')); + } + } + + var targetImage = target.closest('[data-testid="image"]'); + if (targetImage) { + e.stopPropagation(); + e.preventDefault(); + const files = e.dataTransfer.files; + dropReplaceImage(targetImage, files); + return; + } }); -window.addEventListener("paste", (e) => { - const files = e.clipboardData.files; - if (!isValidImageList(files)) { - return; - } +window.addEventListener('paste', e => { + const files = e.clipboardData.files; + if (!isValidImageList(files)) { + return; + } - const visibleImageFields = [ - ...gradioApp().querySelectorAll('[data-testid="image"]'), - ].filter((el) => uiElementIsVisible(el)); - if (!visibleImageFields.length) { - return; - } + const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')] + .filter(el => uiElementIsVisible(el)) + .sort((a, b) => uiElementInSight(b) - uiElementInSight(a)); - const firstFreeImageField = visibleImageFields.filter((el) => - el.querySelector("input[type=file]") - )?.[0]; - dropReplaceImage( - firstFreeImageField - ? firstFreeImageField - : visibleImageFields[visibleImageFields.length - 1], - files - ); + if (!visibleImageFields.length) { + return; + } + + const firstFreeImageField = visibleImageFields + .filter(el => el.querySelector('input[type=file]'))?.[0]; + + dropReplaceImage( + firstFreeImageField ? + firstFreeImageField : + visibleImageFields[visibleImageFields.length - 1] + , files + ); }); diff --git a/javascript/extensions.js b/javascript/extensions.js index 29185b4e..312131b7 100644 --- a/javascript/extensions.js +++ b/javascript/extensions.js @@ -1,3 +1,4 @@ + function extensions_apply(_disabled_list, _update_list, disable_all) { var disable = []; var update = []; @@ -32,7 +33,7 @@ function extensions_check() { var id = randomId(); - requestProgress(id, gradioApp().getElementById('extensions_installed_top'), null, function() { + requestProgress(id, gradioApp().getElementById('extensions_installed_html'), null, function() { }); diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 9a260fba..493f31af 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -1,579 +1,349 @@ -function setupExtraNetworksForTab(tabname) { - gradioApp() - .querySelector("#" + tabname + "_extra_tabs") - .classList.add("extra-networks"); - - let tabs = gradioApp().querySelector("#" + tabname + "_extra_tabs > div"); - let search = gradioApp().querySelector("#" + tabname + "_extra_search textarea" ); - let refresh = gradioApp().getElementById(tabname + "_extra_refresh"); - - //let sort = gradioApp().getElementById(tabname + '_extra_sort'); - //let sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder'); - - let clear = document.createElement("div"); - clear.id = tabname + "_extra_clear"; - clear.classList.add("token-remove", "remove-all", "svelte-a6vu2r", "hide"); - clear.title = "Clear search"; - clear.innerHTML = - ''; - - search.classList.add("search"); - - tabs.appendChild(search); - tabs.appendChild(clear); - tabs.appendChild(refresh); - -/* - sort.classList.add('sort'); - sortOrder.classList.add('sortorder'); - sort.dataset.sortkey = 'sortDefault'; - tabs.appendChild(sort); - tabs.appendChild(sortOrder); */ - - clear.addEventListener("click", function (evt) { - search.value = ""; - updateInput(search); - }); - - setTimeout(function () { - refresh.click(); - }, 500); - - - setTimeout(extraNetworksApplyFilter[tabname], 1); - - search.addEventListener("input", function (evt) { - searchTerm = search.value.toLowerCase(); - - gradioApp() - .querySelectorAll("#" + tabname + "_extra_tabs div.card") - .forEach(function (elem) { - let text = - elem.querySelector(".name").textContent.toLowerCase() + - " " + - elem.querySelector(".search_term").textContent.toLowerCase(); - elem.parentElement.style.display = - text.indexOf(searchTerm) == -1 ? "none" : ""; - }); - }); -} - -function applyExtraNetworkFilter(tabname){ - setTimeout(extraNetworksApplyFilter[tabname], 1); -} - -var extraNetworksApplyFilter = {} -var activePromptTextarea = {}; - -function setupExtraNetworks() { - setupExtraNetworksForTab("txt2img"); - setupExtraNetworksForTab("img2img"); - - function registerPrompt(tabname, id) { - var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); - - if (!activePromptTextarea[tabname]) { - activePromptTextarea[tabname] = textarea; - } - - textarea.addEventListener("focus", function () { - activePromptTextarea[tabname] = textarea; - }); - } - - registerPrompt("txt2img", "txt2img_prompt"); - registerPrompt("txt2img", "txt2img_neg_prompt"); - registerPrompt("img2img", "img2img_prompt"); - registerPrompt("img2img", "img2img_neg_prompt"); -} - -onUiLoaded(setupExtraNetworks); - -var re_extranet = /<([^:]+:[^:]+):[\d\.]+>/; -var re_extranet_g = /\s+<([^:]+:[^:]+):[\d\.]+>/g; - -function tryToRemoveExtraNetworkFromPrompt(textarea, text) { - var m = text.match(re_extranet); - if (!m) return false; - - var partToSearch = m[1]; - var replaced = false; - var newTextareaText = textarea.value.replaceAll( - re_extranet_g, - function (found) { - m = found.match(re_extranet); - if (m[1] == partToSearch) { - replaced = true; - return ""; - } - return found; - } - ); - - if (replaced) { - textarea.value = newTextareaText; - return true; - } - - return false; -} - -function cardClicked(tabname, textToAdd, allowNegativePrompt) { - var textarea = allowNegativePrompt - ? activePromptTextarea[tabname] - : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea"); - - if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) { - textarea.value = - textarea.value + opts.extra_networks_add_text_separator + textToAdd; - } - - updateInput(textarea); -} - -function saveCardPreview(event, tabname, filename) { - var textarea = gradioApp().querySelector( - "#" + tabname + "_preview_filename > label > textarea" - ); - var button = gradioApp().getElementById(tabname + "_save_preview"); - - textarea.value = filename; - updateInput(textarea); - - button.click(); - - var search = gradioApp().querySelector( - "#" + tabname + "_extra_tabs textarea" - ); - - setTimeout(function () { - search.value = search.value.toLowerCase(); - updateInput(search); - }, 1000); - - event.stopPropagation(); - event.preventDefault(); -} - -function extraNetworksSearchButton(tabs_id, event) { - var searchTextarea = gradioApp().querySelector( - "#" + tabs_id + " > div > textarea" - ); - var button = event.target; - var text = button.classList.contains("search-all") - ? "" - : button.textContent.trim(); - //text = event.target.selectedIndex == 0 ? "" : event.target.options[event.target.selectedIndex].text; - - searchTextarea.value = text; - updateInput(searchTextarea); -} - -var globalPopup = null; -var globalPopupInner = null; -function popup(contents) { - if (!globalPopup) { - globalPopup = document.createElement("div"); - globalPopup.onclick = function () { - globalPopup.style.display = "none"; - }; - globalPopup.classList.add("global-popup"); - - var close = document.createElement("div"); - close.classList.add("global-popup-close"); - close.onclick = function () { - globalPopup.style.display = "none"; - }; - close.title = "Close"; - globalPopup.appendChild(close); - - globalPopupInner = document.createElement("div"); - globalPopupInner.onclick = function (event) { - event.stopPropagation(); - return false; - }; - globalPopupInner.classList.add("global-popup-inner"); - globalPopup.appendChild(globalPopupInner); - - gradioApp().appendChild(globalPopup); - } - - globalPopupInner.innerHTML = ""; - globalPopupInner.appendChild(contents); - - globalPopup.style.display = "flex"; -} - -function extraNetworksShowMetadata(text) { - var elem = document.createElement("pre"); - elem.classList.add("popup-metadata"); - elem.textContent = text; - - popup(elem); -} - -function requestGet(url, data, handler, errorHandler) { - var xhr = new XMLHttpRequest(); - var args = Object.keys(data) - .map(function (k) { - return encodeURIComponent(k) + "=" + encodeURIComponent(data[k]); - }) - .join("&"); - xhr.open("GET", url + "?" + args, true); - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - try { - var js = JSON.parse(xhr.responseText); - handler(js); - } catch (error) { - console.error(error); - errorHandler(); - } - } else { - errorHandler(); - } - } - }; - var js = JSON.stringify(data); - xhr.send(js); -} - -function extraNetworksRequestMetadata(event, extraPage, cardName) { - var showError = function () { - extraNetworksShowMetadata("there was an error getting metadata"); - }; - - requestGet( - "./sd_extra_networks/metadata", - { page: extraPage, item: cardName }, - function (data) { - if (data && data.metadata) { - extraNetworksShowMetadata(data.metadata); - } else { - showError(); - } - }, - showError - ); - - event.stopPropagation(); -} - - -/* -function setupExtraNetworksForTab(tabname) { - gradioApp().querySelector('#' + tabname + '_extra_tabs').classList.add('extra-networks'); - - var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div'); - var search = gradioApp().querySelector('#' + tabname + '_extra_search textarea'); - var sort = gradioApp().getElementById(tabname + '_extra_sort'); - var sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder'); - var refresh = gradioApp().getElementById(tabname + '_extra_refresh'); - - search.classList.add('search'); - sort.classList.add('sort'); - sortOrder.classList.add('sortorder'); - sort.dataset.sortkey = 'sortDefault'; - tabs.appendChild(search); - tabs.appendChild(sort); - tabs.appendChild(sortOrder); - tabs.appendChild(refresh); - - var applyFilter = function() { - var searchTerm = search.value.toLowerCase(); - - gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card').forEach(function(elem) { - var searchOnly = elem.querySelector('.search_only'); - var text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase(); - - var visible = text.indexOf(searchTerm) != -1; - - if (searchOnly && searchTerm.length < 4) { - visible = false; - } - - elem.style.display = visible ? "" : "none"; - }); - }; - - var applySort = function() { - var reverse = sortOrder.classList.contains("sortReverse"); - var sortKey = sort.querySelector("input").value.toLowerCase().replace("sort", "").replaceAll(" ", "_").replace(/_+$/, "").trim(); - sortKey = sortKey ? "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1) : ""; - var sortKeyStore = sortKey ? sortKey + (reverse ? "Reverse" : "") : ""; - if (!sortKey || sortKeyStore == sort.dataset.sortkey) { - return; - } - - sort.dataset.sortkey = sortKeyStore; - - var cards = gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card'); - cards.forEach(function(card) { - card.originalParentElement = card.parentElement; - }); - var sortedCards = Array.from(cards); - sortedCards.sort(function(cardA, cardB) { - var a = cardA.dataset[sortKey]; - var b = cardB.dataset[sortKey]; - if (!isNaN(a) && !isNaN(b)) { - return parseInt(a) - parseInt(b); - } - - return (a < b ? -1 : (a > b ? 1 : 0)); - }); - if (reverse) { - sortedCards.reverse(); - } - cards.forEach(function(card) { - card.remove(); - }); - sortedCards.forEach(function(card) { - card.originalParentElement.appendChild(card); - }); - }; - - search.addEventListener("input", applyFilter); - applyFilter(); - ["change", "blur", "click"].forEach(function(evt) { - sort.querySelector("input").addEventListener(evt, applySort); - }); - sortOrder.addEventListener("click", function() { - sortOrder.classList.toggle("sortReverse"); - applySort(); - }); - - extraNetworksApplyFilter[tabname] = applyFilter; -} - -function applyExtraNetworkFilter(tabname) { - setTimeout(extraNetworksApplyFilter[tabname], 1); -} - -var extraNetworksApplyFilter = {}; -var activePromptTextarea = {}; - -function setupExtraNetworks() { - setupExtraNetworksForTab('txt2img'); - setupExtraNetworksForTab('img2img'); - - function registerPrompt(tabname, id) { - var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); - - if (!activePromptTextarea[tabname]) { - activePromptTextarea[tabname] = textarea; - } - - textarea.addEventListener("focus", function() { - activePromptTextarea[tabname] = textarea; - }); - } - - registerPrompt('txt2img', 'txt2img_prompt'); - registerPrompt('txt2img', 'txt2img_neg_prompt'); - registerPrompt('img2img', 'img2img_prompt'); - registerPrompt('img2img', 'img2img_neg_prompt'); -} - -onUiLoaded(setupExtraNetworks); - -var re_extranet = /<([^:]+:[^:]+):[\d.]+>(.*)/; -var re_extranet_g = /\s+<([^:]+:[^:]+):[\d.]+>/g; - -function tryToRemoveExtraNetworkFromPrompt(textarea, text) { - var m = text.match(re_extranet); - var replaced = false; - var newTextareaText; - if (m) { - var extraTextAfterNet = m[2]; - var partToSearch = m[1]; - var foundAtPosition = -1; - newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, net, pos) { - m = found.match(re_extranet); - if (m[1] == partToSearch) { - replaced = true; - foundAtPosition = pos; - return ""; - } - return found; - }); - - if (foundAtPosition >= 0 && newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) { - newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length); - } - } else { - newTextareaText = textarea.value.replaceAll(new RegExp(text, "g"), function(found) { - if (found == text) { - replaced = true; - return ""; - } - return found; - }); - } - - if (replaced) { - textarea.value = newTextareaText; - return true; - } - - return false; -} - -function cardClicked(tabname, textToAdd, allowNegativePrompt) { - var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea"); - - if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) { - textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd; - } - - updateInput(textarea); -} - -function saveCardPreview(event, tabname, filename) { - var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea'); - var button = gradioApp().getElementById(tabname + '_save_preview'); - - textarea.value = filename; - updateInput(textarea); - - button.click(); - - event.stopPropagation(); - event.preventDefault(); -} - -function extraNetworksSearchButton(tabs_id, event) { - var searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea'); - var button = event.target; - var text = button.classList.contains("search-all") ? "" : button.textContent.trim(); - - searchTextarea.value = text; - updateInput(searchTextarea); -} - -var globalPopup = null; -var globalPopupInner = null; -function closePopup() { - if (!globalPopup) return; - - globalPopup.style.display = "none"; -} -function popup(contents) { - if (!globalPopup) { - globalPopup = document.createElement('div'); - globalPopup.onclick = closePopup; - globalPopup.classList.add('global-popup'); - - var close = document.createElement('div'); - close.classList.add('global-popup-close'); - close.onclick = closePopup; - close.title = "Close"; - globalPopup.appendChild(close); - - globalPopupInner = document.createElement('div'); - globalPopupInner.onclick = function(event) { - event.stopPropagation(); return false; - }; - globalPopupInner.classList.add('global-popup-inner'); - globalPopup.appendChild(globalPopupInner); - - gradioApp().querySelector('.main').appendChild(globalPopup); - } - - globalPopupInner.innerHTML = ''; - globalPopupInner.appendChild(contents); - - globalPopup.style.display = "flex"; -} - -function extraNetworksShowMetadata(text) { - var elem = document.createElement('pre'); - elem.classList.add('popup-metadata'); - elem.textContent = text; - - popup(elem); -} - -function requestGet(url, data, handler, errorHandler) { - var xhr = new XMLHttpRequest(); - var args = Object.keys(data).map(function(k) { - return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]); - }).join('&'); - xhr.open("GET", url + "?" + args, true); - - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - try { - var js = JSON.parse(xhr.responseText); - handler(js); - } catch (error) { - console.error(error); - errorHandler(); - } - } else { - errorHandler(); - } - } - }; - var js = JSON.stringify(data); - xhr.send(js); -} - -function extraNetworksRequestMetadata(event, extraPage, cardName) { - var showError = function() { - extraNetworksShowMetadata("there was an error getting metadata"); - }; - - requestGet("./sd_extra_networks/metadata", {page: extraPage, item: cardName}, function(data) { - if (data && data.metadata) { - extraNetworksShowMetadata(data.metadata); - } else { - showError(); - } - }, showError); - - event.stopPropagation(); -} - -var extraPageUserMetadataEditors = {}; - -function extraNetworksEditUserMetadata(event, tabname, extraPage, cardName) { - var id = tabname + '_' + extraPage + '_edit_user_metadata'; - - var editor = extraPageUserMetadataEditors[id]; - if (!editor) { - editor = {}; - editor.page = gradioApp().getElementById(id); - editor.nameTextarea = gradioApp().querySelector("#" + id + "_name" + ' textarea'); - editor.button = gradioApp().querySelector("#" + id + "_button"); - extraPageUserMetadataEditors[id] = editor; - } - - editor.nameTextarea.value = cardName; - updateInput(editor.nameTextarea); - - editor.button.click(); - - popup(editor.page); - - event.stopPropagation(); -} - -function extraNetworksRefreshSingleCard(page, tabname, name) { - requestGet("./sd_extra_networks/get-single-card", {page: page, tabname: tabname, name: name}, function(data) { - if (data && data.html) { - var card = gradioApp().querySelector('.card[data-name=' + JSON.stringify(name) + ']'); // likely using the wrong stringify function - - var newDiv = document.createElement('DIV'); - newDiv.innerHTML = data.html; - var newCard = newDiv.firstElementChild; - - newCard.style = ''; - card.parentElement.insertBefore(newCard, card); - card.parentElement.removeChild(card); - } - }); -} -*/ \ No newline at end of file +function toggleCss(key, css, enable) { + var style = document.getElementById(key); + if (enable && !style) { + style = document.createElement('style'); + style.id = key; + style.type = 'text/css'; + document.head.appendChild(style); + } + if (style && !enable) { + document.head.removeChild(style); + } + if (style) { + style.innerHTML == ''; + style.appendChild(document.createTextNode(css)); + } +} + +function setupExtraNetworksForTab(tabname) { + gradioApp().querySelector('#' + tabname + '_extra_tabs').classList.add('extra-networks'); + + var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div'); + var searchDiv = gradioApp().getElementById(tabname + '_extra_search'); + var search = searchDiv.querySelector('textarea'); + var sort = gradioApp().getElementById(tabname + '_extra_sort'); + var sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder'); + var refresh = gradioApp().getElementById(tabname + '_extra_refresh'); + var showDirsDiv = gradioApp().getElementById(tabname + '_extra_show_dirs'); + var showDirs = gradioApp().querySelector('#' + tabname + '_extra_show_dirs input'); + + sort.dataset.sortkey = 'sortDefault'; + tabs.appendChild(searchDiv); + tabs.appendChild(sort); + tabs.appendChild(sortOrder); + tabs.appendChild(refresh); + tabs.appendChild(showDirsDiv); + + var applyFilter = function() { + var searchTerm = search.value.toLowerCase(); + + gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card').forEach(function(elem) { + var searchOnly = elem.querySelector('.search_only'); + var text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase(); + + var visible = text.indexOf(searchTerm) != -1; + + if (searchOnly && searchTerm.length < 4) { + visible = false; + } + + elem.style.display = visible ? "" : "none"; + }); + }; + + var applySort = function() { + var reverse = sortOrder.classList.contains("sortReverse"); + var sortKey = sort.querySelector("input").value.toLowerCase().replace("sort", "").replaceAll(" ", "_").replace(/_+$/, "").trim(); + sortKey = sortKey ? "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1) : ""; + var sortKeyStore = sortKey ? sortKey + (reverse ? "Reverse" : "") : ""; + if (!sortKey || sortKeyStore == sort.dataset.sortkey) { + return; + } + + sort.dataset.sortkey = sortKeyStore; + + var cards = gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card'); + cards.forEach(function(card) { + card.originalParentElement = card.parentElement; + }); + var sortedCards = Array.from(cards); + sortedCards.sort(function(cardA, cardB) { + var a = cardA.dataset[sortKey]; + var b = cardB.dataset[sortKey]; + if (!isNaN(a) && !isNaN(b)) { + return parseInt(a) - parseInt(b); + } + + return (a < b ? -1 : (a > b ? 1 : 0)); + }); + if (reverse) { + sortedCards.reverse(); + } + cards.forEach(function(card) { + card.remove(); + }); + sortedCards.forEach(function(card) { + card.originalParentElement.appendChild(card); + }); + }; + + search.addEventListener("input", applyFilter); + applyFilter(); + ["change", "blur", "click"].forEach(function(evt) { + sort.querySelector("input").addEventListener(evt, applySort); + }); + sortOrder.addEventListener("click", function() { + sortOrder.classList.toggle("sortReverse"); + applySort(); + }); + + extraNetworksApplyFilter[tabname] = applyFilter; + + var showDirsUpdate = function() { + var css = '#' + tabname + '_extra_tabs .extra-network-subdirs { display: none; }'; + toggleCss(tabname + '_extra_show_dirs_style', css, !showDirs.checked); + localSet('extra-networks-show-dirs', showDirs.checked ? 1 : 0); + }; + showDirs.checked = localGet('extra-networks-show-dirs', 1) == 1; + showDirs.addEventListener("change", showDirsUpdate); + showDirsUpdate(); +} + +function applyExtraNetworkFilter(tabname) { + setTimeout(extraNetworksApplyFilter[tabname], 1); +} + +var extraNetworksApplyFilter = {}; +var activePromptTextarea = {}; + +function setupExtraNetworks() { + setupExtraNetworksForTab('txt2img'); + setupExtraNetworksForTab('img2img'); + + function registerPrompt(tabname, id) { + var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); + + if (!activePromptTextarea[tabname]) { + activePromptTextarea[tabname] = textarea; + } + + textarea.addEventListener("focus", function() { + activePromptTextarea[tabname] = textarea; + }); + } + + registerPrompt('txt2img', 'txt2img_prompt'); + registerPrompt('txt2img', 'txt2img_neg_prompt'); + registerPrompt('img2img', 'img2img_prompt'); + registerPrompt('img2img', 'img2img_neg_prompt'); +} + +onUiLoaded(setupExtraNetworks); + +var re_extranet = /<([^:]+:[^:]+):[\d.]+>(.*)/; +var re_extranet_g = /\s+<([^:]+:[^:]+):[\d.]+>/g; + +function tryToRemoveExtraNetworkFromPrompt(textarea, text) { + var m = text.match(re_extranet); + var replaced = false; + var newTextareaText; + if (m) { + var extraTextAfterNet = m[2]; + var partToSearch = m[1]; + var foundAtPosition = -1; + newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, net, pos) { + m = found.match(re_extranet); + if (m[1] == partToSearch) { + replaced = true; + foundAtPosition = pos; + return ""; + } + return found; + }); + + if (foundAtPosition >= 0 && newTextareaText.substr(foundAtPosition, extraTextAfterNet.length) == extraTextAfterNet) { + newTextareaText = newTextareaText.substr(0, foundAtPosition) + newTextareaText.substr(foundAtPosition + extraTextAfterNet.length); + } + } else { + newTextareaText = textarea.value.replaceAll(new RegExp(text, "g"), function(found) { + if (found == text) { + replaced = true; + return ""; + } + return found; + }); + } + + if (replaced) { + textarea.value = newTextareaText; + return true; + } + + return false; +} + +function cardClicked(tabname, textToAdd, allowNegativePrompt) { + var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea"); + + if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) { + textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd; + } + + updateInput(textarea); +} + +function saveCardPreview(event, tabname, filename) { + var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea'); + var button = gradioApp().getElementById(tabname + '_save_preview'); + + textarea.value = filename; + updateInput(textarea); + + button.click(); + + event.stopPropagation(); + event.preventDefault(); +} + +function extraNetworksSearchButton(tabs_id, event) { + var searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > label > textarea'); + var button = event.target; + var text = button.classList.contains("search-all") ? "" : button.textContent.trim(); + + searchTextarea.value = text; + updateInput(searchTextarea); +} + +var globalPopup = null; +var globalPopupInner = null; +function closePopup() { + if (!globalPopup) return; + + globalPopup.style.display = "none"; +} +function popup(contents) { + if (!globalPopup) { + globalPopup = document.createElement('div'); + globalPopup.onclick = closePopup; + globalPopup.classList.add('global-popup'); + + var close = document.createElement('div'); + close.classList.add('global-popup-close'); + close.onclick = closePopup; + close.title = "Close"; + globalPopup.appendChild(close); + + globalPopupInner = document.createElement('div'); + globalPopupInner.onclick = function(event) { + event.stopPropagation(); return false; + }; + globalPopupInner.classList.add('global-popup-inner'); + globalPopup.appendChild(globalPopupInner); + + gradioApp().querySelector('.main').appendChild(globalPopup); + } + + globalPopupInner.innerHTML = ''; + globalPopupInner.appendChild(contents); + + globalPopup.style.display = "flex"; +} + +var storedPopupIds = {}; +function popupId(id) { + if (!storedPopupIds[id]) { + storedPopupIds[id] = gradioApp().getElementById(id); + } + + popup(storedPopupIds[id]); +} + +function extraNetworksShowMetadata(text) { + var elem = document.createElement('pre'); + elem.classList.add('popup-metadata'); + elem.textContent = text; + + popup(elem); +} + +function requestGet(url, data, handler, errorHandler) { + var xhr = new XMLHttpRequest(); + var args = Object.keys(data).map(function(k) { + return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]); + }).join('&'); + xhr.open("GET", url + "?" + args, true); + + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + try { + var js = JSON.parse(xhr.responseText); + handler(js); + } catch (error) { + console.error(error); + errorHandler(); + } + } else { + errorHandler(); + } + } + }; + var js = JSON.stringify(data); + xhr.send(js); +} + +function extraNetworksRequestMetadata(event, extraPage, cardName) { + var showError = function() { + extraNetworksShowMetadata("there was an error getting metadata"); + }; + + requestGet("./sd_extra_networks/metadata", {page: extraPage, item: cardName}, function(data) { + if (data && data.metadata) { + extraNetworksShowMetadata(data.metadata); + } else { + showError(); + } + }, showError); + + event.stopPropagation(); +} + +var extraPageUserMetadataEditors = {}; + +function extraNetworksEditUserMetadata(event, tabname, extraPage, cardName) { + var id = tabname + '_' + extraPage + '_edit_user_metadata'; + + var editor = extraPageUserMetadataEditors[id]; + if (!editor) { + editor = {}; + editor.page = gradioApp().getElementById(id); + editor.nameTextarea = gradioApp().querySelector("#" + id + "_name" + ' textarea'); + editor.button = gradioApp().querySelector("#" + id + "_button"); + extraPageUserMetadataEditors[id] = editor; + } + + editor.nameTextarea.value = cardName; + updateInput(editor.nameTextarea); + + editor.button.click(); + + popup(editor.page); + + event.stopPropagation(); +} + +function extraNetworksRefreshSingleCard(page, tabname, name) { + requestGet("./sd_extra_networks/get-single-card", {page: page, tabname: tabname, name: name}, function(data) { + if (data && data.html) { + var card = gradioApp().querySelector('.card[data-name=' + JSON.stringify(name) + ']'); // likely using the wrong stringify function + + var newDiv = document.createElement('DIV'); + newDiv.innerHTML = data.html; + var newCard = newDiv.firstElementChild; + + newCard.style.display = ''; + card.parentElement.insertBefore(newCard, card); + card.parentElement.removeChild(card); + } + }); +} diff --git a/javascript/generationParams.js b/javascript/generationParams.js index 35ccd716..7c0fd221 100644 --- a/javascript/generationParams.js +++ b/javascript/generationParams.js @@ -1,4 +1,5 @@ // attaches listeners to the txt2img and img2img galleries to update displayed generation param text when the image changes + let txt2img_gallery, img2img_gallery, modal = undefined; onAfterUiUpdate(function() { if (!txt2img_gallery) { @@ -7,6 +8,10 @@ onAfterUiUpdate(function() { if (!img2img_gallery) { img2img_gallery = attachGalleryListeners("img2img"); } + if (!modal) { + modal = gradioApp().getElementById('lightboxModal'); + modalObserver.observe(modal, {attributes: true, attributeFilter: ['style']}); + } }); let modalObserver = new MutationObserver(function(mutations) { diff --git a/javascript/hints.js b/javascript/hints.js index f3dd9019..6de9372e 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -23,12 +23,7 @@ var titles = { "\u{1f4cb}": "Apply selected styles to current prompt", "\u{1f4d2}": "Paste available values into the field", "\u{1f3b4}": "Show/hide extra networks", - - "\u{1f5e8}": "Interogate Clip", - "\u{1f5ea}": "Interogate Deepbooru", - "\u{1F300}": "Restore progress", - "\u{267E}": "Toggle generate forever", - + "\u{1f300}": "Restore progress", "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", "SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back", @@ -50,11 +45,6 @@ var titles = { "Skip": "Stop processing current image and continue processing.", "Interrupt": "Stop processing images and return any results accumulated so far.", "Save": "Write image to a directory (default - log/images) and generation parameters into csv file.", - "Zip": "Save as Zip", - "Send to txt2img": "Send to txt2img", - "Send to img2img": "Send to img2img", - "Send to inpaint": "Send to inpaint", - "Send to extras": "Send to extras", "X values": "Separate values for X axis using commas.", "Y values": "Separate values for Y axis using commas.", @@ -200,3 +190,14 @@ onUiUpdate(function(mutationRecords) { tooltipCheckTimer = setTimeout(processTooltipCheckNodes, 1000); } }); + +onUiLoaded(function() { + for (var comp of window.gradio_config.components) { + if (comp.props.webui_tooltip && comp.props.elem_id) { + var elem = gradioApp().getElementById(comp.props.elem_id); + if (elem) { + elem.title = comp.props.webui_tooltip; + } + } + } +}); diff --git a/javascript/hires_fix.js b/javascript/hires_fix.js index 2c111bd8..0d04ab3b 100644 --- a/javascript/hires_fix.js +++ b/javascript/hires_fix.js @@ -1,19 +1,18 @@ -function onCalcResolutionHires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y) { - function setInactive(elem, inactive) { - elem.classList.toggle('inactive', !!inactive); - } - - var hrUpscaleBy = gradioApp().getElementById('txt2img_hr_scale'); - var hrResizeX = gradioApp().getElementById('txt2img_hr_resize_x'); - var hrResizeY = gradioApp().getElementById('txt2img_hr_resize_y'); - - gradioApp().getElementById('txt2img_hires_fix_row2').style.display = opts.use_old_hires_fix_width_height ? "none" : "block"; - - setInactive(hrUpscaleBy, opts.use_old_hires_fix_width_height || hr_resize_x > 0 || hr_resize_y > 0); - setInactive(hrResizeX, opts.use_old_hires_fix_width_height || hr_resize_x == 0); - setInactive(hrResizeY, opts.use_old_hires_fix_width_height || hr_resize_y == 0); - - setTimeout(function () { - return [enable, width, height, hr_scale, hr_resize_x, hr_resize_y]; - }, 100); -} + +function onCalcResolutionHires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y) { + function setInactive(elem, inactive) { + elem.classList.toggle('inactive', !!inactive); + } + + var hrUpscaleBy = gradioApp().getElementById('txt2img_hr_scale'); + var hrResizeX = gradioApp().getElementById('txt2img_hr_resize_x'); + var hrResizeY = gradioApp().getElementById('txt2img_hr_resize_y'); + + gradioApp().getElementById('txt2img_hires_fix_row2').style.display = opts.use_old_hires_fix_width_height ? "none" : ""; + + setInactive(hrUpscaleBy, opts.use_old_hires_fix_width_height || hr_resize_x > 0 || hr_resize_y > 0); + setInactive(hrResizeX, opts.use_old_hires_fix_width_height || hr_resize_x == 0); + setInactive(hrResizeY, opts.use_old_hires_fix_width_height || hr_resize_y == 0); + + return [enable, width, height, hr_scale, hr_resize_x, hr_resize_y]; +} diff --git a/javascript/imageMaskFix.js b/javascript/imageMaskFix.js index d1a07807..900c56f3 100644 --- a/javascript/imageMaskFix.js +++ b/javascript/imageMaskFix.js @@ -2,10 +2,6 @@ * temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668 * @see https://github.com/gradio-app/gradio/issues/1721 */ - -/* -window.addEventListener( 'resize', () => imageMaskResize()); - function imageMaskResize() { const canvases = gradioApp().querySelectorAll('#img2maskimg .touch-none canvas'); if (!canvases.length) { @@ -41,299 +37,7 @@ function imageMaskResize() { c.style.maxHeight = '100%'; c.style.objectFit = 'contain'; }); - } - - onUiUpdate(() => imageMaskResize()); -*/ - -onUiLoaded(function () { - const color_box = ''; - const brush_size = ''; - let is_drawing = false; - let img_src = []; - let spl_instances = []; - let spl_pan_instances = []; - let img2img_tab_index = 0; - let intervalLastUIUpdate; - const container = gradioApp().querySelector(".gradio-container"); - const observer = new MutationObserver(() => - gradioApp() - .querySelectorAll('div[data-testid="image"]') - .forEach(function (elem, i) { - let img_parent = elem.parentElement.querySelector( - 'div[data-testid="image"] > div' - ); - let img = img_parent.querySelector("img"); - if (img) { - if (img_src[i] != img.src) { - let tool_buttons = img_parent.querySelectorAll("button"); - //console.log(tool_buttons); - if (tool_buttons.length > 2) { - img_parent.style.visibility = "hidden"; - - if (intervalLastUIUpdate != null) - clearInterval(intervalLastUIUpdate); - - intervalLastUIUpdate = setInterval(function () { - clearInterval(intervalLastUIUpdate); - img_parent.addEventListener("mouseup", function (e) {}); - - let spl_parent = elem.parentElement; - let spl; - let spl_pan; - let isPanning; - let splid; - - if (spl_parent.className != "spl-pane") { - spl = new Spotlight(); - spl.init(spl_parent, "-" + spl_parent.id); - - spl.addControl("undo", spl_undo_handler); - spl_pan = spl.addControl("pan", spl_pan_handler); - spl.addControl("brush", spl_brush_handler, brush_size); - if (tool_buttons.length == 5) { - spl.addControl("color", spl_color_handler, color_box); - } - spl.addControl("clear", spl_clear_handler); - - spl_instances[i] = spl; - spl_pan_instances[i] = spl_pan; - } else { - spl = spl_instances[i]; - spl_pan = spl_pan_instances[i]; - } - - img_src[i] = img.src; - //console.log("NEWIMAGE"); - - function spl_undo_handler(e) { - tool_buttons[0].click(); - } - - function spl_clear_handler(e) { - tool_buttons[2].click(); - spl.panzoom(false); - img_parent.classList.remove("no-point-events"); - img_parent.parentElement.classList.remove("move"); - document.removeEventListener("wheel", preventDefault, false); - setTimeout(function () { - spl.close(false, true); - img_parent.style.flexGrow = "1"; - img_src[i] = ""; - elem.style.transform = "none"; - }, 500); - } - - function spl_color_handler(e) {} - function spl_brush_handler(e) {} - - function preventDefault(e) { - e = e || window.event; - if (e.preventDefault) { - e.preventDefault(); - } - e.returnValue = false; - } - - function pan_toggle(val, target) { - isPanning = val; - target.classList.toggle("on", isPanning); - spl.panzoom(val); - - if (isPanning) { - img_parent.classList.add("no-point-events"); - img_parent.parentElement.classList.add("move"); - document.addEventListener("wheel", preventDefault, { - passive: false, - }); - } else { - img_parent.classList.remove("no-point-events"); - img_parent.parentElement.classList.remove("move"); - document.removeEventListener( - "wheel", - preventDefault, - false - ); - } - } - - function spl_pan_handler(e) { - isPanning = !isPanning; - pan_toggle(isPanning, this); - } - - function update_color(listener) { - let input_color = img_parent.querySelector( - "input[type='color']" - ); - let spl = - img_parent.parentElement.parentElement.parentElement - .parentElement.parentElement; - let spl_color = spl.querySelector( - ".spl-color input[type='color']" - ); - spl_color.value = input_color.value; - - if (listener) { - spl_color.addEventListener("input", function (ev) { - input_color.value = ev.target.value; - updateInput(input_color); - pan_toggle(false, spl_pan); - }); - } - } - - function update_brush(listener) { - let input_range = img_parent.querySelector( - "input[type='range']" - ); - let spl = - img_parent.parentElement.parentElement.parentElement - .parentElement.parentElement; - let spl_brush = spl.querySelector( - ".spl-brush input[type='range']" - ); - spl_brush.value = input_range.value; - - if (listener) { - spl_brush.addEventListener("input", function (ev) { - input_range.value = ev.target.value; - updateInput(input_range); - }); - } - } - - function init_drawing_tools() { - let input_color = img_parent.querySelector( - "input[type='color']" - ); - if (!input_color) { - let tbcolor = img_parent.querySelector( - "button[aria-label='Select brush color']" - ); - if (tbcolor) { - tbcolor.click(); - setTimeout(function () { - update_color(true); - }, 100); - } - } else { - setTimeout(function () { - update_color(false); - }, 100); - } - - let input_range = img_parent.querySelector( - "input[type='range']" - ); - if (!input_range) { - let tbrange = img_parent.querySelector( - "button[aria-label='Use brush']" - ); - - if (tbrange) { - tbrange.click(); - setTimeout(function () { - update_brush(true); - }, 100); - } - } else { - setTimeout(function () { - update_brush(false); - }, 100); - } - } - - let w = img.naturalWidth; - let h = img.naturalHeight; - img_parent.style.width = `${w}px`; - img_parent.style.height = `${h}px`; - - spl.show([ - { - media: "node", - src: elem, - //autohide: true, - //control: ["pan","clear","undo","fullscreen","autofit","zoom-in","zoom-out","close"], - class: "relative", - }, - ]); - - img_parent.style.flexGrow = "0"; - pan_toggle(false, spl_pan); - spl.panzoom(false); - setTimeout(function () { - init_drawing_tools(); - }, 500); - img_parent.style.visibility = "visible"; - }, 1000); - } - } - } - }) - ); - observer.observe(container, { childList: true, subtree: true }); - - /* gradioApp().querySelectorAll('#mode_img2img > .tabitem').forEach(function (tb, ti){ - tb.querySelectorAll('[id^="img2img_copy_to_"] > button').forEach(function (btn, bi){ - - btn.addEventListener("click", function(e) { - console.log(ti + " > " + bi); - let src_canvas = tb.querySelector('[key="drawing"]'); - if(src_canvas){ - let dest_canvas = gradioApp().querySelector('#mode_img2img .tabitem:nth-child('+parseInt(bi+1)+') [key="drawing"]'); - //let destCtx = dest_canvas.getContext('2d'); - //destCtx.drawImage(src_canvas, 0, 0); - console.log(src_canvas); - console.log(dest_canvas); - } - }) - }) - }) - - */ -}); - -/* -let intervalLastUIUpdate; -function onLastUIUpdate(){ - clearInterval(intervalLastUIUpdate); - const img2img_tab = gradioApp().querySelector('#img2img_img2img_tab'); - if(img2img_tab && selectedTabItemId=="tab_img2img"){ - const current_img2img_tab_index = get_img2img_tab_index()[0]; - //if(img2img_tab_index != current_img2img_tab_index){ - console.log(current_img2img_tab_index); - if(current_img2img_tab_index > 3 || current_img2img_tab_index == 0) return; - img2img_tab_index = current_img2img_tab_index; - let tabid; - - if(img2img_tab_index == 1){ - tabid = "#img2img_img2img_sketch_tab";// #img2img_sketch"; - }else if(img2img_tab_index == 2){ - tabid = "#img2img_inpaint_tab";// #img2maskimg"; - }else if(img2img_tab_index == 3){ - tabid = "#img2img_inpaint_sketch_tab";// #inpaint_sketch"; - } - //const parent_img2img_tab_img = gradioApp().querySelector('#mode_img2img > div:nth-child('+(img2img_tab_index+2)+') div[data-testid="image"] > div'); - const parent_img2img_tab_img = gradioApp().querySelector('#mode_img2img '+tabid+' div[data-testid="image"] > div'); - const img2img_tab_img = parent_img2img_tab_img.querySelector('img'); - if(img2img_tab_img){ - parent_img2img_tab_img.style.flexGrow = "0"; - img2img_tab_img.onload = function() { - let w = this.naturalWidth; - let h = this.naturalHeight; - parent_img2img_tab_img.style.width = `${w}px`; - parent_img2img_tab_img.style.height = `${h}px`; - } - }else{ - parent_img2img_tab_img.style.flexGrow = "1"; - } - //} - } } -onUiUpdate(function() { - if(intervalLastUIUpdate != null) clearInterval(intervalLastUIUpdate); - intervalLastUIUpdate = setInterval(onLastUIUpdate, 1000); -}) */ - +onAfterUiUpdate(imageMaskResize); +window.addEventListener('resize', imageMaskResize); diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js index 6a910b57..c21d396e 100644 --- a/javascript/imageviewer.js +++ b/javascript/imageviewer.js @@ -1,242 +1,259 @@ -//called from progressbar -function showGalleryImage() { - //need to clean up the old code +// A full size 'lightbox' preview modal shown when left clicking on gallery previews +function closeModal() { + gradioApp().getElementById("lightboxModal").style.display = "none"; } -let like; -let tile; +function showModal(event) { + const source = event.target || event.srcElement; + const modalImage = gradioApp().getElementById("modalImage"); + const lb = gradioApp().getElementById("lightboxModal"); + modalImage.src = source.src; + if (modalImage.style.display === 'none') { + lb.style.setProperty('background-image', 'url(' + source.src + ')'); + } + lb.style.display = "flex"; + lb.focus(); -let slide = 0; -let gallery = []; -let fullImg_src; -//let control = ["pan","undo","like","tile","page","fullscreen","autofit","zoom-in","zoom-out","clear","close","download","prev","next"]; -let control = [ - "like", - "tile", - "page", - "fullscreen", - "autofit", - "zoom-in", - "zoom-out", - "clear", - "close", - "download", - "prev", - "next", -]; - -let img_browser; -let img_file_name; - -let spl_pane; -let spl_zoom_out; -let spl_zoom_in; -let spotlight_gallery; - -function tile_zoom_update(val) { - let current_tile_state_size = gallery[slide].tile_size; - current_tile_state_size += val * 5; - current_tile_state_size = Math.max(5, Math.min(100, current_tile_state_size)); - spl_pane.style.setProperty("background-size", current_tile_state_size + "%"); - gallery[slide].tile_size = current_tile_state_size; + const tabTxt2Img = gradioApp().getElementById("tab_txt2img"); + const tabImg2Img = gradioApp().getElementById("tab_img2img"); + // show the save button in modal only on txt2img or img2img tabs + if (tabTxt2Img.style.display != "none" || tabImg2Img.style.display != "none") { + gradioApp().getElementById("modal_save").style.display = "inline"; + } else { + gradioApp().getElementById("modal_save").style.display = "none"; + } + event.stopPropagation(); } -function tile_wheel(event) { - let delta = event["deltaY"]; - delta = (delta < 0 ? 1 : delta ? -1 : 0) * 0.5; - tile_zoom_update(delta); -} -function tile_zoom_in(event) { - tile_zoom_update(1); -} -function tile_zoom_out(event) { - tile_zoom_update(-1); +function negmod(n, m) { + return ((n % m) + m) % m; } -function removeTile() { - spl_pane.removeEventListener("wheel", tile_wheel); - spl_zoom_out.removeEventListener("click", tile_zoom_out); - spl_zoom_in.removeEventListener("click", tile_zoom_in); +function updateOnBackgroundChange() { + const modalImage = gradioApp().getElementById("modalImage"); + if (modalImage && modalImage.offsetParent) { + let currentButton = selected_gallery_button(); - spl_pane.classList.remove("hide"); - spl_pane.style.setProperty("background-image", "none"); - spotlight_gallery.zoom(0.0); + if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) { + modalImage.src = currentButton.children[0].src; + if (modalImage.style.display === 'none') { + const modal = gradioApp().getElementById("lightboxModal"); + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + } + } } -function addTile(spl_img) { - spl_pane.addEventListener("wheel", tile_wheel); - spl_zoom_out.addEventListener("click", tile_zoom_out); - spl_zoom_in.addEventListener("click", tile_zoom_in); +function modalImageSwitch(offset) { + var galleryButtons = all_gallery_buttons(); - const current_tile_state_size = gallery[slide].tile_size; - spl_pane.classList.add("hide"); - spl_pane.style.setProperty("background-position", "center"); - spl_pane.style.setProperty("background-size", current_tile_state_size + "%"); - if (spl_img) { - spl_pane.style.setProperty("background-image", `url(${spl_img.src})`); - } + if (galleryButtons.length > 1) { + var currentButton = selected_gallery_button(); + + var result = -1; + galleryButtons.forEach(function(v, i) { + if (v == currentButton) { + result = i; + } + }); + + if (result != -1) { + var nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]; + nextButton.click(); + const modalImage = gradioApp().getElementById("modalImage"); + const modal = gradioApp().getElementById("lightboxModal"); + modalImage.src = nextButton.children[0].src; + if (modalImage.style.display === 'none') { + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + setTimeout(function() { + modal.focus(); + }, 10); + } + } } -function tile_handler(event) { - const current_tile_state = !gallery[slide].tile; - gallery[slide].tile = current_tile_state; - - this.classList.toggle("on"); - - if (current_tile_state) { - const spl_img = gradioApp().querySelector("#spotlight-gal .spl-pane img"); - addTile(spl_img); - } else { - removeTile(); - } -} -function like_handler(event) { - const current_like_state = !gallery[slide].like; - gallery[slide].like = current_like_state; - this.classList.toggle("on"); - - if (current_like_state) { - // add to favorites ... - //img_file_name.value = gallery[slide].src; - //console.log(gallery[slide].src); - } else { - // remove from favorites ... - } +function saveImage() { + const tabTxt2Img = gradioApp().getElementById("tab_txt2img"); + const tabImg2Img = gradioApp().getElementById("tab_img2img"); + const saveTxt2Img = "save_txt2img"; + const saveImg2Img = "save_img2img"; + if (tabTxt2Img.style.display != "none") { + gradioApp().getElementById(saveTxt2Img).click(); + } else if (tabImg2Img.style.display != "none") { + gradioApp().getElementById(saveImg2Img).click(); + } else { + console.error("missing implementation for saving modal of this type"); + } } -function createGallerySpotlight() { - //console.log("clicked"); - slide = 0; - gallery = []; - - gradioApp() - .querySelectorAll("#" + selectedTabItemId + " .thumbnails img") - .forEach(function (elem, i) { - elem.setAttribute("gal-id", i); - //if(fullImg_src == elem.src) slide = parseInt(i+1); - if (elem.parentElement.className.indexOf("selected") != -1) - slide = parseInt(i + 1); - //console.log(slide); - gallery[i] = { - src: elem.src, - title: "Seed:" + elem.src, - //description: "This is a description.", - like: false, - tile: false, - tile_size: 50, - }; - }); - - const options = { - class: "sd-gallery", - index: slide, - //control: ["like","page","theme","fullscreen","autofit","zoom-in","zoom-out","close","download","play","prev","next"], - control: control, - //animation: animation, - onshow: function (index) {}, - onchange: function (index, options) { - slide = index - 1; - tile.classList.toggle("on", gallery[slide].tile); - //if(img_browser){ - like.classList.toggle("on", gallery[slide].like); - - //} - - spl_pane = gradioApp().querySelector( - "#spotlight-gal .spl-pane:nth-child(" + index + ")" - ); - spl_zoom_out = gradioApp().querySelector("#spotlight-gal .spl-zoom-out"); - spl_zoom_in = gradioApp().querySelector("#spotlight-gal .spl-zoom-in"); - - const current_tile_state = gallery[slide].tile; - if (current_tile_state) { - addTile(); - } else { - removeTile(); - } - }, - onclose: function (index) { - gradioApp() - .querySelector( - "#" + - selectedTabItemId + - " .thumbnails .thumbnail-item:nth-child(" + - (slide + 1) + - ")" - ) - .click(); - }, - }; - - //assign(options, modifier); - - spotlight_gallery.show(gallery, options); - spotlight_gallery.panzoom(true); +function modalSaveImage(event) { + saveImage(); + event.stopPropagation(); } -function fullImg_click_handler(e) { - e.stopPropagation(); - e.preventDefault(); - createGallerySpotlight(); +function modalNextImage(event) { + modalImageSwitch(1); + event.stopPropagation(); } -let intervalUiUpdateIViewer; -function onUiHeaderTabUpdate() { - if (intervalUiUpdateIViewer != null) clearInterval(intervalUiUpdateIViewer); - intervalUiUpdateIViewer = setInterval(onUiUpdateIViewer, 500); +function modalPrevImage(event) { + modalImageSwitch(-1); + event.stopPropagation(); } -let fullImg_preview; -function onUiUpdateIViewer() { - clearInterval(intervalUiUpdateIViewer); - //update_performant_inputs(selectedTabItemId); - - //fullImg_preview = gradioApp().querySelector('#'+selectedTabItemId+' [id$="2img_results"] .modify-upload + img.w-full.object-contain'); - fullImg_preview = gradioApp().querySelector( - "#" + selectedTabItemId + " .preview > img" - ); - if (opts.js_modal_lightbox && fullImg_preview) { - fullImg_src = fullImg_preview.src; - fullImg_preview.removeEventListener("click", fullImg_click_handler); - fullImg_preview.addEventListener("click", fullImg_click_handler, true); //bubbling phase - - /* - // this is an idea to integrate image browser extension seamlesly, - // without the need to change to the image browser tab extension users will be able to review images after generation - // and add them to favorites or delete the ones that don't like on the spot - const img_browser = gradioApp().querySelector('[id$="2img_images_history"]'); - const tbname = selectedTabItemId.split("_")[1]; - if(img_browser && tbname ==("txt2img" || "img2img")){ - const images_history = gradioApp().querySelector('[id$="'+tbname+'_images_history"]'); - const history_button_panel = images_history.querySelector('[id$="'+tbname+'_images_history_button_panel"]'); - const labels = images_history.querySelectorAll('label.block span'); - for(let i=0;i -1; + + // For Firefox, listening on click first switched to next image then shows the lightbox. + // If you know how to fix this without switching to mousedown event, please. + // For other browsers the event is click to make it possiblr to drag picture. + var event = isFirefox ? 'mousedown' : 'click'; + + e.addEventListener(event, function(evt) { + if (evt.button == 1) { + open(evt.target.src); + evt.preventDefault(); + return; + } + if (!opts.js_modal_lightbox || evt.button != 0) return; + + modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed); + evt.preventDefault(); + showModal(evt); + }, true); + +} + +function modalZoomSet(modalImage, enable) { + if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable); +} + +function modalZoomToggle(event) { + var modalImage = gradioApp().getElementById("modalImage"); + modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen')); + event.stopPropagation(); +} + +function modalTileImageToggle(event) { + const modalImage = gradioApp().getElementById("modalImage"); + const modal = gradioApp().getElementById("lightboxModal"); + const isTiling = modalImage.style.display === 'none'; + if (isTiling) { + modalImage.style.display = 'block'; + modal.style.setProperty('background-image', 'none'); + } else { + modalImage.style.display = 'none'; + modal.style.setProperty('background-image', `url(${modalImage.src})`); + } + + event.stopPropagation(); +} + +onAfterUiUpdate(function() { + var fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img'); + if (fullImg_preview != null) { + fullImg_preview.forEach(setupImageForLightbox); + } + updateOnBackgroundChange(); }); -onUiLoaded(function () { - spotlight_gallery = new Spotlight(); - spotlight_gallery.init( - gradioApp().querySelector(".gradio-container"), - "-gal" - ); - tile = spotlight_gallery.addControl("tile", tile_handler); - like = spotlight_gallery.addControl("like", like_handler); -}); +document.addEventListener("DOMContentLoaded", function() { + //const modalFragment = document.createDocumentFragment(); + const modal = document.createElement('div'); + modal.onclick = closeModal; + modal.id = "lightboxModal"; + modal.tabIndex = 0; + modal.addEventListener('keydown', modalKeyHandler, true); -document.addEventListener("DOMContentLoaded", function () {}); + const modalControls = document.createElement('div'); + modalControls.className = 'modalControls gradio-container'; + modal.append(modalControls); + + const modalZoom = document.createElement('span'); + modalZoom.className = 'modalZoom cursor'; + modalZoom.innerHTML = '⤡'; + modalZoom.addEventListener('click', modalZoomToggle, true); + modalZoom.title = "Toggle zoomed view"; + modalControls.appendChild(modalZoom); + + const modalTileImage = document.createElement('span'); + modalTileImage.className = 'modalTileImage cursor'; + modalTileImage.innerHTML = '⊞'; + modalTileImage.addEventListener('click', modalTileImageToggle, true); + modalTileImage.title = "Preview tiling"; + modalControls.appendChild(modalTileImage); + + const modalSave = document.createElement("span"); + modalSave.className = "modalSave cursor"; + modalSave.id = "modal_save"; + modalSave.innerHTML = "🖫"; + modalSave.addEventListener("click", modalSaveImage, true); + modalSave.title = "Save Image(s)"; + modalControls.appendChild(modalSave); + + const modalClose = document.createElement('span'); + modalClose.className = 'modalClose cursor'; + modalClose.innerHTML = '×'; + modalClose.onclick = closeModal; + modalClose.title = "Close image viewer"; + modalControls.appendChild(modalClose); + + const modalImage = document.createElement('img'); + modalImage.id = 'modalImage'; + modalImage.onclick = closeModal; + modalImage.tabIndex = 0; + modalImage.addEventListener('keydown', modalKeyHandler, true); + modal.appendChild(modalImage); + + const modalPrev = document.createElement('a'); + modalPrev.className = 'modalPrev'; + modalPrev.innerHTML = '❮'; + modalPrev.tabIndex = 0; + modalPrev.addEventListener('click', modalPrevImage, true); + modalPrev.addEventListener('keydown', modalKeyHandler, true); + modal.appendChild(modalPrev); + + const modalNext = document.createElement('a'); + modalNext.className = 'modalNext'; + modalNext.innerHTML = '❯'; + modalNext.tabIndex = 0; + modalNext.addEventListener('click', modalNextImage, true); + modalNext.addEventListener('keydown', modalKeyHandler, true); + + modal.appendChild(modalNext); + + try { + gradioApp().appendChild(modal); + } catch (e) { + gradioApp().body.appendChild(modal); + } + + document.body.appendChild(modal); + +}); diff --git a/javascript/imageviewerGamepad.js b/javascript/imageviewerGamepad.js index 8f824148..a22c7e6e 100644 --- a/javascript/imageviewerGamepad.js +++ b/javascript/imageviewerGamepad.js @@ -60,4 +60,4 @@ function sleepUntil(f, timeout) { } }, 20); }); -} \ No newline at end of file +} diff --git a/javascript/inputAccordion.js b/javascript/inputAccordion.js new file mode 100644 index 00000000..f2839852 --- /dev/null +++ b/javascript/inputAccordion.js @@ -0,0 +1,37 @@ +var observerAccordionOpen = new MutationObserver(function(mutations) { + mutations.forEach(function(mutationRecord) { + var elem = mutationRecord.target; + var open = elem.classList.contains('open'); + + var accordion = elem.parentNode; + accordion.classList.toggle('input-accordion-open', open); + + var checkbox = gradioApp().querySelector('#' + accordion.id + "-checkbox input"); + checkbox.checked = open; + updateInput(checkbox); + + var extra = gradioApp().querySelector('#' + accordion.id + "-extra"); + if (extra) { + extra.style.display = open ? "" : "none"; + } + }); +}); + +function inputAccordionChecked(id, checked) { + var label = gradioApp().querySelector('#' + id + " .label-wrap"); + if (label.classList.contains('open') != checked) { + label.click(); + } +} + +onUiLoaded(function() { + for (var accordion of gradioApp().querySelectorAll('.input-accordion')) { + var labelWrap = accordion.querySelector('.label-wrap'); + observerAccordionOpen.observe(labelWrap, {attributes: true, attributeFilter: ['class']}); + + var extra = gradioApp().querySelector('#' + accordion.id + "-extra"); + if (extra) { + labelWrap.insertBefore(extra, labelWrap.lastElementChild); + } + } +}); diff --git a/javascript/localStorage.js b/javascript/localStorage.js new file mode 100644 index 00000000..dc1a36c3 --- /dev/null +++ b/javascript/localStorage.js @@ -0,0 +1,26 @@ + +function localSet(k, v) { + try { + localStorage.setItem(k, v); + } catch (e) { + console.warn(`Failed to save ${k} to localStorage: ${e}`); + } +} + +function localGet(k, def) { + try { + return localStorage.getItem(k); + } catch (e) { + console.warn(`Failed to load ${k} from localStorage: ${e}`); + } + + return def; +} + +function localRemove(k) { + try { + return localStorage.removeItem(k); + } catch (e) { + console.warn(`Failed to remove ${k} from localStorage: ${e}`); + } +} diff --git a/javascript/localization.js b/javascript/localization.js index f9028164..8f00c186 100644 --- a/javascript/localization.js +++ b/javascript/localization.js @@ -1,3 +1,4 @@ + // localization = {} -- the dict with translations is created by the backend var ignore_ids_for_localization = { @@ -10,11 +11,11 @@ var ignore_ids_for_localization = { train_hypernetwork: 'OPTION', txt2img_styles: 'OPTION', img2img_styles: 'OPTION', - setting_random_artist_categories: 'SPAN', - setting_face_restoration_model: 'SPAN', - setting_realesrgan_enabled_models: 'SPAN', - extras_upscaler_1: 'SPAN', - extras_upscaler_2: 'SPAN', + setting_random_artist_categories: 'OPTION', + setting_face_restoration_model: 'OPTION', + setting_realesrgan_enabled_models: 'OPTION', + extras_upscaler_1: 'OPTION', + extras_upscaler_2: 'OPTION', }; var re_num = /^[.\d]+$/; @@ -106,12 +107,41 @@ function processNode(node) { }); } +function localizeWholePage() { + processNode(gradioApp()); + + function elem(comp) { + var elem_id = comp.props.elem_id ? comp.props.elem_id : "component-" + comp.id; + return gradioApp().getElementById(elem_id); + } + + for (var comp of window.gradio_config.components) { + if (comp.props.webui_tooltip) { + let e = elem(comp); + + let tl = e ? getTranslation(e.title) : undefined; + if (tl !== undefined) { + e.title = tl; + } + } + if (comp.props.placeholder) { + let e = elem(comp); + let textbox = e ? e.querySelector('[placeholder]') : null; + + let tl = textbox ? getTranslation(textbox.placeholder) : undefined; + if (tl !== undefined) { + textbox.placeholder = tl; + } + } + } +} + function dumpTranslations() { if (!hasLocalization()) { // If we don't have any localization, // we will not have traversed the app to find // original_lines, so do that now. - processNode(gradioApp()); + localizeWholePage(); } var dumped = {}; if (localization.rtl) { @@ -153,7 +183,7 @@ document.addEventListener("DOMContentLoaded", function() { }); }); - processNode(gradioApp()); + localizeWholePage(); if (localization.rtl) { // if the language is from right to left, (new MutationObserver((mutations, observer) => { // wait for the style to load diff --git a/javascript/notification.js b/javascript/notification.js index 82577b2d..6d799561 100644 --- a/javascript/notification.js +++ b/javascript/notification.js @@ -1,3 +1,5 @@ +// Monitors the gallery and sends a browser notification when the leading image is new. + let lastHeadImg = null; let notificationButton = null; @@ -13,7 +15,7 @@ onAfterUiUpdate(function() { } } - const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"][style*="display: block"] div[id$="_results"] .thumbnail-item > img'); + const galleryPreviews = gradioApp().querySelectorAll('div[id^="tab_"] div[id$="_results"] .thumbnail-item > img'); if (galleryPreviews == null) return; @@ -44,4 +46,4 @@ onAfterUiUpdate(function() { parent.focus(); this.close(); }; -}); \ No newline at end of file +}); diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 8606030b..77761495 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -36,13 +36,13 @@ function pad2(x) { } function formatTime(secs) { - if (secs > 3600) { - return pad2(Math.floor(secs / 60 / 60)) + ":" + pad2(Math.floor(secs / 60) % 60) + ":" + pad2(Math.floor(secs) % 60); - } else if (secs > 60) { - return pad2(Math.floor(secs / 60)) + ":" + pad2(Math.floor(secs) % 60); - } else { - return Math.floor(secs) + "s"; - } + if (secs > 3600) { + return pad2(Math.floor(secs / 60 / 60)) + ":" + pad2(Math.floor(secs / 60) % 60) + ":" + pad2(Math.floor(secs) % 60); + } else if (secs > 60) { + return pad2(Math.floor(secs / 60)) + ":" + pad2(Math.floor(secs) % 60); + } else { + return Math.floor(secs) + "s"; + } } function setTitle(progress) { @@ -57,6 +57,7 @@ function setTitle(progress) { } } + function randomId() { return "task(" + Math.random().toString(36).slice(2, 7) + Math.random().toString(36).slice(2, 7) + Math.random().toString(36).slice(2, 7) + ")"; } @@ -64,145 +65,122 @@ function randomId() { // starts sending progress requests to "/internal/progress" uri, creating progressbar above progressbarContainer element and // preview inside gallery element. Cleans up all created stuff when the task is over and calls atEnd. // calls onProgress every time there is a progress update -function requestProgress( - id_task, - progressbarContainer, - gallery, - atEnd, - onProgress, - inactivityTimeout = 40 -) { - var dateStart = new Date(); - var wasEverActive = false; - var parentProgressbar = progressbarContainer.parentNode; - var parentGallery = gallery ? gallery.parentNode : null; +function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgress, inactivityTimeout = 40) { + var dateStart = new Date(); + var wasEverActive = false; + var parentProgressbar = progressbarContainer.parentNode; - var divProgress = document.createElement("div"); - divProgress.className = "progressDiv"; + var divProgress = document.createElement('div'); + divProgress.className = 'progressDiv'; + divProgress.style.display = opts.show_progressbar ? "block" : "none"; + var divInner = document.createElement('div'); + divInner.className = 'progress'; - divProgress.style.display = opts.show_progressbar ? "block" : "none"; - var divInner = document.createElement("div"); - divInner.className = "progress"; + divProgress.appendChild(divInner); + parentProgressbar.insertBefore(divProgress, progressbarContainer); - divProgress.appendChild(divInner); - parentProgressbar.insertBefore(divProgress, progressbarContainer); + var livePreview = null; - if (parentGallery) { - var livePreview = gradioApp().querySelector(".livePreview"); - if (!livePreview) { - livePreview = document.createElement("div"); - livePreview.classList.add("livePreview", "init"); - parentGallery.insertBefore(livePreview, gallery); - } - livePreview.classList.remove("dropPreview"); - } + var removeProgressBar = function() { + if (!divProgress) return; - var removeProgressBar = function () { - setTitle(""); - if (divProgress) { - parentProgressbar.removeChild(divProgress); - } + setTitle(""); + parentProgressbar.removeChild(divProgress); + if (gallery && livePreview) gallery.removeChild(livePreview); + atEnd(); - if (progressbarContainer.id == "txt2img_gallery_container") { - showSubmitButtons("txt2img", true); - } else if (progressbarContainer.id == "img2img_gallery_container") { - showSubmitButtons("img2img", true); - } - if (livePreview) { - if (parentGallery) parentGallery.removeChild(livePreview); - } - gradioApp() - .querySelectorAll("#tabs + div, #tabs + div > *:not(ul)") - .forEach(function (elem) { - elem.style.setProperty("display", "block", "important"); - }); - atEnd(); - }; + divProgress = null; + }; - var fun = function (id_task, id_live_preview) { - request( - "./internal/progress", - { id_task: id_task, id_live_preview: id_live_preview }, - function (res) { - if (res.completed) { - removeProgressBar(); - return; - } - - var rect = progressbarContainer.getBoundingClientRect(); - - if (rect.width) { - divProgress.style.width = rect.width + "px"; - } - - let progressText = ""; - - divInner.style.width = (res.progress || 0) * 100.0 + "%"; - divInner.style.background = res.progress ? "" : "transparent"; - - if (res.progress > 0) { - progressText = ((res.progress || 0) * 100.0).toFixed(0) + "%"; - } - - if (res.eta) { - progressText += " ETA: " + formatTime(res.eta); - } - - setTitle(progressText); - - if (res.textinfo && res.textinfo.indexOf("\n") == -1) { - progressText = res.textinfo + " " + progressText; - } - - divInner.textContent = progressText; - - var elapsedFromStart = (new Date() - dateStart) / 1000; - - if (res.active) wasEverActive = true; - - if (!res.active && wasEverActive) { - removeProgressBar(); - return; - } - - if ( - elapsedFromStart > inactivityTimeout && - !res.queued && - !res.active - ) { - removeProgressBar(); - return; - } - - if (res.live_preview && gallery) { - - livePreview.classList.remove("init"); - - var img = new Image(); - img.onload = function () { - img.width = img.naturalWidth; - img.height = img.naturalHeight; - livePreview.appendChild(img); - if (livePreview.childElementCount > 2) { - livePreview.removeChild(livePreview.firstElementChild); + var funProgress = function(id_task) { + request("./internal/progress", {id_task: id_task, live_preview: false}, function(res) { + if (res.completed) { + removeProgressBar(); + return; } - }; - img.src = res.live_preview; - } - if (onProgress) { - onProgress(res); - } + let progressText = ""; - setTimeout(() => { - fun(id_task, res.id_live_preview); - }, opts.live_preview_refresh_period || 500); - }, - function () { - removeProgressBar(); - } - ); - }; + divInner.style.width = ((res.progress || 0) * 100.0) + '%'; + divInner.style.background = res.progress ? "" : "transparent"; + + if (res.progress > 0) { + progressText = ((res.progress || 0) * 100.0).toFixed(0) + '%'; + } + + if (res.eta) { + progressText += " ETA: " + formatTime(res.eta); + } + + setTitle(progressText); + + if (res.textinfo && res.textinfo.indexOf("\n") == -1) { + progressText = res.textinfo + " " + progressText; + } + + divInner.textContent = progressText; + + var elapsedFromStart = (new Date() - dateStart) / 1000; + + if (res.active) wasEverActive = true; + + if (!res.active && wasEverActive) { + removeProgressBar(); + return; + } + + if (elapsedFromStart > inactivityTimeout && !res.queued && !res.active) { + removeProgressBar(); + return; + } + + if (onProgress) { + onProgress(res); + } + + setTimeout(() => { + funProgress(id_task, res.id_live_preview); + }, opts.live_preview_refresh_period || 500); + }, function() { + removeProgressBar(); + }); + }; + + var funLivePreview = function(id_task, id_live_preview) { + request("./internal/progress", {id_task: id_task, id_live_preview: id_live_preview}, function(res) { + if (!divProgress) { + return; + } + + if (res.live_preview && gallery) { + var img = new Image(); + img.onload = function() { + if (!livePreview) { + livePreview = document.createElement('div'); + livePreview.className = 'livePreview'; + gallery.insertBefore(livePreview, gallery.firstElementChild); + } + + livePreview.appendChild(img); + if (livePreview.childElementCount > 2) { + livePreview.removeChild(livePreview.firstElementChild); + } + }; + img.src = res.live_preview; + } + + setTimeout(() => { + funLivePreview(id_task, res.id_live_preview); + }, opts.live_preview_refresh_period || 500); + }, function() { + removeProgressBar(); + }); + }; + + funProgress(id_task, 0); + + if (gallery) { + funLivePreview(id_task, 0); + } - fun(id_task, 0); } diff --git a/javascript/resizeHandle.js b/javascript/resizeHandle.js new file mode 100644 index 00000000..8c5c5169 --- /dev/null +++ b/javascript/resizeHandle.js @@ -0,0 +1,141 @@ +(function() { + const GRADIO_MIN_WIDTH = 320; + const GRID_TEMPLATE_COLUMNS = '1fr 16px 1fr'; + const PAD = 16; + const DEBOUNCE_TIME = 100; + + const R = { + tracking: false, + parent: null, + parentWidth: null, + leftCol: null, + leftColStartWidth: null, + screenX: null, + }; + + let resizeTimer; + let parents = []; + + function setLeftColGridTemplate(el, width) { + el.style.gridTemplateColumns = `${width}px 16px 1fr`; + } + + function displayResizeHandle(parent) { + if (window.innerWidth < GRADIO_MIN_WIDTH * 2 + PAD * 4) { + parent.style.display = 'flex'; + if (R.handle != null) { + R.handle.style.opacity = '0'; + } + return false; + } else { + parent.style.display = 'grid'; + if (R.handle != null) { + R.handle.style.opacity = '100'; + } + return true; + } + } + + function afterResize(parent) { + if (displayResizeHandle(parent) && parent.style.gridTemplateColumns != GRID_TEMPLATE_COLUMNS) { + const oldParentWidth = R.parentWidth; + const newParentWidth = parent.offsetWidth; + const widthL = parseInt(parent.style.gridTemplateColumns.split(' ')[0]); + + const ratio = newParentWidth / oldParentWidth; + + const newWidthL = Math.max(Math.floor(ratio * widthL), GRADIO_MIN_WIDTH); + setLeftColGridTemplate(parent, newWidthL); + + R.parentWidth = newParentWidth; + } + } + + function setup(parent) { + const leftCol = parent.firstElementChild; + const rightCol = parent.lastElementChild; + + parents.push(parent); + + parent.style.display = 'grid'; + parent.style.gap = '0'; + parent.style.gridTemplateColumns = GRID_TEMPLATE_COLUMNS; + + const resizeHandle = document.createElement('div'); + resizeHandle.classList.add('resize-handle'); + parent.insertBefore(resizeHandle, rightCol); + + resizeHandle.addEventListener('mousedown', (evt) => { + if (evt.button !== 0) return; + + evt.preventDefault(); + evt.stopPropagation(); + + document.body.classList.add('resizing'); + + R.tracking = true; + R.parent = parent; + R.parentWidth = parent.offsetWidth; + R.handle = resizeHandle; + R.leftCol = leftCol; + R.leftColStartWidth = leftCol.offsetWidth; + R.screenX = evt.screenX; + }); + + resizeHandle.addEventListener('dblclick', (evt) => { + evt.preventDefault(); + evt.stopPropagation(); + + parent.style.gridTemplateColumns = GRID_TEMPLATE_COLUMNS; + }); + + afterResize(parent); + } + + window.addEventListener('mousemove', (evt) => { + if (evt.button !== 0) return; + + if (R.tracking) { + evt.preventDefault(); + evt.stopPropagation(); + + const delta = R.screenX - evt.screenX; + const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - GRADIO_MIN_WIDTH - PAD), GRADIO_MIN_WIDTH); + setLeftColGridTemplate(R.parent, leftColWidth); + } + }); + + window.addEventListener('mouseup', (evt) => { + if (evt.button !== 0) return; + + if (R.tracking) { + evt.preventDefault(); + evt.stopPropagation(); + + R.tracking = false; + + document.body.classList.remove('resizing'); + } + }); + + + window.addEventListener('resize', () => { + clearTimeout(resizeTimer); + + resizeTimer = setTimeout(function() { + for (const parent of parents) { + afterResize(parent); + } + }, DEBOUNCE_TIME); + }); + + setupResizeHandle = setup; +})(); + +onUiLoaded(function() { + for (var elem of gradioApp().querySelectorAll('.resize-handle-row')) { + if (!elem.querySelector('.resize-handle')) { + setupResizeHandle(elem); + } + } +}); diff --git a/javascript/spotlight.js b/javascript/spotlight.js deleted file mode 100644 index 88ae8ed2..00000000 --- a/javascript/spotlight.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Spotlight.js v0.7.8 - * Copyright 2019-2021 Nextapps GmbH - * Author: Thomas Wilkerling - * Licence: Apache-2.0 - * https://github.com/nextapps-de/spotlight - */ - /* - this library was rewritten by anapnoe to work with https://github.com/anapnoe/stable-diffusion-webui-ux - it supports multi-instancing, enable-disable panzoom functionallity and input type tools - */ - -!function(e){"use strict";let t=function(t,i={}){this.controls=["info","theme","download","play","page","close","autofit","zoom-in","zoom-out","prev","next","fullscreen"],this.controls_default={page:1,close:1,autofit:1,"zoom-in":1,"zoom-out":1,prev:1,next:1,fullscreen:1},this.keycodes={BACKSPACE:8,ESCAPE:27,SPACEBAR:32,LEFT:37,RIGHT:39,UP:38,NUMBLOCK_PLUS:107,PLUS:187,DOWN:40,NUMBLOCK_MINUS:109,MINUS:189,INFO:73};let s=this;Object.assign||(Object.assign=function(e,t){let i=Object.keys(t);for(let s=0,o;s{s.toggleClass(e,t,!0)},this.removeClass=(e,t)=>{s.toggleClass(e,t)},this.toggleClass=(e,t,i)=>{e.classList[i?"add":"remove"](t)},this.hasClass=(e,t)=>e.classList.contains(t),this.setStyle=(e,t,i)=>{i=""+i,e["_s_"+t]!==i&&(e.style.setProperty(t,i),e["_s_"+t]=i)};let o=0;this.prepareStyle=(e,t)=>{t&&(s.setStyle(e,"transition","none"),t()),o||(o=e.clientTop&&0),t&&s.setStyle(e,"transition","")},this.setText=(e,t)=>{e.firstChild.nodeValue=t},this.getByClass=(e,t)=>(t||document).getElementsByClassName(e),this.getByTag=(e,t)=>(t||document).getElementsByTagName(e),this.addListener=(e,t,i,o)=>{s.toggleListener(!0,e,t,i,o)},this.removeListener=(e,t,i,o)=>{s.toggleListener(!1,e,t,i,o)},this.toggleListener=(e,t,i,s,o)=>{t[(e?"add":"remove")+"EventListener"](i,s,!o&&!1!==o||o)},this.cancelEvent=(e,t)=>{e.stopPropagation(),t&&e.preventDefault()},this.downloadImage=(e,t)=>{let i=s.createElement("a"),o=t.src;i.href=o,i.download=o.substring(o.lastIndexOf("/")+1),s.body.appendChild(i),i.click(),s.body.removeChild(i)},this.createElement=e=>document.createElement(e),this.toggleDisplay=(e,t)=>{s.setStyle(e,"display",t?"":"none")},this.toggleVisibility=(e,t)=>{s.setStyle(e,"visibility",t?"":"hidden")},this.toggleAnimation=(e,t)=>{s.setStyle(e,"transition",t?"":"none")},this.widget=this.createElement("div"),this.widget.innerHTML="
",this.video_support={},this.tpl_video=this.createElement("video"),this.parse_src=(e,t,i,o)=>{let n,l;if("node"!==o){let a=Object.keys(i);for(let r=0,d;r3&&0===d.indexOf("src")){if("video"===o){let p=s.video_support[d];if(p){if(p>0){n=i[d];break}}else if(s.tpl_video.canPlayType("video/"+d.substring(3).replace("-","").toLowerCase())){s.video_support[d]=1,n=i[d];break}else s.video_support[d]=-1}else{let c=parseInt(d.substring(4),10);if(c){let h=Math.abs(t-c);(!l||h{s.body||(s.id="spotlight"+t,s.widget.id="spotlight"+t,s.doc=document.body,s.body=e,s.slider=s.getOneByClass("scene"),s.header=s.getOneByClass("header"),s.footer=s.getOneByClass("footer"),s.title=s.getOneByClass("title"),s.description=s.getOneByClass("description"),s.button=s.getOneByClass("button"),s.page_prev=s.getOneByClass("prev"),s.page_next=s.getOneByClass("next"),s.page=s.getOneByClass("page"),s.progress=s.getOneByClass("progress"),s.spinner=s.getOneByClass("spinner"),s.panes=[s.getOneByClass("pane")],s.addControl("close",s.close),s.doc[s.prefix_request="requestFullscreen"]||s.doc[s.prefix_request="msRequestFullscreen"]||s.doc[s.prefix_request="webkitRequestFullscreen"]||s.doc[s.prefix_request="mozRequestFullscreen"]||(s.prefix_request=""),s.prefix_request?(s.prefix_exit=s.prefix_request.replace("request","exit").replace("mozRequest","mozCancel").replace("Request","Exit"),s.maximize=s.addControl("fullscreen",s.fullscreen)):s.controls.pop(),s.addControl("info",s.info),s.addControl("autofit",s.autofit),s.addControl("zoom-in",s.zoom_in),s.addControl("zoom-out",s.zoom_out),s.addControl("theme",s.theme),s.player=s.addControl("play",s.play),s.addControl("download",s.download),s.addListener(s.page_prev,"click",s.prev),s.addListener(s.page_next,"click",s.next),s.track=s.getOneByClass("track"),s.addListener(s.track,"mousedown",s.start),s.addListener(s.track,"mousemove",s.move),s.addListener(s.track,"mouseleave",s.end),s.addListener(s.track,"mouseup",s.end),s.addListener(s.track,"touchstart",s.start,{passive:!1}),s.addListener(s.track,"touchmove",s.move,{passive:!0}),s.addListener(s.track,"touchend",s.end),s.addListener(s.button,"click",function(){s.options_click?s.options_click(s.current_slide,s.options):s.options_href&&(location.href=s.options_href)}))},this.getOneByClass=e=>this.controls_dom[e]=this.getByClass("spl-"+e,this.widget)[0],this.addControl=(e,t,i="")=>{let o=s.createElement("div");return o.className="spl-"+e,o.innerHTML=i,s.addListener(o,"click",t),s.header.appendChild(o),s.controls_dom[e]=o},this.removeControl=e=>{let t=s.controls_dom[e];t&&(s.header.removeChild(t),s.controls_dom[e]=null)},this.dispatch=e=>{let t=e.target.closest(".spotlight");if(t){s.cancelEvent(e,!0);let i=t.closest(".spotlight-group");s.anchors=s.getByClass("spotlight",i);for(let o=0;o{s.anchors=e,t&&(s.options_group=t,s.options_onshow=t.onshow,s.options_onchange=t.onchange,s.options_onclose=t.onclose,i=i||t.index),s.init_gallery(i)},this.panzoom=e=>{s.toggleListener(e,s.track,"wheel",s.wheel_listener,{passive:!1}),s.toggleListener(e,s.track,"mousedown",s.start),s.toggleListener(e,s.track,"mousemove",s.move),s.toggleListener(e,s.track,"mouseleave",s.end),s.toggleListener(e,s.track,"mouseup",s.end),s.toggleListener(e,s.track,"touchstart",s.start,{passive:!1}),s.toggleListener(e,s.track,"touchmove",s.move,{passive:!0}),s.toggleListener(e,s.track,"touchend",s.end)},this.init_gallery=e=>{if(s.slide_count=s.anchors.length,s.slide_count){s.body||s.init(),s.options_onshow&&s.options_onshow(e);let t=s.panes[0],i=t.parentElement;for(let o=s.panes.length;o{let s=i[e];return void 0!==s?"false"!=(s=""+s)&&(s||t):t},this.apply_options=e=>{s.options={},s.options_group&&Object.assign(s.options,s.options_group),Object.assign(s.options,e.dataset||e),s.options_media=s.options.media,s.options_click=s.options.onclick,s.options_theme=s.options.theme,s.options_class=s.options.class,s.options_autohide=s.parse_option("autohide",!1),s.options_infinite=s.parse_option("infinite"),s.options_progress=s.parse_option("progress",!0),s.options_autoslide=s.parse_option("autoslide"),s.options_preload=s.parse_option("preload",!0),s.options_href=s.options.buttonHref,s.delay=s.options_autoslide&&parseFloat(s.options_autoslide)||7,s.toggle_theme||s.options_theme&&s.theme(s.options_theme),s.options_class&&s.addClass(s.widget,s.options_class),s.options_class&&s.prepareStyle(s.widget);let t=s.options.control;if(t){let i="string"==typeof t?t.split(","):t;for(let o=0;o{e?s.prepareStyle(s.media,s.prepare_animation):(s.toggleAnimation(s.slider,s.animation_slide),s.setStyle(s.media,"opacity",s.animation_fade?0:1),s.update_scroll(s.animation_scale&&.8),s.animation_custom&&s.addClass(s.media,s.animation_custom))},this.init_slide=e=>{if(s.panel=s.panes[e-1],s.media=s.panel.firstChild,s.current_slide=e,s.media)s.disable_autoresizer(),s.options_fit&&s.addClass(s.media,s.options_fit),s.prepare_animation(!0),s.animation_custom&&s.removeClass(s.media,s.animation_custom),s.animation_fade&&s.setStyle(s.media,"opacity",1),s.animation_scale&&s.setStyle(s.media,"transform",""),s.setStyle(s.media,"visibility","visible"),s.gallery_next&&(s.media_next.src=s.gallery_next),s.options_autoslide&&s.animate_bar(s.playing);else{let t=s.gallery.media;if(s.parse_option("spinner",!0),"node"===t){s.media=s.gallery.src,"string"==typeof s.media&&(s.media=gradioApp().querySelector(s.media)),s.media&&(s.media._root||(s.media._root=s.media.parentElement),s.update_media_viewport(),s.panel.appendChild(s.media),s.init_slide(e));return}s.toggle_spinner(s.options_spinner,!0),s.media=s.createElement("img"),s.media.onload=function(){s.media===s&&(s.media.onerror=null,s.toggle_spinner(s.options_spinner),s.init_slide(e),s.update_media_viewport())},s.media.src=s.gallery.src,s.panel.appendChild(s.media),s.media&&(s.options_spinner||s.setStyle(s.media,"visibility","visible"),s.media.onerror=function(){s.media===s&&(s.checkout(s.media),s.addClass(s.spinner,"error"),s.toggle_spinner(s.options_spinner))})}},this.toggle_spinner=(e,t)=>{e&&s.toggleClass(s.spinner,"spin",t)},this.has_fullscreen=()=>document.fullscreen||document.fullscreenElement||document.webkitFullscreenElement||document.mozFullScreenElement,this.resize_listener=()=>{if(s.update_widget_viewport(),s.media&&s.update_media_viewport(),s.prefix_request){let e=s.has_fullscreen();s.toggleClass(s.maximize,"on",e),e||s.detect_fullscreen()}},this.detect_fullscreen=()=>{s.toggleDisplay(s.maximize,screen.availHeight-e.innerHeight>0)},this.update_widget_viewport=()=>{s.viewport_w=s.widget.clientWidth,s.viewport_h=s.widget.clientHeight},this.update_media_viewport=()=>{s.media_w=s.media.clientWidth,s.media_h=s.media.clientHeight},this.update_scroll=e=>{s.setStyle(s.media,"transform","translate(-50%, -50%) scale("+(e||s.scale)+")")},this.update_panel=(e,t)=>{s.setStyle(s.panel,"transform",e||t?"translate("+e+"px, "+t+"px)":"")},this.update_slider=(e,t,i)=>{t?s.prepareStyle(s.slider,function(){s.update_slider(e,!1,i)}):s.setStyle(s.slider,"transform","translateX("+(-(100*e)+(i||0))+"%)")},this.toggle_listener=t=>{s.toggleListener(t,e,"keydown",s.key_listener),s.toggleListener(t,e,"resize",s.resize_listener)},this.history_listener=e=>{s.panel&&e.state.spl&&s.close(!0)},this.key_listener=e=>{if(s.panel){let t=!1!==s.options["zoom-in"];switch(e.keyCode){case s.keycodes.BACKSPACE:t&&s.autofit();break;case s.keycodes.SPACEBAR:s.options_autoslide&&s.play();break;case s.keycodes.LEFT:s.prev();break;case s.keycodes.RIGHT:s.next();break;case s.keycodes.NUMBLOCK_PLUS:case s.keycodes.PLUS:t&&s.zoom_in();break;case s.keycodes.NUMBLOCK_MINUS:case s.keycodes.MINUS:t&&s.zoom_out();break;case s.keycodes.INFO:s.info()}}},this.wheel_listener=e=>{if(s.panel&&!1!==s.options["zoom-in"]){let t=e.deltaY;(t=(t<0?1:t?-1:0)*.5)<0?s.zoom_out():s.zoom_in()}},this.play=(e,t)=>{let i="boolean"==typeof e?e:!this.playing;!s.playing===i&&(s.playing=s.playing?clearTimeout(s.playing):1,s.toggleClass(s.player,"on",s.playing),t||s.animate_bar(s.playing))},this.animate_bar=e=>{s.options_progress&&(s.prepareStyle(s.progress,function(){s.setStyle(s.progress,"transition-duration",""),s.setStyle(s.progress,"transform","")}),e&&(s.setStyle(s.progress,"transition-duration",s.delay+"s"),s.setStyle(s.progress,"transform","translateX(0)"))),e&&(s.playing=setTimeout(s.next,1e3*s.delay))},this.autohide=()=>{s.options_autohide&&(s.hide_cooldown=Date.now()+2950,s.hide||(s.addClass(s.widget,"menu"),s.schedule(3e3)))},this.schedule=e=>{s.hide=setTimeout(function(){let e=Date.now();e>=s.hide_cooldown?(s.removeClass(s.widget,"menu"),s.hide=0):s.schedule(s.hide_cooldown-e)},e)},this.menu=e=>{"boolean"==typeof e&&(s.hide=e?s.hide:0),s.hide?(s.hide=clearTimeout(s.hide),s.removeClass(s.widget,"menu")):s.autohide()},this.start=e=>{s.cancelEvent(e,!0),s.is_down=!0,s.dragged=!1;let t=e.touches;t&&(t=t[0])&&(e=t),s.slidable=s.media_w*s.scale<=s.viewport_w,s.startX=e.pageX,s.startY=e.pageY,s.toggleAnimation(s.panel)},this.end=e=>{if(s.cancelEvent(e),s.is_down){if(s.dragged){if(s.slidable&&s.dragged){let t=s.x<-(s.viewport_w/7)&&(s.current_slides.viewport_w/7&&(s.current_slide>1||s.options_infinite);(t||i)&&(s.update_slider(s.current_slide-1,!0,s.x/s.viewport_w*100),t&&s.next()||i&&s.prev()),s.x=0,s.update_panel()}s.toggleAnimation(s.panel,!0)}else s.menu();s.is_down=!1}},this.move=e=>{if(s.cancelEvent(e),s.is_down){let t=e.touches;t&&(t=t[0])&&(e=t);let i=(s.media_w*s.scale-s.viewport_w)/2;s.x-=s.startX-(s.startX=e.pageX),!s.slidable&&(s.x>i?s.x=i:s.x<-i&&(s.x=-i),s.media_h*s.scale>s.viewport_h&&(i=(s.media_h*s.scale-s.viewport_h)/2,s.y-=s.startY-(s.startY=e.pageY),s.y>i?s.y=i:s.y<-i&&(s.y=-i))),s.dragged=!0,s.update_panel(s.x,s.y)}else s.autohide()},this.fullscreen=e=>{let t=s.has_fullscreen();("boolean"!=typeof e||!!t!==e)&&(t?document[s.prefix_exit]():s.widget[s.prefix_request]())},this.theme=e=>{"string"!=typeof e&&(e=s.toggle_theme?"":s.options_theme||"white"),s.toggle_theme!==e&&(s.toggle_theme&&s.removeClass(s.widget,s.toggle_theme),e&&s.addClass(s.widget,e),s.toggle_theme=e)},this.autofit=e=>{"boolean"==typeof e&&(s.toggle_autofit=!e),s.toggle_autofit=1===s.scale&&!s.toggle_autofit,s.toggleClass(s.media,"autofit",s.toggle_autofit),s.setStyle(s.media,"transform",""),s.scale=1,s.x=0,s.y=0,s.update_media_viewport(),s.toggleAnimation(s.panel),s.update_panel()},this.zoom_in=e=>{let t=s.scale/.65;t<=50&&(s.disable_autoresizer(),s.x/=.65,s.y/=.65,s.update_panel(s.x,s.y),s.zoom(t))},this.zoom_out=e=>{let t=.65*s.scale;s.disable_autoresizer(),t>=1&&(1===t?s.x=s.y=0:(s.x*=.65,s.y*=.65),s.update_panel(s.x,s.y),s.zoom(t))},this.zoom=e=>{s.scale=e||1,s.update_scroll()},this.info=()=>{s.footer_visible=!s.footer_visible,s.toggleVisibility(s.footer,s.footer_visible)},this.disable_autoresizer=()=>{s.toggle_autofit&&s.autofit()},this.show_gallery=()=>{s.toggleAnimation(s.widget,!0),s.addClass(s.body,"hide-scrollbars"),s.addClass(s.widget,"show"),s.toggle_listener(!0),s.update_widget_viewport(),s.resize_listener(),s.autohide(),s.options_autoslide&&s.play(!0,!0)},this.download=()=>{s.downloadImage(s.body,s.media)},this.close=(e,t)=>{if(s.hasClass(s.body,"relative")&&!t){s.fullscreen(!1);return}t||setTimeout(function(){s.body.removeChild(s.widget),s.panel=s.media=s.gallery=s.options=s.options_group=s.anchors=s.options_onshow=s.options_onchange=s.options_onclose=s.options_click=null},200),s.removeClass(s.body,"hide-scrollbars"),s.removeClass(s.widget,"show"),s.fullscreen(!1),s.toggle_listener(),s.gallery_next&&(s.media_next.src=""),s.playing&&s.play(),s.media&&s.checkout(s.media),s.hide&&(s.hide=clearTimeout(s.hide)),s.toggle_theme&&s.theme(),s.options_class&&s.removeClass(s.widget,s.options_class),s.options_onclose&&s.options_onclose(),t&&(s.body.removeChild(s.widget),s.panel=s.media=s.gallery=s.options=s.options_group=s.anchors=s.options_onshow=s.options_onchange=s.options_onclose=s.options_click=null)},this.checkout=e=>{if(e._root)e._root.appendChild(e),e._root=null;else{let t=e.parentNode;t&&t.removeChild(e),e=e.src=e.onerror=""}},this.prev=e=>{if(e&&s.autohide(),s.slide_count>1){if(s.current_slide>1)return s.goto(s.current_slide-1);if(s.options_infinite)return s.update_slider(s.slide_count,!0),s.goto(s.slide_count)}},this.next=e=>{if(e&&s.autohide(),s.slide_count>1){if(s.current_slide{if(e!==s.current_slide){s.playing?(clearTimeout(s.playing),s.animate_bar()):s.autohide();let t=e>s.current_slide;return s.current_slide=e,s.setup_page(t),!0}},this.prepare=e=>{let t=s.anchors[s.current_slide-1];s.apply_options(t);let i=n&&n.downlink,o=Math.max(s.viewport_h,s.viewport_w)*l;i&&1200*i{if(s.x=0,s.y=0,s.scale=1,s.media){if(s.media.onerror)s.checkout(s.media);else{let t=s.media;setTimeout(function(){t&&s.media!==t&&(s.checkout(t),t=null)},650),s.prepare_animation(),s.update_panel()}}s.footer&&s.toggleVisibility(s.footer,0),s.prepare(e),s.update_slider(s.current_slide-1),s.removeClass(s.spinner,"error"),s.init_slide(s.current_slide),s.toggleAnimation(s.panel),s.update_panel();let i=s.gallery.title,o=s.parse_option("description"),n=s.parse_option("button"),l=i||o||n;l&&(i&&s.setText(s.title,i),o&&s.setText(s.description,o),n&&s.setText(s.button,n),s.toggleDisplay(s.title,i),s.toggleDisplay(s.description,o),s.toggleDisplay(s.button,n),s.setStyle(s.footer,"transform","all"===s.options_autohide?"":"none")),s.options_autohide||s.addClass(s.widget,"menu"),s.toggleVisibility(s.footer,s.footer_visible&&l),s.toggleVisibility(s.page_prev,s.options_infinite||s.current_slide>1),s.toggleVisibility(s.page_next,s.options_infinite||s.current_slide1?s.current_slide+" / "+s.slide_count:""),s.options_onchange&&s.options_onchange(s.current_slide,s.options)}};"undefined"!=typeof module&&void 0!==module.exports?module.exports=t:e.Spotlight=t}(window); \ No newline at end of file diff --git a/javascript/textualInversion.js b/javascript/textualInversion.js index 99360557..20443fcc 100644 --- a/javascript/textualInversion.js +++ b/javascript/textualInversion.js @@ -1,3 +1,6 @@ + + + function start_training_textual_inversion() { gradioApp().querySelector('#ti_error').innerHTML = ''; diff --git a/javascript/ui.js b/javascript/ui.js index da748446..dbab8334 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -1,1996 +1,323 @@ +// various functions for interaction with ui.py not large enough to warrant putting them in separate files + function set_theme(theme) { - /* - var gradioURL = window.location.href; - if (!gradioURL.includes('?__theme=')) { - window.location.replace(gradioURL + '?__theme=' + theme); - } - */ + var gradioURL = window.location.href; + if (!gradioURL.includes('?__theme=')) { + window.location.replace(gradioURL + '?__theme=' + theme); + } } -var selectedTabItemId = "tab_txt2img"; - function all_gallery_buttons() { - var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small'); - var visibleGalleryButtons = []; - allGalleryButtons.forEach(function(elem) { - if (elem.parentElement.offsetParent) { - visibleGalleryButtons.push(elem); - } - }); - return visibleGalleryButtons; + var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small'); + var visibleGalleryButtons = []; + allGalleryButtons.forEach(function(elem) { + if (elem.parentElement.offsetParent) { + visibleGalleryButtons.push(elem); + } + }); + return visibleGalleryButtons; } function selected_gallery_button() { - var allCurrentButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnail-item.thumbnail-small.selected'); - var visibleCurrentButton = null; - allCurrentButtons.forEach(function(elem) { - if (elem.parentElement.offsetParent) { - visibleCurrentButton = elem; - } - }); - return visibleCurrentButton; + return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null; } function selected_gallery_index() { - var buttons = all_gallery_buttons(); - var button = selected_gallery_button(); - - var result = -1; - buttons.forEach(function(v, i) { - if (v == button) { - result = i; - } - }); - - return result; + return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected')); } function extract_image_from_gallery(gallery) { - if (gallery.length == 0) { - return [null]; - } - if (gallery.length == 1) { - return [gallery[0]]; - } + if (gallery.length == 0) { + return [null]; + } + if (gallery.length == 1) { + return [gallery[0]]; + } - var index = selected_gallery_index(); + var index = selected_gallery_index(); - if (index < 0 || index >= gallery.length) { - // Use the first image in the gallery as the default - index = 0; - } + if (index < 0 || index >= gallery.length) { + // Use the first image in the gallery as the default + index = 0; + } - return [gallery[index]]; + return [gallery[index]]; } window.args_to_array = Array.from; // Compatibility with e.g. extensions that may expect this to be around function switch_to_txt2img() { - gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click(); - return Array.from(arguments); + return Array.from(arguments); } function switch_to_img2img_tab(no) { - gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click(); - gradioApp().getElementById('mode_img2img').querySelectorAll('button')[no].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click(); + gradioApp().getElementById('mode_img2img').querySelectorAll('button')[no].click(); } function switch_to_img2img() { - switch_to_img2img_tab(0); - return Array.from(arguments); + switch_to_img2img_tab(0); + return Array.from(arguments); } function switch_to_sketch() { - switch_to_img2img_tab(1); - return Array.from(arguments); + switch_to_img2img_tab(1); + return Array.from(arguments); } function switch_to_inpaint() { - switch_to_img2img_tab(2); - return Array.from(arguments); + switch_to_img2img_tab(2); + return Array.from(arguments); } function switch_to_inpaint_sketch() { - switch_to_img2img_tab(3); - return Array.from(arguments); + switch_to_img2img_tab(3); + return Array.from(arguments); } function switch_to_extras() { - gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click(); + gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click(); - return Array.from(arguments); + return Array.from(arguments); } function get_tab_index(tabId) { - let buttons = gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button'); - for (let i = 0; i < buttons.length; i++) { - if (buttons[i].classList.contains('selected')) { - return i; - } - } - return 0; + let buttons = gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button'); + for (let i = 0; i < buttons.length; i++) { + if (buttons[i].classList.contains('selected')) { + return i; + } + } + return 0; } function create_tab_index_args(tabId, args) { - var res = Array.from(args); - res[0] = get_tab_index(tabId); - return res; + var res = Array.from(args); + res[0] = get_tab_index(tabId); + return res; } function get_img2img_tab_index() { - let res = Array.from(arguments); - res.splice(-2); - res[0] = get_tab_index('mode_img2img'); - return res; + let res = Array.from(arguments); + res.splice(-2); + res[0] = get_tab_index('mode_img2img'); + return res; } function create_submit_args(args) { - var res = Array.from(args); + var res = Array.from(args); - // As it is currently, txt2img and img2img send back the previous output args (txt2img_gallery, generation_info, html_info) whenever you generate a new image. - // This can lead to uploading a huge gallery of previously generated images, which leads to an unnecessary delay between submitting and beginning to generate. - // I don't know why gradio is sending outputs along with inputs, but we can prevent sending the image gallery here, which seems to be an issue for some. - // If gradio at some point stops sending outputs, this may break something - if (Array.isArray(res[res.length - 3])) { - res[res.length - 3] = null; - } + // As it is currently, txt2img and img2img send back the previous output args (txt2img_gallery, generation_info, html_info) whenever you generate a new image. + // This can lead to uploading a huge gallery of previously generated images, which leads to an unnecessary delay between submitting and beginning to generate. + // I don't know why gradio is sending outputs along with inputs, but we can prevent sending the image gallery here, which seems to be an issue for some. + // If gradio at some point stops sending outputs, this may break something + if (Array.isArray(res[res.length - 3])) { + res[res.length - 3] = null; + } - return res; + return res; } function showSubmitButtons(tabname, show) { - gradioApp().getElementById(tabname + "_interrupt").style.display = show ? "none" : "flex"; - gradioApp().getElementById(tabname + "_skip").style.display = show ? "none" : "flex"; - gradioApp().getElementById(tabname + "_generate").style.display = !show ? "none" : "flex"; + gradioApp().getElementById(tabname + '_interrupt').style.display = show ? "none" : "block"; + gradioApp().getElementById(tabname + '_skip').style.display = show ? "none" : "block"; } function showRestoreProgressButton(tabname, show) { - var button = gradioApp().getElementById(tabname + "_restore_progress"); - if (!button) return; + var button = gradioApp().getElementById(tabname + "_restore_progress"); + if (!button) return; - button.style.display = show ? "flex" : "none"; + button.style.display = show ? "flex" : "none"; } - function submit() { - showSubmitButtons('txt2img', false); + showSubmitButtons('txt2img', false); - var id = randomId(); - localStorage.setItem("txt2img_task_id", id); + var id = randomId(); + localSet("txt2img_task_id", id); - requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() { - showSubmitButtons('txt2img', true); - localStorage.removeItem("txt2img_task_id"); - showRestoreProgressButton('txt2img', false); - }); + requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() { + showSubmitButtons('txt2img', true); + localRemove("txt2img_task_id"); + showRestoreProgressButton('txt2img', false); + }); - var res = create_submit_args(arguments); + var res = create_submit_args(arguments); - res[0] = id; + res[0] = id; - return res; + return res; } function submit_img2img() { - showSubmitButtons('img2img', false); + showSubmitButtons('img2img', false); - var id = randomId(); - localStorage.setItem("img2img_task_id", id); + var id = randomId(); + localSet("img2img_task_id", id); - requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() { - showSubmitButtons('img2img', true); - localStorage.removeItem("img2img_task_id"); - showRestoreProgressButton('img2img', false); - }); + requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() { + showSubmitButtons('img2img', true); + localRemove("img2img_task_id"); + showRestoreProgressButton('img2img', false); + }); - var res = create_submit_args(arguments); + var res = create_submit_args(arguments); - res[0] = id; - res[1] = get_tab_index('mode_img2img'); + res[0] = id; + res[1] = get_tab_index('mode_img2img'); - return res; + return res; } function restoreProgressTxt2img() { - showRestoreProgressButton("txt2img", false); - var id = localStorage.getItem("txt2img_task_id"); + showRestoreProgressButton("txt2img", false); + var id = localGet("txt2img_task_id"); - id = localStorage.getItem("txt2img_task_id"); + if (id) { + requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() { + showSubmitButtons('txt2img', true); + }, null, 0); + } - if (id) { - requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() { - showSubmitButtons('txt2img', true); - }, null, 0); - } - - return id; + return id; } function restoreProgressImg2img() { - showRestoreProgressButton("img2img", false); + showRestoreProgressButton("img2img", false); - var id = localStorage.getItem("img2img_task_id"); + var id = localGet("img2img_task_id"); - if (id) { - requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() { - showSubmitButtons('img2img', true); - }, null, 0); - } + if (id) { + requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() { + showSubmitButtons('img2img', true); + }, null, 0); + } - return id; + return id; } + onUiLoaded(function() { - showRestoreProgressButton('txt2img', localStorage.getItem("txt2img_task_id")); - showRestoreProgressButton('img2img', localStorage.getItem("img2img_task_id")); + showRestoreProgressButton('txt2img', localGet("txt2img_task_id")); + showRestoreProgressButton('img2img', localGet("img2img_task_id")); }); function modelmerger() { - var id = randomId(); - requestProgress(id, gradioApp().getElementById('modelmerger_results_panel'), null, function() {}); + var id = randomId(); + requestProgress(id, gradioApp().getElementById('modelmerger_results_panel'), null, function() {}); - var res = create_submit_args(arguments); - res[0] = id; - return res; + var res = create_submit_args(arguments); + res[0] = id; + return res; } function ask_for_style_name(_, prompt_text, negative_prompt_text) { - var name_ = prompt('Style name:'); - return [name_, prompt_text, negative_prompt_text]; + var name_ = prompt('Style name:'); + return [name_, prompt_text, negative_prompt_text]; } function confirm_clear_prompt(prompt, negative_prompt) { - if (confirm("Delete prompt?")) { - prompt = ""; - negative_prompt = ""; - } + if (confirm("Delete prompt?")) { + prompt = ""; + negative_prompt = ""; + } - return [prompt, negative_prompt]; -} - - -var promptTokecountUpdateFuncs = {}; - -function recalculatePromptTokens(name) { - if (promptTokecountUpdateFuncs[name]) { - promptTokecountUpdateFuncs[name](); - } -} - -function recalculate_prompts_txt2img() { - recalculatePromptTokens('txt2img_prompt'); - recalculatePromptTokens('txt2img_neg_prompt'); - return Array.from(arguments); -} - -function recalculate_prompts_img2img() { - recalculatePromptTokens('img2img_prompt'); - recalculatePromptTokens('img2img_neg_prompt'); - return Array.from(arguments); + return [prompt, negative_prompt]; } var opts = {}; -onUiUpdate(function() { - - if (Object.keys(opts).length != 0) return; +onAfterUiUpdate(function() { + if (Object.keys(opts).length != 0) return; - var json_elem = gradioApp().getElementById("settings_json"); - if (json_elem == null) return; + var json_elem = gradioApp().getElementById('settings_json'); + if (json_elem == null) return; - var textarea = json_elem.querySelector("textarea"); - var jsdata = textarea.value; - opts = JSON.parse(jsdata); - executeCallbacks(optionsChangedCallbacks); + var textarea = json_elem.querySelector('textarea'); + var jsdata = textarea.value; + opts = JSON.parse(jsdata); - Object.defineProperty(textarea, "value", { - set: function (newValue) { - var valueProp = Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - "value" - ); - var oldValue = valueProp.get.call(textarea); - valueProp.set.call(textarea, newValue); + executeCallbacks(optionsChangedCallbacks); /*global optionsChangedCallbacks*/ - if (oldValue != newValue) { - opts = JSON.parse(textarea.value); - } + Object.defineProperty(textarea, 'value', { + set: function(newValue) { + var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value'); + var oldValue = valueProp.get.call(textarea); + valueProp.set.call(textarea, newValue); - executeCallbacks(optionsChangedCallbacks); - }, - get: function () { - var valueProp = Object.getOwnPropertyDescriptor( - HTMLTextAreaElement.prototype, - "value" - ); - return valueProp.get.call(textarea); - }, - }); - - //console.log(opts); - - json_elem.parentElement.style.display = "none"; - - function registerTextarea(id, id_counter, id_button) { - var prompt = gradioApp().getElementById(id); - var counter = gradioApp().getElementById(id_counter); - var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); - - if (counter.parentElement == prompt.parentElement) { - return; - } - - prompt.parentElement.insertBefore(counter, prompt); - counter.classList.add("token-counter"); - prompt.parentElement.style.position = "relative"; - - promptTokecountUpdateFuncs[id] = function () { - update_token_counter(id_button); - }; - textarea.addEventListener("input", promptTokecountUpdateFuncs[id]); - } - - registerTextarea( - "txt2img_prompt", - "txt2img_token_counter", - "txt2img_token_button" - ); - registerTextarea( - "txt2img_neg_prompt", - "txt2img_negative_token_counter", - "txt2img_negative_token_button" - ); - registerTextarea( - "img2img_prompt", - "img2img_token_counter", - "img2img_token_button" - ); - registerTextarea( - "img2img_neg_prompt", - "img2img_negative_token_counter", - "img2img_negative_token_button" - ); - - var show_all_pages = gradioApp().getElementById("settings_show_all_pages"); - var settings_tabs = gradioApp().querySelector("#settings div"); - if (show_all_pages && settings_tabs) { - settings_tabs.appendChild(show_all_pages); - show_all_pages.onclick = function () { - gradioApp() - .querySelectorAll("#settings > div") - .forEach(function (elem) { - elem.style.display = "block"; - }); - gradioApp() - .querySelectorAll("#settings > div > div > div") - .forEach(function (elem) { - elem.style.maxHeight = "none"; - }); - }; - } - /* - ^ matches the start - * matches any position - $ matches the end - */ - /* anapnoe ui start */ - - /* auto grow textarea */ - function autoGrowPromptTextarea() { - gradioApp() - .querySelectorAll('[id$="_prompt"] textarea') - .forEach(function (elem) { - elem.parentElement.click(); - }); - } - - gradioApp() - .querySelectorAll( - '[id$="_prompt"] textarea, [id^="setting_"] textarea, textarea' - ) - .forEach(function (elem) { - elem.style.boxSizing = "border-box"; - var offset = elem.offsetHeight - elem.clientHeight; - elem.addEventListener("input", function (e) { - e.target.style.minHeight = "auto"; - e.target.style.minHeight = e.target.scrollHeight + offset + 2 + "px"; - }); - - elem.parentElement.addEventListener("click", function (e) { - let textarea = e.currentTarget.querySelector("textarea"); - textarea.style.minHeight = "auto"; - textarea.style.minHeight = textarea.scrollHeight + offset + 2 + "px"; - }); - }); - - /* resizable split view */ - const resizeEvent = window.document.createEvent("UIEvents"); - resizeEvent.initUIEvent("resize", true, false, window, 0); - - gradioApp() - .querySelectorAll('[id $="2img_splitter"]') - .forEach((elem) => { - elem.addEventListener("mousedown", function (e) { - e.preventDefault(); - - let resizer = e.currentTarget; - let container = resizer.parentElement; - - let flexDir = window - .getComputedStyle(container) - .getPropertyValue("flex-direction"); - - let leftSide = resizer.previousElementSibling; - let rightSide = resizer.nextElementSibling; - - let dir = flexDir == "row-reverse" ? -1.0 : 1.0; - - let x = e.clientX; - let y = e.clientY; - let leftWidth = leftSide.getBoundingClientRect().width; - - function mouseMoveHandler(e) { - resizer.style.cursor = "col-resize"; - container.style.cursor = "col-resize"; - - const dx = (e.clientX - x) * dir; - const dy = (e.clientY - y) * dir; - - const newLeftWidth = - ((leftWidth + dx) * 100) / container.getBoundingClientRect().width; - leftSide.style.flexBasis = `${newLeftWidth}%`; - leftSide.style.userSelect = "none"; - leftSide.style.pointerEvents = "none"; - rightSide.style.userSelect = "none"; - rightSide.style.pointerEvents = "none"; - //window.dispatchEvent(resizeEvent); - } - - function mouseUpHandler() { - resizer.style.removeProperty("cursor"); - container.style.removeProperty("cursor"); - leftSide.style.removeProperty("user-select"); - leftSide.style.removeProperty("pointer-events"); - rightSide.style.removeProperty("user-select"); - rightSide.style.removeProperty("pointer-events"); - container.removeEventListener("mousemove", mouseMoveHandler); - container.removeEventListener("mouseup", mouseUpHandler); - //window.dispatchEvent(resizeEvent); - } - - container.addEventListener("mousemove", mouseMoveHandler); - container.addEventListener("mouseup", mouseUpHandler); - }); - - let flex_reverse = false; - elem.addEventListener("dblclick", function (e) { - flex_reverse = !flex_reverse; - e.preventDefault(); - - let resizer = e.currentTarget; - let container = resizer.parentElement; - //let flexDir = window.getComputedStyle(container).getPropertyValue('flex-direction'); - - if (flex_reverse) { - container.style.flexDirection = "row-reverse"; - } else { - container.style.flexDirection = "row"; - } - }); - }); - - // set this globally - //let selectedTabItemId = "tab_txt2img"; - /* switch tab item from instance button, this is the only method that works i havent found a workaround yet */ - const Observe = (sel, opt, cb) => { - const Obs = new MutationObserver((m) => [...m].forEach(cb)); - gradioApp() - .querySelectorAll(sel) - .forEach((el) => Obs.observe(el, opt)); - }; - Observe( - "#tabs > div.tabitem", - { - attributesList: ["style"], - attributeOldValue: true, - }, - (m) => { - if (m.target.style.display === "block") { - let idx = parseInt(m.target.getAttribute("tab-item")); - selectedTabItemId = m.target.id; - tabItemChanged(idx); - } - } - ); - - function tabItemChanged(idx) { - gradioApp() - .querySelectorAll( - "#tabs > div > button.selected, #nav_menu_header_tabs > button.selected" - ) - .forEach(function (tab) { - tab.classList.remove("selected"); - }); - - gradioApp() - .querySelectorAll( - "#tabs > div > button:nth-child(" + - (idx + 1) + - "), #nav_menu_header_tabs > button:nth-child(" + - (idx + 1) + - ")" - ) - .forEach(function (tab) { - tab.classList.add("selected"); - }); - //gardio removes listeners and attributes from tab buttons we add them again here - gradioApp() - .querySelectorAll("#tabs > div > button") - .forEach(function (tab, index) { - tab.setAttribute("tab-id", index); - tab.removeEventListener("mouseup", navTabClicked); - tab.addEventListener("mouseup", navTabClicked); - if (tab.innerHTML.indexOf("Theme") != -1) tab.style.display = "none"; - }); - - /* gradioApp().querySelectorAll('[id^="image_buttons_"] button').forEach(function (elem){ - - if(elem.id == "txt2img_tab"){ - elem.setAttribute("tab-id", 0); - elem.removeEventListener('click', navTabClicked); - elem.addEventListener('click', navTabClicked); - }else if(elem.id == "img2img_tab" || elem.id == "inpaint_tab"){ - elem.setAttribute("tab-id", 1); - elem.removeEventListener('click', navTabClicked); - elem.addEventListener('click', navTabClicked); - }if(elem.id == "extras_tab"){ - elem.setAttribute("tab-id", 2); - elem.removeEventListener('click', navTabClicked); - elem.addEventListener('click', navTabClicked); - } - }) */ - - /* const pdiv = gradioApp().querySelector("#"+selectedTabItemId+" .progressDiv"); - if(!pdiv && selectedTabItemId == "tab_txt2img"){ - showSubmitButtons('txt2img', true); - }else if(!pdiv && selectedTabItemId == "tab_img2img"){ - showSubmitButtons('img2img', true); - } */ - - //window.onUiHeaderTabUpdate(); - // also here the same issue - /* - gradioApp().querySelectorAll('[id^="image_buttons"] [id$="_tab"]').forEach(function (button, index){ - if(button.id == ("img2img_tab" || "inpaint_tab") ){ - button.setAttribute("tab-id", 1 ); - }else if(button.id == "extras_tab"){ - button.setAttribute("tab-id", 2 ); - } - - button.removeEventListener('mouseup', navTabClicked); - button.addEventListener('mouseup', navTabClicked); - - - }) - */ - - netMenuVisibility(); - } - - // menu - function disableScroll() { - scrollTop = window.pageYOffset || document.documentElement.scrollTop; - scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; - window.scrollTo(scrollLeft, scrollTop); - - window.onscroll = function () { - window.scrollTo(scrollLeft, scrollTop); - }; - } - - function enableScroll() { - window.onscroll = function () {}; - } - - function getPos(el) { - let rect = el.getBoundingClientRect(); - return { x: rect.left, y: rect.top }; - } - - function toggleMenu(isopen, icon, panel, func) { - if (isopen) { - panel.classList.add("open"); - icon.classList.add("fixed"); - gradioApp().addEventListener("click", func); - disableScroll(); - } else { - panel.classList.remove("open"); - icon.classList.remove("fixed"); - gradioApp().removeEventListener("click", func); - enableScroll(); - } - } - - // close aside views - function closeAsideViews(menu) { - if (quick_menu != menu && quick_menu_open) quick_menu.click(); - if (net_menu != menu && net_menu_open) net_menu.click(); - if (theme_menu != menu && theme_menu_open) theme_menu.click(); - } - - // if we change to other view other than 2img and if aside mode is selected close extra networks aside and hide the net menu icon - let net_container = gradioApp().querySelector("#txt2img_extra_networks_row"); - let net_menu_open = false; - const net_menu = gradioApp().querySelector("#extra_networks_menu"); - function netMenuVisibility() { - if (selectedTabItemId.indexOf("2img") != -1) { - net_menu.style.display = "block"; - let nid = selectedTabItemId.split("_")[1]; - net_container = gradioApp().querySelector( - "#" + nid + "_extra_networks_row" - ); - if (net_container.classList.contains("aside")) { - net_menu.style.display = "block"; - toggleMenu(net_menu_open, net_menu, net_container, null); - } else { - net_menu.style.display = "none"; - } - } else { - net_menu.style.display = "none"; - } - } - - // mobile nav menu - const tabs_menu = gradioApp().querySelector("#tabs > div:first-child"); - const nav_menu = gradioApp().querySelector("#nav_menu"); - const header = gradioApp().querySelector("#header-top"); - let menu_open = false; - const z_menu = nav_menu.cloneNode(true); - z_menu.id = "clone_nav_menu"; - header.parentElement.append(z_menu); - function toggleNavMenu(e) { - e.stopPropagation(); - menu_open = !menu_open; - toggleMenu(menu_open, nav_menu, tabs_menu, toggleNavMenu); - } - z_menu.addEventListener("click", toggleNavMenu); - - // quicksettings nav menu - let quick_menu_open = false; - const quicksettings_overflow = gradioApp().querySelector( - "#quicksettings_overflow" - ); - const quick_menu = gradioApp().querySelector("#quick_menu"); - function toggleQuickMenu(e) { - closeAsideViews(quick_menu); - quick_menu_open = !quick_menu_open; - const withinBoundaries = e.composedPath().includes(quicksettings_overflow); - if (!quick_menu_open && withinBoundaries) { - quick_menu_open = true; - } else { - e.preventDefault(); - e.stopPropagation(); - toggleMenu( - quick_menu_open, - quick_menu, - quicksettings_overflow, - toggleQuickMenu - ); - } - } - quick_menu.addEventListener("click", toggleQuickMenu); - - // extra networks nav menu - function clickedOutside(e) { - //console.log(e.target.getAttribute('data-testid')); - if ( - e.target.getAttribute("data-testid") != "textbox" && - e.target.getAttribute("data-testid") - ) { - if (net_menu_open && e.target.closest('[id$="2img_settings_scroll"]')) - net_menu.click(); - } - } - function toggleNetMenu(e) { - closeAsideViews(net_menu); - net_menu_open = !net_menu_open; - e.preventDefault(); - e.stopPropagation(); - toggleMenu(net_menu_open, net_menu, net_container, clickedOutside); - } - net_menu.addEventListener("click", toggleNetMenu); - gradioApp() - .querySelectorAll('button[id*="2img_extra_networks"]') - .forEach((elem) => { - elem.addEventListener("click", toggleNetMenu); - }); - - // theme nav menu - let theme_container = gradioApp().querySelector("#tab_ui_theme"); - let theme_menu_open = false; - const theme_menu = gradioApp().querySelector("#theme_menu"); - function toggleThemeMenu(e) { - closeAsideViews(theme_menu); - theme_menu_open = !theme_menu_open; - e.preventDefault(); - e.stopPropagation(); - toggleMenu(theme_menu_open, theme_menu, theme_container, null); - } - theme_menu.addEventListener("click", toggleThemeMenu); - - const theme_tab = gradioApp().querySelector("#tab_ui_theme"); - function theme_aside(value) { - if (value) { - theme_tab.classList.add("aside"); - } else { - theme_tab.classList.remove("aside"); - } - } - if (theme_tab) theme_aside(true); - - function generateOnRepeat(elem, isforever) { - if (elem.generateOnRepeatInterval != null) - clearInterval(elem.generateOnRepeatInterval); - if (isforever) { - const generate_button = elem.previousElementSibling; - elem.generateOnRepeatInterval = setInterval(function () { - if (window.getComputedStyle(generate_button).display !== "none") { - generate_button.click(); - } - }, 500); - } - } - - function toggleGenerateForever(e) { - e.target.classList.toggle("active"); - if (e.target.className.indexOf("active") != -1) { - generateOnRepeat(e.target, true); - } else { - generateOnRepeat(e.target, false); - } - e.preventDefault(); - e.stopPropagation(); - } - - gradioApp() - .querySelectorAll('button[id*="2img_generate_forever"]') - .forEach((elem) => { - elem.addEventListener("click", toggleGenerateForever); - }); - - /* let generateOnRepeat = function (genbuttonid, interruptbuttonid) { - let genbutton = gradioApp().querySelector(genbuttonid); - let interruptbutton = gradioApp().querySelector(interruptbuttonid); - if (!interruptbutton.offsetParent) { - genbutton.click(); - } - clearInterval(window.generateOnRepeatInterval); - window.generateOnRepeatInterval = setInterval(function () { - if (!interruptbutton.offsetParent) { - genbutton.click(); - } - }, 500); - }; - - appendContextMenuOption("#txt2img_generate", "Generate forever", function () { - generateOnRepeat("#txt2img_generate", "#txt2img_interrupt"); - }); - appendContextMenuOption("#img2img_generate", "Generate forever", function () { - generateOnRepeat("#img2img_generate", "#img2img_interrupt"); - }); - - let cancelGenerateForever = function () { - clearInterval(window.generateOnRepeatInterval); - }; */ - - // - /* - function attachAccordionListeners(elem) { - elem.querySelectorAll(".gradio-accordion > div.wrap").forEach((elem) => { - elem.addEventListener("click", toggleAccordion); - }); - } - function toggleAccordion(e) { - //e.preventDefault(); - //e.stopPropagation(); - //e.stopImmediatePropagation(); - let accordion_content = - e.currentTarget.parentElement.querySelector(".gap.svelte-vt1mxs"); - - if (accordion_content) { - e.preventDefault(); - e.stopPropagation(); - let accordion_icon = e.currentTarget.parentElement.querySelector( - ".label-wrap > .icon" - ); - if (accordion_content.className.indexOf("hidden") != -1) { - accordion_content.classList.remove("hidden"); - accordion_icon.style.setProperty("transform", "rotate(0deg)"); - e.currentTarget.classList.add("hide"); - } else { - accordion_content.classList.add("hidden"); - accordion_icon.style.setProperty("transform", "rotate(90deg)"); - e.currentTarget.classList.remove("hide"); - } - } else { - let accordion_btn = - e.currentTarget.parentElement.querySelector(".label-wrap"); - e.currentTarget.classList.add("hide"); - accordion_btn.click(); - //maybe here we need to setInterval until the content is available - setTimeout(function () { - accordion_content = accordion_btn.parentElement; - //console.log(accordion_content); - attachAccordionListeners(accordion_content); - }, 1000); - } - } - - attachAccordionListeners(gradioApp()); - */ - // additional ui styles - let styleobj = {}; - const r = gradioApp(); - const style = document.createElement("style"); - style.id = "ui-styles"; - r.appendChild(style); - - function updateOpStyles() { - let ops_styles = ""; - for (const key in styleobj) { - ops_styles += styleobj[key]; - } - const ui_styles = gradioApp().getElementById("ui-styles"); - ui_styles.innerHTML = ops_styles; - //console.log(ui_styles); - } - - // generated image fit contain - scale - function imageGeneratedFitMethod(value) { - styleobj.ui_view_fit = - "[id$='2img_gallery'] div>img {object-fit:" + value + "!important;}"; - } - gradioApp() - .querySelector("#setting_ui_output_image_fit") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='radio']")) { - imageGeneratedFitMethod(e.target.value.toLowerCase()); - updateOpStyles(); - } - }); - imageGeneratedFitMethod(opts.ui_output_image_fit.toLowerCase()); - - // livePreview fit contain - scale - function imagePreviewFitMethod(value) { - styleobj.ui_fit = ".livePreview img {object-fit:" + value + "!important;}"; - } - gradioApp() - .querySelector("#setting_live_preview_image_fit") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='radio']")) { - imagePreviewFitMethod(e.target.value.toLowerCase()); - updateOpStyles(); - } - }); - imagePreviewFitMethod(opts.live_preview_image_fit.toLowerCase()); - - // viewports order left - right - function viewportOrder(value) { - styleobj.ui_views_order = - "[id$=_prompt_image] + div {flex-direction:" + value + ";}"; - } - gradioApp() - .querySelector("#setting_ui_views_order") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='radio']")) { - viewportOrder(e.target.value.toLowerCase()); - updateOpStyles(); - } - }); - viewportOrder(opts.ui_views_order.toLowerCase()); - - // sd max resolution output - function sdMaxOutputResolution(value) { - gradioApp() - .querySelectorAll('[id$="2img_width"] input,[id$="2img_height"] input') - .forEach((elem) => { - elem.max = value; - }); - } - gradioApp() - .querySelector("#setting_sd_max_resolution") - .addEventListener("input", function (e) { - let intvalue = parseInt(e.target.value); - intvalue = Math.min(Math.max(intvalue, 512), 16384); - sdMaxOutputResolution(intvalue); - }); - sdMaxOutputResolution(opts.sd_max_resolution); - - function extra_networks_visibility(value) { - gradioApp() - .querySelectorAll('[id$="2img_extra_networks_row"]') - .forEach((elem) => { - if (value) { - elem.classList.remove("!hidden"); - } else { - elem.classList.add("!hidden"); - } - }); - } - gradioApp() - .querySelector("#setting_extra_networks_default_visibility input") - .addEventListener("click", function (e) { - extra_networks_visibility(e.target.checked); - }); - extra_networks_visibility(opts.extra_networks_default_visibility); - - function extra_networks_card_size(value) { - styleobj.extra_networks_card_size = - ":root{--ae-extra-networks-card-size:" + value + ";}"; - } - gradioApp() - .querySelectorAll("#setting_extra_networks_cards_size input") - .forEach(function (elem) { - elem.addEventListener("input", function (e) { - extra_networks_card_size(e.target.value); - updateOpStyles(); - }); - }); - extra_networks_card_size(opts.extra_networks_cards_size); - - function extra_networks_cards_visible_rows(value) { - styleobj.extra_networks_cards_visible_rows = - ":root{--ae-extra-networks-visible-rows:" + value + ";}"; - } - gradioApp() - .querySelectorAll("#setting_extra_networks_cards_visible_rows input") - .forEach(function (elem) { - elem.addEventListener("input", function (e) { - extra_networks_cards_visible_rows(e.target.value); - updateOpStyles(); - }); - }); - extra_networks_cards_visible_rows(opts.extra_networks_cards_visible_rows); - - function extra_networks_aside(value) { - gradioApp() - .querySelectorAll('[id$="2img_extra_networks_row"]') - .forEach((elem) => { - if (value) { - elem.classList.add("aside"); - } else { - elem.classList.remove("aside"); - } - netMenuVisibility(); - }); - } - gradioApp() - .querySelector("#setting_extra_networks_aside input") - .addEventListener("click", function (e) { - extra_networks_aside(e.target.checked); - }); - extra_networks_aside(opts.extra_networks_aside); - - // hidden - header ui tabs - let radio_hidden_html = ""; - let radio_header_html = ""; - let hiddentabs = {}; - let headertabs = {}; - const setting_ui_hidden_tabs = gradioApp().querySelector( - "#setting_ui_hidden_tabs textarea" - ); - const setting_ui_header_tabs = gradioApp().querySelector( - "#setting_ui_header_tabs textarea" - ); - const parent_header_tabs = gradioApp().querySelector("#nav_menu_header_tabs"); - setting_ui_hidden_tabs.style.display = "none"; - setting_ui_header_tabs.style.display = "none"; - - const maintabs = gradioApp().querySelectorAll( - "#tabs > div:first-child > button" - ); - const tabitems = gradioApp().querySelectorAll("#tabs > div.tabitem"); - - function tabOpsSave(setting) { - updateInput(setting); - - } - - function tabsHiddenChange() { - const keys = Object.keys(hiddentabs); - setting_ui_hidden_tabs.value = ""; - keys.forEach((key, index) => { - //console.log(`${key}: ${hiddentabs[key]} ${index}`); - if (hiddentabs[key] == true) { - styleobj[key] = - "#tabs > div:first-child > button:nth-child(" + - (index + 1) + - "){display:none;}"; - setting_ui_hidden_tabs.value += key + ","; - } else { - styleobj[key] = - "#tabs > div:first-child > button:nth-child(" + - (index + 1) + - "){display:block;}"; - } - }); - - tabOpsSave(setting_ui_hidden_tabs); - tabsHeaderChange(); - } - function tabsHeaderChange() { - const keys = Object.keys(headertabs); - setting_ui_header_tabs.value = ""; - keys.forEach((key, index) => { - //console.log(`${key}: ${hiddentabs[key]} ${index}`); - let nkey = key + "_hr"; - if (headertabs[key] == true && hiddentabs[key] == false) { - styleobj[nkey] = - "#nav_menu_header_tabs > button:nth-child(" + - (index + 1) + - "){display:block;}"; - setting_ui_header_tabs.value += key + ","; - } else { - styleobj[nkey] = - "#nav_menu_header_tabs > button:nth-child(" + - (index + 1) + - "){display:none;}"; - } - }); - - tabOpsSave(setting_ui_header_tabs); - } - - function navigate2TabItem(idx) { - gradioApp() - .querySelectorAll("#tabs > div.tabitem") - .forEach(function (tabitem, index) { - if (idx == index) { - tabitem.style.display = "block"; - } else { - tabitem.style.display = "none"; - } - }); - } - - function navTabClicked(e) { - const idx = parseInt(e.currentTarget.getAttribute("tab-id")); - navigate2TabItem(idx); - } - - maintabs.forEach(function (elem, index) { - let tabvalue = elem.innerText.replaceAll(" ", ""); - hiddentabs[tabvalue] = false; - headertabs[tabvalue] = false; - let checked_hidden = ""; - let checked_header = ""; - if (setting_ui_hidden_tabs.value.indexOf(tabvalue) != -1) { - hiddentabs[tabvalue] = true; - checked_hidden = "checked"; - } - if (setting_ui_header_tabs.value.indexOf(tabvalue) != -1) { - headertabs[tabvalue] = true; - checked_header = "checked"; - } - radio_hidden_html += - '"; - - radio_header_html += - '"; - - tabitems[index].setAttribute("tab-item", index); - elem.setAttribute("tab-id", index); - - let clonetab = elem.cloneNode(true); - clonetab.id = tabvalue + "_clone"; - parent_header_tabs.append(clonetab); - clonetab.addEventListener("click", navTabClicked); - }); - - let div = document.createElement("div"); - div.id = "hidden_radio_tabs_container"; - div.classList.add("flex", "flex-wrap", "gap-2", "wrap", "svelte-1qxcj04"); - div.innerHTML = radio_hidden_html; - setting_ui_hidden_tabs.parentElement.appendChild(div); - - div = document.createElement("div"); - div.id = "header_radio_tabs_container"; - div.classList.add("flex", "flex-wrap", "gap-2", "wrap", "svelte-1qxcj04"); - div.innerHTML = radio_header_html; - setting_ui_header_tabs.parentElement.appendChild(div); - - // hidden tabs - gradioApp() - .querySelector("#hidden_radio_tabs_container") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='checkbox']")) { - let tabvalue = e.target.value.replaceAll(" ", ""); - hiddentabs[tabvalue] = e.target.checked; - tabsHiddenChange(); - updateOpStyles(); - } - }); - // header tabs - gradioApp() - .querySelector("#header_radio_tabs_container") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='checkbox']")) { - let tabvalue = e.target.value.replaceAll(" ", ""); - headertabs[tabvalue] = e.target.checked; - tabsHeaderChange(); - updateOpStyles(); - } - }); - - tabsHiddenChange(); - - gradioApp() - .querySelectorAll('[id^="image_buttons_"] button, #png_2img_results button') - .forEach(function (elem) { - //console.log(opts.send_seed); - if (elem.id == "txt2img_tab") { - elem.setAttribute("tab-id", 0); - elem.addEventListener("click", navTabClicked); - } else if (elem.id == "img2img_tab" || elem.id == "inpaint_tab") { - elem.setAttribute("tab-id", 1); - elem.addEventListener("click", navTabClicked); - } - if (elem.id == "extras_tab") { - elem.setAttribute("tab-id", 2); - elem.addEventListener("click", navTabClicked); - } - }); - - gradioApp() - .querySelectorAll('[id$="2img_extra_tabs"] .search') - .forEach(function (elem) { - elem.addEventListener("keyup", function (e) { - if (e.defaultPrevented) { - return; // Do nothing if event already handled - } - switch (e.code) { - case "Escape": - if (e.target.value == "") { - net_menu.click(); - } else { - e.target.value = ""; - updateInput(e.target); + if (oldValue != newValue) { + opts = JSON.parse(textarea.value); } - break; + + executeCallbacks(optionsChangedCallbacks); + }, + get: function() { + var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value'); + return valueProp.get.call(textarea); } - }); }); - // add - remove quicksettings - const settings_submit = gradioApp().querySelector("#settings_submit"); - const quick_parent = gradioApp().querySelector( - "#quicksettings_overflow_container" - ); - const setting_quicksettings = gradioApp().querySelector( - "#setting_quicksettings textarea" - ); - function saveQuickSettings() { - updateInput(setting_quicksettings); - const cEvent = new Event("click"); //submit - Object.defineProperty(cEvent, "target", { value: settings_submit }); - settings_submit.dispatchEvent(cEvent); - console.log(setting_quicksettings.value); - } + json_elem.parentElement.style.display = "none"; - /* - function addModelCheckpoint(){ - if(setting_quicksettings.value.indexOf("sd_model_checkpoint") === -1){ - setting_quicksettings.value += ",sd_model_checkpoint"; - } - saveQuickSettings(); - } - */ + setupTokenCounters(); - function add2quickSettings(id, section, checked) { - let field_settings = setting_quicksettings.value.replace(" ", ""); - if (checked) { - field_settings += "," + id; - let setting_row = gradioApp().querySelector("#row_setting_" + id); - quick_parent.append(setting_row); - setting_row.classList.add("warning"); - } else { - field_settings = field_settings.replaceAll(id, ","); - const setting_parent = gradioApp().querySelector( - "#" + section + "_settings_2img_settings" - ); - let quick_row = gradioApp().querySelector("#row_setting_" + id); - setting_parent.append(quick_row); - quick_row.classList.remove("warning"); + var show_all_pages = gradioApp().getElementById('settings_show_all_pages'); + var settings_tabs = gradioApp().querySelector('#settings div'); + if (show_all_pages && settings_tabs) { + settings_tabs.appendChild(show_all_pages); + show_all_pages.onclick = function() { + gradioApp().querySelectorAll('#settings > div').forEach(function(elem) { + if (elem.id == "settings_tab_licenses") { + return; + } + + elem.style.display = "block"; + }); + }; } - field_settings = field_settings.replace(/,{2,}/g, ","); - setting_quicksettings.value = field_settings; - //addModelCheckpoint(); - saveQuickSettings(); - //console.log(section + " - " + id + " - " + checked); - } - gradioApp() - .querySelectorAll('[id*="add2quick_"]') - .forEach(function (elem) { - let trg = elem.id.split("_add2quick_setting_"); - let sid = trg[0]; - let tid = trg[1]; - let elem_input = gradioApp().querySelector("#" + elem.id + " input"); - if (elem_input) { - elem_input.addEventListener("click", function (e) { - add2quickSettings(tid, sid, e.target.checked); - }); - } - }); - //addModelCheckpoint(); - - // input release component dispatcher - let cached_clone_range; - let cached_clone_num; - let active_clone_input = []; - let focus_input; - - function ui_input_release_component(elem) { - //console.log("ok"); - if (active_clone_input.length > 0) return; - - //img2img_width - let parent = elem.parentElement; - let comp_parent = parent.parentElement.parentElement; - - if ( - comp_parent.id == "img2img_width" || - comp_parent.id == "img2img_height" || - comp_parent.id == "img2img_scale" || - comp_parent.id.indexOf("--ae-") != -1 || - comp_parent.id.indexOf("theme") != -1 || - comp_parent.className.indexOf("posex") != -1 - ) - return; - - let clone_num = elem.cloneNode(); - active_clone_input.push(clone_num); - - let label = parent.querySelector("label"); - - clone_num.id = "num_clone"; - clone_num.value = elem.value; - parent.append(clone_num); - elem.classList.add("hidden"); - - clone_num.addEventListener("change", function (e) { - elem.value = clone_num.value; - updateInput(elem); - }); - - clone_num.addEventListener("focus", function (e) { - focus_input = clone_num; - }); - - cached_clone_num = clone_num; - cached_clone_range = false; - - if (label) { - let comp_range = comp_parent.querySelector("input[type='range']"); - let clone_range = comp_range.cloneNode(); - active_clone_input.push(clone_range); - - clone_range.id = comp_range.id + "_clone"; - clone_range.value = comp_range.value; - comp_range.parentElement.append(clone_range); - comp_range.classList.add("hidden"); - - clone_range.addEventListener("input", function (e) { - clone_num.value = e.target.value; - }); - clone_range.addEventListener("change", function (e) { - elem.value = clone_range.value; - updateInput(elem); - }); - clone_num.addEventListener("input", function (e) { - clone_range.value = e.target.value; - }); - - cached_clone_range = clone_range; - } - } - /* function ui_input_focus_handler(e) { - if (e.target != focus_input) { - focus_input = false; - ui_input_release_handler(e); - } - } */ - - function ui_input_release_handler(e) { - const len = active_clone_input.length; - if (focus_input) { - return; - } - if (len > 0) { - if (e.target.id.indexOf("_clone") == -1) { - for (var i = len - 1; i >= 0; i--) { - let relem = active_clone_input[i]; - relem.previousElementSibling.classList.remove("hidden"); - relem.remove(); - active_clone_input.pop(); - } - } - } - - let elem_type = e.target.tagName; - if (elem_type == "INPUT") { - let elem = e.target; - if (elem.type == "number") { - ui_input_release_component(elem); - } else if (elem.type == "range") { - elem = e.target.parentElement.querySelector("input[type='number']"); - if (elem) { - ui_input_release_component(elem); - } - } - } - } - let timeoutId; - - function ui_input_touchmove_handler(e) { - if (cached_clone_range && cached_clone_num) { - if (e.touches) { - const rect = cached_clone_range.getBoundingClientRect(); - const xoffset_min = rect.left + window.scrollX; - //const xoffset_max = (rect.right + window.scrollX); - //const yoffset_min = (rect.top + window.scrollY); - //const yoffset_max = (rect.bottom + window.scrollY); - //if( e.touches[0].pageY > yoffset_min && e.touches[0].pageY < yoffset_max && e.touches[0].pageX > xoffset_min && e.touches[0].pageX < xoffset_max){ - e.preventDefault(); - const percent = - parseInt(((e.touches[0].pageX - xoffset_min) / rect.width) * 10000) / - 10000; - cached_clone_range.value = - percent * (cached_clone_range.max - cached_clone_range.min) + - parseFloat(cached_clone_range.min); - cached_clone_num.value = cached_clone_range.value; - //} - } - } - } - function ui_input_touchend_handler(e) { - if (cached_clone_range && cached_clone_num) { - const elem = cached_clone_range.previousElementSibling; - elem.value = cached_clone_range.value; - updateInput(elem); - } - } - - function slider_contextmenu(e) { - e.preventDefault(); - } - function slider_touchend(e) { - if (timeoutId) clearTimeout(timeoutId); - } - function slider_touchmove(e) { - if (timeoutId) clearTimeout(timeoutId); - } - function slider_touchstart(e) { - const gcontainer = e.target; - //gcontainer.removeEventListener('contextmenu', slider_contextmenu); - gcontainer.removeEventListener("touchend", slider_touchend); - gcontainer.removeEventListener("touchmove", slider_touchmove); - gcontainer.removeEventListener("touchend", ui_input_touchend_handler); - gcontainer.removeEventListener("touchmove", ui_input_touchmove_handler); - - timeoutId = setTimeout(function () { - timeoutId = null; - focus_input = false; - e.stopPropagation(); - ui_input_release_handler(e); - ui_input_touchmove_handler(e); - gcontainer.addEventListener("touchmove", ui_input_touchmove_handler, { - passive: false, - }); - gcontainer.addEventListener("touchend", ui_input_touchend_handler); - }, 500); - - //gcontainer.addEventListener('contextmenu', slider_contextmenu); - gcontainer.addEventListener("touchend", slider_touchend); - gcontainer.addEventListener("touchmove", slider_touchmove, { - passive: false, - }); - } - - function ui_dispatch_input_release(value) { - const gcontainer = gradioApp().querySelector(".gradio-container"); - if (value) { - gcontainer.addEventListener("mouseover", ui_input_release_handler); - gcontainer.addEventListener("touchstart", slider_touchstart, { - passive: false, - }); - } else { - gcontainer.removeEventListener("mouseover", ui_input_release_handler); - gcontainer.removeEventListener("touchstart", slider_touchstart); - //gcontainer.removeEventListener('contextmenu', slider_contextmenu); - gcontainer.removeEventListener("touchend", slider_touchend); - gcontainer.removeEventListener("touchmove", slider_touchmove); - gcontainer.removeEventListener("touchend", ui_input_touchend_handler); - gcontainer.removeEventListener("touchmove", ui_input_touchmove_handler); - } - } - gradioApp() - .querySelector("#setting_ui_dispatch_input_release input") - .addEventListener("click", function (e) { - ui_dispatch_input_release(e.target.checked); - }); - ui_dispatch_input_release(opts.ui_dispatch_input_release); - - // step ticks for performant input range - function ui_show_range_ticks(value, interactive) { - if (value) { - const range_selectors = "input[type='range']"; - //const range_selectors = "[id$='_clone']:is(input[type='range'])"; - gradioApp() - .querySelectorAll(range_selectors) - .forEach(function (elem) { - let spacing = (elem.step / (elem.max - elem.min)) * 100.0; - let tsp = "max(3px, calc(" + spacing + "% - 1px))"; - let fsp = "max(4px, calc(" + spacing + "% + 0px))"; - var style = elem.style; - style.setProperty( - "--ae-slider-bg-overlay", - "repeating-linear-gradient( 90deg, transparent, transparent " + - tsp + - ", var(--ae-input-border-color) " + - tsp + - ", var(--ae-input-border-color) " + - fsp + - " )" - ); - }); - } else if (interactive) { - gradioApp() - .querySelectorAll("input[type='range']") - .forEach(function (elem) { - var style = elem.style; - style.setProperty("--ae-slider-bg-overlay", "transparent"); - }); - } - } - gradioApp() - .querySelector("#setting_ui_show_range_ticks input") - .addEventListener("click", function (e) { - ui_show_range_ticks(e.target.checked, true); - }); - ui_show_range_ticks(opts.ui_show_range_ticks); - - const gradio_main = gradioApp().querySelector(".gradio-container > div.main"); - function ui_no_slider_layout(value) { - if (value) { - gradio_main.classList.add("no-slider-layout"); - } else { - gradio_main.classList.remove("no-slider-layout"); - } - } - gradioApp() - .querySelector("#setting_ui_no_slider_layout input") - .addEventListener("click", function (e) { - ui_no_slider_layout(e.target.checked, true); - }); - ui_no_slider_layout(opts.ui_no_slider_layout); - - // draggable reordable quicksettings - const container = gradioApp().querySelector( - "#quicksettings_overflow_container" - ); - let draggables; - let lastElemAfter; - let islastChild; - let timeout; - - function preventBehavior(e) { - e.stopPropagation(); - e.preventDefault(); - return false; - } - let sdCheckpointModels = []; - function getSdCheckpointModels() { - gradioApp() - .querySelectorAll("#txt2img_checkpoints_cards .card") - .forEach(function (elem, i) { - sdCheckpointModels[i] = elem.getAttribute("onclick").split('"')[1]; - }); - } - getSdCheckpointModels(); - - function remove_overrides() { - let checked_overrides = []; - gradioApp() - .querySelectorAll("#setting_ignore_overrides input") - .forEach(function (elem, i) { - if (elem.checked) { - checked_overrides[i] = elem.nextElementSibling.innerHTML; - } - }); - //console.log(checked_overrides); - gradioApp() - .querySelectorAll("[id$='2img_override_settings'] .token") - .forEach(function (token) { - let token_arr = token.querySelector("span").innerHTML.split(":"); - let token_name = token_arr[0]; - let token_value = token_arr[1]; - token_value = token_value.replaceAll(" ", ""); - - if (token_name.indexOf("Model hash") != -1) { - const info_label = gradioApp().querySelector( - "[id$='2img_override_settings'] label span" - ); - info_label.innerHTML = "Override settings MDL: unknown"; - for (let m = 0; m < sdCheckpointModels.length; m++) { - let m_str = sdCheckpointModels[m]; - if (m_str.indexOf(token_value) != -1) { - info_label.innerHTML = - "Override settings MDL: " + m_str.split("[")[0] + ""; - break; - } - } - } - if (checked_overrides.indexOf(token_name) != -1) { - token.querySelector(".token-remove").click(); - gradioApp() - .querySelector( - "#" + selectedTabItemId + " [id$='2img_override_settings']" - ) - .parentElement.classList.add("show"); - } else { - // maybe we add them again, for now we can select and add the removed tokens manually from the drop down - } - }); - } - gradioApp() - .querySelector("#setting_ignore_overrides") - .addEventListener("click", function (e) { - setTimeout(function () { - remove_overrides(); - }, 100); - }); - - function update_input_fields(tab) { - /* - let input_selectors = "#tab_"+ tab + " [id^='num_clone']:is(input[type='number'])"; - gradioApp().querySelectorAll(input_selectors).forEach(function (elem){ - let elem_source = elem.previousElementSibling; - elem.value = elem_source.value; - updateInput(elem); - }) - */ - remove_overrides(); - autoGrowPromptTextarea(); - } - - gradioApp() - .querySelectorAll( - "#tab_pnginfo #png_2img_results button, [id$='2img_actions_column'] #paste" - ) - .forEach(function (elem) { - elem.addEventListener("click", function (e) { - let button_id; - if (e.target.id == "paste") { - button_id = e.target.nextElementSibling.id.split("_")[0]; - } else { - button_id = e.target.id.split("_")[0]; - } - setTimeout(function () { - update_input_fields(button_id); - }, 500); - }); - }); - - const pnginfo = gradioApp().querySelector("#tab_pnginfo"); - function forwardFromPngInfo() { - if (selectedTabItemId == "tab_txt2img") { - pnginfo.querySelector("#txt2img_tab").click(); - //close generation info - gradioApp() - .querySelector( - "#txt2img_results > div:last-child > div.gradio-accordion > div.hide" - ) - ?.click(); - - const img_src = pnginfo.querySelector("img"); - const gallery_parent = gradioApp().querySelector( - "#txt2img_gallery_container" - ); - const live_preview = gallery_parent.querySelector(".livePreview"); - if (live_preview) { - live_preview.innerHTML = - ''; - } else { - const div = document.createElement("div"); - div.classList.add("livePreview", "dropPreview"); - div.innerHTML = - ''; - gallery_parent.prepend(div); - } - } else if (selectedTabItemId == "tab_img2img") { - pnginfo.querySelector("#img2img_tab").click(); - //close generation info - gradioApp() - .querySelector( - "#img2img_results > div:last-child > div.gradio-accordion > div.hide" - ) - ?.click(); - } - } - - function fetchPngInfoData(files) { - /* const oldFetch = window.fetch; - - window.fetch = async (input, options) => { - const response = await oldFetch(input, options); - if( 'run/predict/' === input ) { - if(response.ok){ - window.fetch = oldFetch; - } - } - return response; - }; */ - - const fileInput = gradioApp().querySelector( - '#pnginfo_image input[type="file"]' - ); - if (fileInput.files != files) { - fileInput.files = files; - fileInput.dispatchEvent(new Event("change")); - } - - setTimeout(function () { - forwardFromPngInfo(); - }, 500); - } - - function drop2View(e) { - e.stopPropagation(); - e.preventDefault(); - const files = e.dataTransfer.files; - - if (!isValidImageList(files)) { - return; - } - const data_image = gradioApp().querySelector( - '#pnginfo_image [data-testid="image"]' - ); - data_image.querySelector('[aria-label="Clear"]')?.click(); - setTimeout(function () { - fetchPngInfoData(files); - }, 1000); - } - - gradioApp() - .querySelectorAll('[id$="2img_results"]') - .forEach((elem) => { - elem.addEventListener("drop", drop2View); - }); - - // function that gets the element next of cursor/touch - function getElementAfter(container, y) { - return draggables.reduce( - (closest, child) => { - const box = child.getBoundingClientRect(); - const offset = y - box.top - box.height / 2; - if (offset < 0 && offset > closest.offset) { - return { offset: offset, element: child }; - } else { - return closest; - } - }, - { offset: Number.NEGATIVE_INFINITY } - ).element; - } - - function dragOrderChange(elementAfter, isComplete, delem) { - if (lastElemAfter !== elementAfter || islastChild) { - if (lastElemAfter != null) { - lastElemAfter.classList.remove("marker-top", "marker-bottom"); - } - - if (elementAfter == null) { - islastChild = true; - lastElemAfter.classList.add("marker-bottom"); - } else { - islastChild = false; - elementAfter.classList.add("marker-top"); - lastElemAfter = elementAfter; - } - } - - if (isComplete) { - if (elementAfter == null) { - container.append(delem); - } else { - container.insertBefore(delem, elementAfter); - } - - let order_settings = ""; - - gradioApp() - .querySelectorAll("#quicksettings_overflow_container > div") - .forEach(function (el) { - el.classList.remove("marker-top", "marker-bottom", "dragging"); - order_settings += el.id.split("row_setting_")[1] + ","; - }); - //console.log(order_settings); - const setting_quicksettings = gradioApp().querySelector( - "#setting_quicksettings textarea" - ); - setting_quicksettings.value = order_settings; - updateInput(setting_quicksettings); - - const cEvent = new Event("click"); //submit - Object.defineProperty(cEvent, "target", { value: settings_submit }); - settings_submit.dispatchEvent(cEvent); - - container.classList.remove("no-scroll"); - } - } - - function touchmove(e) { - let y = e.touches[0].clientY; - let elementAfter = getElementAfter(container, y); - dragOrderChange(elementAfter); - } - function touchstart(e) { - e.currentTarget.draggable = "false"; - let target = e.currentTarget; - // touch should be hold for 1 second - timeout = setTimeout(function () { - target.classList.add("dragging"); - container.classList.add("no-scroll"); - target.addEventListener("touchmove", touchmove); - container.addEventListener("touchmove", preventBehavior, { - passive: false, - }); - }, 1000); - - target.addEventListener("touchend", touchend); - target.addEventListener("touchcancel", touchcancel); - } - function touchend(e) { - e.currentTarget.draggable = "true"; - clearTimeout(timeout); - e.currentTarget.removeEventListener("touchmove", touchmove); - container.removeEventListener("touchmove", preventBehavior); - let y = e.changedTouches[0].clientY; - let elementAfter = getElementAfter(container, y); - dragOrderChange(elementAfter, true, e.currentTarget); - } - function touchcancel(e) { - e.currentTarget.draggable = "true"; - clearTimeout(timeout); - e.currentTarget.classList.remove("dragging"); - e.currentTarget.removeEventListener("touchmove", touchmove); - container.removeEventListener("touchmove", preventBehavior); - } - - function dragstart(e) { - e.currentTarget.draggable = "false"; - e.currentTarget.classList.add("dragging"); - } - function dragend(e) { - e.stopPropagation(); - e.preventDefault(); - e.currentTarget.draggable = "true"; - let y = e.clientY; - let elementAfter = getElementAfter(container, y); - dragOrderChange(elementAfter, true, e.currentTarget); - } - function dragOver(e) { - e.preventDefault(); - let y = e.clientY; - let elementAfter = getElementAfter(container, y); - dragOrderChange(elementAfter); - } - - function actionQuickSettingsDraggable(checked) { - if (checked) { - draggables = Array.from( - gradioApp().querySelectorAll( - "#quicksettings_overflow_container > div:not(.dragging)" - ) - ); - gradioApp().addEventListener("drop", preventBehavior); - } else { - gradioApp().removeEventListener("drop", preventBehavior); - } - - gradioApp() - .querySelectorAll("#quicksettings_overflow_container > div") - .forEach(function (elem) { - elem.draggable = checked; - if (checked) { - elem.addEventListener("touchstart", touchstart); - elem.addEventListener("dragstart", dragstart); - elem.addEventListener("dragend", dragend); - elem.addEventListener("dragover", dragOver); - } else { - elem.removeEventListener("touchstart", touchstart, false); - elem.removeEventListener("touchend", touchend, false); - elem.removeEventListener("touchcancel", touchcancel, false); - elem.removeEventListener("touchmove", touchmove, false); - elem.removeEventListener("dragstart", dragstart, false); - elem.removeEventListener("dragend", dragend, false); - elem.removeEventListener("dragover", dragOver, false); - } - }); - } - - gradioApp() - .querySelector("#quicksettings_draggable") - .addEventListener("click", function (e) { - if (e.target && e.target.matches("input[type='checkbox']")) { - actionQuickSettingsDraggable(e.target.checked); - } - }); - - updateOpStyles(); - - /* anapnoe ui end */ }); onOptionsChanged(function() { - var elem = gradioApp().getElementById('sd_checkpoint_hash'); - var sd_checkpoint_hash = opts.sd_checkpoint_hash || ""; - var shorthash = sd_checkpoint_hash.substring(0, 10); + var elem = gradioApp().getElementById('sd_checkpoint_hash'); + var sd_checkpoint_hash = opts.sd_checkpoint_hash || ""; + var shorthash = sd_checkpoint_hash.substring(0, 10); - if (elem && elem.textContent != shorthash) { - elem.textContent = shorthash; - elem.title = sd_checkpoint_hash; - elem.href = "https://google.com/search?q=" + sd_checkpoint_hash; - } + if (elem && elem.textContent != shorthash) { + elem.textContent = shorthash; + elem.title = sd_checkpoint_hash; + elem.href = "https://google.com/search?q=" + sd_checkpoint_hash; + } }); let txt2img_textarea, img2img_textarea = undefined; -let wait_time = 800; -let token_timeouts = {}; - -function update_txt2img_tokens(...args) { - update_token_counter("txt2img_token_button"); - if (args.length == 2) { - return args[0]; - } - return args; -} - -function update_img2img_tokens(...args) { - update_token_counter( - "img2img_token_button" - ); - if (args.length == 2) { - return args[0]; - } - return args; -} - -function update_token_counter(button_id) { - if (token_timeouts[button_id]) { - clearTimeout(token_timeouts[button_id]); - } - token_timeouts[button_id] = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time); -} - - function restart_reload() { - let bg_color = window - .getComputedStyle(gradioApp().querySelector("#header-top")) - .getPropertyValue("--ae-main-bg-color"); - let primary_color = window - .getComputedStyle(gradioApp().querySelector(".icon-info")) - .getPropertyValue("--ae-primary-color"); - let panel_color = window - .getComputedStyle(gradioApp().querySelector(".gradio-box")) - .getPropertyValue("--ae-panel-bg-color"); + document.body.innerHTML = '

Reloading...

'; - localStorage.setItem("bg_color", bg_color); - localStorage.setItem("primary_color", primary_color); - localStorage.setItem("panel_color", panel_color); + var requestPing = function() { + requestGet("./internal/ping", {}, function(data) { + location.reload(); + }, function() { + setTimeout(requestPing, 500); + }); + }; - if (localStorage.hasOwnProperty("bg_color")) { - bg_color = localStorage.getItem("bg_color"); - primary_color = localStorage.getItem("primary_color"); - panel_color = localStorage.getItem("panel_color"); - } + setTimeout(requestPing, 2000); - document.body.style.backgroundColor = bg_color; - - let style = document.createElement("style"); - style.type = "text/css"; - style.innerHTML = - ".loader{position:absolute;top:50vh;left:50vw;height:60px;width:160px;margin:0;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%)} .circles{position:absolute;left:-5px;top:0;height:60px;width:180px} .circles span{position:absolute;top:25px;height:12px;width:12px;border-radius:12px;background-color:" + - panel_color + - "} .circles span.one{right:80px} .circles span.two{right:40px} .circles span.three{right:0px} .circles{-webkit-animation:animcircles 0.5s infinite linear;animation:animcircles 0.5s infinite linear} @-webkit-keyframes animcircles{0%{-webkit-transform:translate(0px,0px);transform:translate(0px,0px)}100%{-webkit-transform:translate(-40px,0px);transform:translate(-40px,0px)}} @keyframes animcircles{0%{-webkit-transform:translate(0px,0px);transform:translate(0px,0px)}100%{-webkit-transform:translate(-40px,0px);transform:translate(-40px,0px)}} .pacman{position:absolute;left:0;top:0;height:60px;width:60px} .pacman .eye{position:absolute;top:10px;left:30px;height:7px;width:7px;border-radius:7px;background-color:" + - bg_color + - '} .pacman span{position:absolute;top:0;left:0;height:60px;width:60px} .pacman span::before{content:"";position:absolute;left:0;height:30px;width:60px;background-color:' + - primary_color + - "} .pacman .top::before{top:0;border-radius:60px 60px 0px 0px} .pacman .bottom::before{bottom:0;border-radius:0px 0px 60px 60px} .pacman .left::before{bottom:0;height:60px;width:30px;border-radius:60px 0px 0px 60px} .pacman .top{-webkit-animation:animtop 0.5s infinite;animation:animtop 0.5s infinite} @-webkit-keyframes animtop{0%,100%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}50%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}} @keyframes animtop{0%,100%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}50%{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}} .pacman .bottom{-webkit-animation:animbottom 0.5s infinite;animation:animbottom 0.5s infinite} @-webkit-keyframes animbottom{0%,100%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}50%{-webkit-transform:rotate(45deg);transform:rotate(45deg)}} @keyframes animbottom{0%,100%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}50%{-webkit-transform:rotate(45deg);transform:rotate(45deg)}}"; - - document.getElementsByTagName("head")[0].appendChild(style); - document.body.innerHTML = - '
'; - - var requestPing = function () { - requestGet( - "./internal/ping", - {}, - function (data) { - location.reload(); - }, - function () { - setTimeout(requestPing, 500); - } - ); - }; - - setTimeout(requestPing, 2000); - - return []; + return []; } // Simulate an `input` DOM event for Gradio Textbox component. Needed after you edit its contents in javascript, otherwise your edits // will only visible on web page and not sent to python. function updateInput(target) { - const e = new Event("input", { bubbles: true }); - Object.defineProperty(e, "target", { value: target }); - target.dispatchEvent(e); - const eb = new Event("blur"); - Object.defineProperty(eb, "target", { value: target }); - target.dispatchEvent(eb); + let e = new Event("input", {bubbles: true}); + Object.defineProperty(e, "target", {value: target}); + target.dispatchEvent(e); } -document.addEventListener("readystatechange", function (e) { - document.body.style.display = "none"; - if (localStorage.hasOwnProperty("bg_color")) { - document.getElementsByTagName("html")[0].style.backgroundColor = - localStorage.getItem("bg_color"); - document.body.style.backgroundColor = localStorage.getItem("bg_color"); - } -}); - -window.onload = function () { - document.getElementsByTagName("html")[0].style.backgroundColor = - localStorage.getItem("bg_color"); - document.body.style.backgroundColor = localStorage.getItem("bg_color"); - document.body.style.display = "none"; - document.body.classList.add("dark"); - setTimeout(function () { - document.body.style.display = "block"; - }, 1000); -}; var desiredCheckpointName = null; function selectCheckpoint(name) { @@ -2038,4 +365,4 @@ function switchWidthHeight(tabname) { updateInput(width); updateInput(height); return []; -} \ No newline at end of file +} diff --git a/javascript/ui_settings_hints.js b/javascript/ui_settings_hints.js index 0f3c6acd..d088f949 100644 --- a/javascript/ui_settings_hints.js +++ b/javascript/ui_settings_hints.js @@ -1,3 +1,5 @@ +// various hints and extra info for the settings tab + var settingsHintsSetup = false; onOptionsChanged(function() { diff --git a/modules/api/api.py b/modules/api/api.py index 606db179..e6edffe7 100644 --- a/modules/api/api.py +++ b/modules/api/api.py @@ -4,6 +4,8 @@ import os import time import datetime import uvicorn +import ipaddress +import requests import gradio as gr from threading import Lock from io import BytesIO @@ -15,7 +17,7 @@ from fastapi.encoders import jsonable_encoder from secrets import compare_digest import modules.shared as shared -from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart +from modules import sd_samplers, deepbooru, sd_hijack, images, scripts, ui, postprocessing, errors, restart, shared_items from modules.api import models from modules.shared import opts from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images @@ -23,8 +25,7 @@ from modules.textual_inversion.textual_inversion import create_embedding, train_ from modules.textual_inversion.preprocess import preprocess from modules.hypernetworks.hypernetwork import create_hypernetwork, train_hypernetwork from PIL import PngImagePlugin,Image -from modules.sd_models import checkpoints_list, unload_model_weights, reload_model_weights, checkpoint_aliases -from modules.sd_vae import vae_dict +from modules.sd_models import unload_model_weights, reload_model_weights, checkpoint_aliases from modules.sd_models_config import find_checkpoint_config_near_filename from modules.realesrgan_model import get_realesrgan_models from modules import devices @@ -56,7 +57,41 @@ def setUpscalers(req: dict): return reqDict +def verify_url(url): + """Returns True if the url refers to a global resource.""" + + import socket + from urllib.parse import urlparse + try: + parsed_url = urlparse(url) + domain_name = parsed_url.netloc + host = socket.gethostbyname_ex(domain_name) + for ip in host[2]: + ip_addr = ipaddress.ip_address(ip) + if not ip_addr.is_global: + return False + except Exception: + return False + + return True + + def decode_base64_to_image(encoding): + if encoding.startswith("http://") or encoding.startswith("https://"): + if not opts.api_enable_requests: + raise HTTPException(status_code=500, detail="Requests not allowed") + + if opts.api_forbid_local_requests and not verify_url(encoding): + raise HTTPException(status_code=500, detail="Request to local resource not allowed") + + headers = {'user-agent': opts.api_useragent} if opts.api_useragent else {} + response = requests.get(encoding, timeout=30, headers=headers) + try: + image = Image.open(BytesIO(response.content)) + return image + except Exception as e: + raise HTTPException(status_code=500, detail="Invalid image url") from e + if encoding.startswith("data:image/"): encoding = encoding.split(";")[1].split(",")[1] try: @@ -197,6 +232,7 @@ class Api: self.add_api_route("/sdapi/v1/prompt-styles", self.get_prompt_styles, methods=["GET"], response_model=List[models.PromptStyleItem]) self.add_api_route("/sdapi/v1/embeddings", self.get_embeddings, methods=["GET"], response_model=models.EmbeddingsResponse) self.add_api_route("/sdapi/v1/refresh-checkpoints", self.refresh_checkpoints, methods=["POST"]) + self.add_api_route("/sdapi/v1/refresh-vae", self.refresh_vae, methods=["POST"]) self.add_api_route("/sdapi/v1/create/embedding", self.create_embedding, methods=["POST"], response_model=models.CreateResponse) self.add_api_route("/sdapi/v1/create/hypernetwork", self.create_hypernetwork, methods=["POST"], response_model=models.CreateResponse) self.add_api_route("/sdapi/v1/preprocess", self.preprocess, methods=["POST"], response_model=models.PreprocessResponse) @@ -329,6 +365,7 @@ class Api: with self.queue_lock: with closing(StableDiffusionProcessingTxt2Img(sd_model=shared.sd_model, **args)) as p: + p.is_api = True p.scripts = script_runner p.outpath_grids = opts.outdir_txt2img_grids p.outpath_samples = opts.outdir_txt2img_samples @@ -343,6 +380,7 @@ class Api: processed = process_images(p) finally: shared.state.end() + shared.total_tqdm.clear() b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else [] @@ -388,6 +426,7 @@ class Api: with self.queue_lock: with closing(StableDiffusionProcessingImg2Img(sd_model=shared.sd_model, **args)) as p: p.init_images = [decode_base64_to_image(x) for x in init_images] + p.is_api = True p.scripts = script_runner p.outpath_grids = opts.outdir_img2img_grids p.outpath_samples = opts.outdir_img2img_samples @@ -402,6 +441,7 @@ class Api: processed = process_images(p) finally: shared.state.end() + shared.total_tqdm.clear() b64images = list(map(encode_pil_to_base64, processed.images)) if send_images else [] @@ -530,7 +570,7 @@ class Api: raise RuntimeError(f"model {checkpoint_name!r} not found") for k, v in req.items(): - shared.opts.set(k, v) + shared.opts.set(k, v, is_api=True) shared.opts.save(shared.config_filename) return @@ -562,10 +602,12 @@ class Api: ] def get_sd_models(self): - return [{"title": x.title, "model_name": x.model_name, "hash": x.shorthash, "sha256": x.sha256, "filename": x.filename, "config": find_checkpoint_config_near_filename(x)} for x in checkpoints_list.values()] + import modules.sd_models as sd_models + return [{"title": x.title, "model_name": x.model_name, "hash": x.shorthash, "sha256": x.sha256, "filename": x.filename, "config": find_checkpoint_config_near_filename(x)} for x in sd_models.checkpoints_list.values()] def get_sd_vaes(self): - return [{"model_name": x, "filename": vae_dict[x]} for x in vae_dict.keys()] + import modules.sd_vae as sd_vae + return [{"model_name": x, "filename": sd_vae.vae_dict[x]} for x in sd_vae.vae_dict.keys()] def get_hypernetworks(self): return [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks] @@ -608,6 +650,10 @@ class Api: with self.queue_lock: shared.refresh_checkpoints() + def refresh_vae(self): + with self.queue_lock: + shared_items.refresh_vae_list() + def create_embedding(self, args: dict): try: shared.state.begin(job="create_embedding") diff --git a/modules/api/models.py b/modules/api/models.py index bf97b1a3..6a574771 100644 --- a/modules/api/models.py +++ b/modules/api/models.py @@ -50,10 +50,12 @@ class PydanticModelGenerator: additional_fields = None, ): def field_type_generator(k, v): - # field_type = str if not overrides.get(k) else overrides[k]["type"] - # print(k, v.annotation, v.default) field_type = v.annotation + if field_type == 'Image': + # images are sent as base64 strings via API + field_type = 'str' + return Optional[field_type] def merge_class_params(class_): @@ -63,7 +65,6 @@ class PydanticModelGenerator: parameters = {**parameters, **inspect.signature(classes.__init__).parameters} return parameters - self._model_name = model_name self._class_data = merge_class_params(class_instance) @@ -72,7 +73,7 @@ class PydanticModelGenerator: field=underscore(k), field_alias=k, field_type=field_type_generator(k, v), - field_value=v.default + field_value=None if isinstance(v.default, property) else v.default ) for (k,v) in self._class_data.items() if k not in API_NOT_ALLOWED ] @@ -208,11 +209,9 @@ class PreprocessResponse(BaseModel): fields = {} for key, metadata in opts.data_labels.items(): value = opts.data.get(key) - optType = opts.typemap.get(type(metadata.default), type(metadata.default)) + optType = opts.typemap.get(type(metadata.default), type(metadata.default)) if metadata.default else Any - if metadata.default is None: - pass - elif metadata is not None: + if metadata is not None: fields.update({key: (Optional[optType], Field(default=metadata.default, description=metadata.label))}) else: fields.update({key: (Optional[optType], Field())}) diff --git a/modules/cache.py b/modules/cache.py index 71fe6302..ff26a213 100644 --- a/modules/cache.py +++ b/modules/cache.py @@ -1,11 +1,12 @@ import json +import os import os.path import threading import time from modules.paths import data_path, script_path -cache_filename = os.path.join(data_path, "cache.json") +cache_filename = os.environ.get('SD_WEBUI_CACHE_FILE', os.path.join(data_path, "cache.json")) cache_data = None cache_lock = threading.Lock() @@ -29,9 +30,12 @@ def dump_cache(): time.sleep(1) with cache_lock: - with open(cache_filename, "w", encoding="utf8") as file: + cache_filename_tmp = cache_filename + "-" + with open(cache_filename_tmp, "w", encoding="utf8") as file: json.dump(cache_data, file, indent=4) + os.replace(cache_filename_tmp, cache_filename) + dump_cache_after = None dump_cache_thread = None diff --git a/modules/call_queue.py b/modules/call_queue.py index 61aa240f..ddf0d573 100644 --- a/modules/call_queue.py +++ b/modules/call_queue.py @@ -1,11 +1,10 @@ from functools import wraps import html -import threading import time -from modules import shared, progress, errors +from modules import shared, progress, errors, devices, fifo_lock -queue_lock = threading.Lock() +queue_lock = fifo_lock.FIFOLock() def wrap_queued_call(func): @@ -75,6 +74,8 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False): error_message = f'{type(e).__name__}: {e}' res = extra_outputs_array + [f"
{html.escape(error_message)}
"] + devices.torch_gc() + shared.state.skipped = False shared.state.interrupted = False shared.state.job_count = 0 diff --git a/modules/cmd_args.py b/modules/cmd_args.py index dd5fadc4..aab62286 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -16,6 +16,8 @@ parser.add_argument("--test-server", action='store_true', help="launch.py argume parser.add_argument("--log-startup", action='store_true', help="launch.py argument: print a detailed log of what's happening at startup") parser.add_argument("--skip-prepare-environment", action='store_true', help="launch.py argument: skip all environment preparation") parser.add_argument("--skip-install", action='store_true', help="launch.py argument: skip installation of packages") +parser.add_argument("--dump-sysinfo", action='store_true', help="launch.py argument: dump limited sysinfo file (without information about extensions, options) to disk and quit") +parser.add_argument("--loglevel", type=str, help="log level; one of: CRITICAL, ERROR, WARNING, INFO, DEBUG", default=None) parser.add_argument("--do-not-download-clip", action='store_true', help="do not download CLIP model even if it's not included in the checkpoint") parser.add_argument("--data-dir", type=str, default=os.path.dirname(os.path.dirname(os.path.realpath(__file__))), help="base path where all user data is stored") parser.add_argument("--config", type=str, default=sd_default_config, help="path to config which constructs model",) @@ -34,9 +36,10 @@ parser.add_argument("--hypernetwork-dir", type=str, default=os.path.join(models_ parser.add_argument("--localizations-dir", type=str, default=os.path.join(script_path, 'localizations'), help="localizations directory") parser.add_argument("--allow-code", action='store_true', help="allow custom script execution from webui") parser.add_argument("--medvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a little speed for low VRM usage") +parser.add_argument("--medvram-sdxl", action='store_true', help="enable --medvram optimization just for SDXL models") parser.add_argument("--lowvram", action='store_true', help="enable stable diffusion model optimizations for sacrificing a lot of speed for very low VRM usage") parser.add_argument("--lowram", action='store_true', help="load stable diffusion checkpoint weights to VRAM instead of RAM") -parser.add_argument("--always-batch-cond-uncond", action='store_true', help="disables cond/uncond batching that is enabled to save memory with --medvram or --lowvram") +parser.add_argument("--always-batch-cond-uncond", action='store_true', help="does not do anything") parser.add_argument("--unload-gfpgan", action='store_true', help="does not do anything.") parser.add_argument("--precision", type=str, help="evaluate at this precision", choices=["full", "autocast"], default="autocast") parser.add_argument("--upcast-sampling", action='store_true', help="upcast sampling. No effect with --no-half. Usually produces similar results to --no-half with better performance while using less memory.") @@ -67,6 +70,7 @@ parser.add_argument("--opt-sdp-no-mem-attention", action='store_true', help="pre parser.add_argument("--disable-opt-split-attention", action='store_true', help="prefer no cross-attention layer optimization for automatic choice of optimization") parser.add_argument("--disable-nan-check", action='store_true', help="do not check if produced images/latent spaces have nans; useful for running without a checkpoint in CI") parser.add_argument("--use-cpu", nargs='+', help="use CPU as torch device for specified modules", default=[], type=str.lower) +parser.add_argument("--disable-model-loading-ram-optimization", action='store_true', help="disable an optimization that reduces RAM use when loading a model") parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests") parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None) parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False) @@ -79,7 +83,7 @@ parser.add_argument("--gradio-auth", type=str, help='set gradio authentication l parser.add_argument("--gradio-auth-path", type=str, help='set gradio authentication file path ex. "/path/to/auth/file" same auth format as --gradio-auth', default=None) parser.add_argument("--gradio-img2img-tool", type=str, help='does not do anything') parser.add_argument("--gradio-inpaint-tool", type=str, help="does not do anything") -parser.add_argument("--gradio-allowed-path", action='append', help="add path to gradio's allowed_paths, make it possible to serve files from it") +parser.add_argument("--gradio-allowed-path", action='append', help="add path to gradio's allowed_paths, make it possible to serve files from it", default=[data_path]) parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last") parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(data_path, 'styles.csv')) parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False) @@ -111,3 +115,5 @@ parser.add_argument('--subpath', type=str, help='customize the subpath for gradi parser.add_argument('--add-stop-route', action='store_true', help='add /_stop route to stop server') parser.add_argument('--api-server-stop', action='store_true', help='enable server stop/restart/kill via api') parser.add_argument('--timeout-keep-alive', type=int, default=30, help='set timeout_keep_alive for uvicorn') +parser.add_argument("--disable-all-extensions", action='store_true', help="prevent all extensions from running regardless of any other settings", default=False) +parser.add_argument("--disable-extra-extensions", action='store_true', help=" prevent all extensions except built-in from running regardless of any other settings", default=False) diff --git a/modules/config_states.py b/modules/config_states.py index 6f1ab53f..b766aef1 100644 --- a/modules/config_states.py +++ b/modules/config_states.py @@ -8,14 +8,12 @@ import time import tqdm from datetime import datetime -from collections import OrderedDict import git from modules import shared, extensions, errors from modules.paths_internal import script_path, config_states_dir - -all_config_states = OrderedDict() +all_config_states = {} def list_config_states(): @@ -28,10 +26,14 @@ def list_config_states(): for filename in os.listdir(config_states_dir): if filename.endswith(".json"): path = os.path.join(config_states_dir, filename) - with open(path, "r", encoding="utf-8") as f: - j = json.load(f) - j["filepath"] = path - config_states.append(j) + try: + with open(path, "r", encoding="utf-8") as f: + j = json.load(f) + assert "created_at" in j, '"created_at" does not exist' + j["filepath"] = path + config_states.append(j) + except Exception as e: + print(f'[ERROR]: Config states {path}, {e}') config_states = sorted(config_states, key=lambda cs: cs["created_at"], reverse=True) diff --git a/modules/devices.py b/modules/devices.py index 57e51da3..c01f0602 100644 --- a/modules/devices.py +++ b/modules/devices.py @@ -3,7 +3,7 @@ import contextlib from functools import lru_cache import torch -from modules import errors +from modules import errors, shared if sys.platform == "darwin": from modules import mac_specific @@ -17,8 +17,6 @@ def has_mps() -> bool: def get_cuda_device_string(): - from modules import shared - if shared.cmd_opts.device_id is not None: return f"cuda:{shared.cmd_opts.device_id}" @@ -40,8 +38,6 @@ def get_optimal_device(): def get_device_for(task): - from modules import shared - if task in shared.cmd_opts.use_cpu: return cpu @@ -71,14 +67,17 @@ def enable_tf32(): torch.backends.cudnn.allow_tf32 = True - errors.run(enable_tf32, "Enabling TF32") -cpu = torch.device("cpu") -device = device_interrogate = device_gfpgan = device_esrgan = device_codeformer = None -dtype = torch.float16 -dtype_vae = torch.float16 -dtype_unet = torch.float16 +cpu: torch.device = torch.device("cpu") +device: torch.device = None +device_interrogate: torch.device = None +device_gfpgan: torch.device = None +device_esrgan: torch.device = None +device_codeformer: torch.device = None +dtype: torch.dtype = torch.float16 +dtype_vae: torch.dtype = torch.float16 +dtype_unet: torch.dtype = torch.float16 unet_needs_upcast = False @@ -90,26 +89,10 @@ def cond_cast_float(input): return input.float() if unet_needs_upcast else input -def randn(seed, shape): - from modules.shared import opts - - torch.manual_seed(seed) - if opts.randn_source == "CPU" or device.type == 'mps': - return torch.randn(shape, device=cpu).to(device) - return torch.randn(shape, device=device) - - -def randn_without_seed(shape): - from modules.shared import opts - - if opts.randn_source == "CPU" or device.type == 'mps': - return torch.randn(shape, device=cpu).to(device) - return torch.randn(shape, device=device) +nv_rng = None def autocast(disable=False): - from modules import shared - if disable: return contextlib.nullcontext() @@ -128,8 +111,6 @@ class NansException(Exception): def test_for_nans(x, where): - from modules import shared - if shared.cmd_opts.disable_nan_check: return @@ -169,3 +150,4 @@ def first_time_calculation(): x = torch.zeros((1, 1, 3, 3)).to(device, dtype) conv2d = torch.nn.Conv2d(1, 1, (3, 3)).to(device, dtype) conv2d(x) + diff --git a/modules/errors.py b/modules/errors.py index 5271a9fe..8c339464 100644 --- a/modules/errors.py +++ b/modules/errors.py @@ -14,7 +14,8 @@ def record_exception(): if exception_records and exception_records[-1] == e: return - exception_records.append((e, tb)) + from modules import sysinfo + exception_records.append(sysinfo.format_exception(e, tb)) if len(exception_records) > 5: exception_records.pop(0) @@ -83,3 +84,53 @@ def run(code, task): code() except Exception as e: display(task, e) + + +def check_versions(): + from packaging import version + from modules import shared + + import torch + import gradio + + expected_torch_version = "2.0.0" + expected_xformers_version = "0.0.20" + expected_gradio_version = "3.41.2" + + if version.parse(torch.__version__) < version.parse(expected_torch_version): + print_error_explanation(f""" +You are running torch {torch.__version__}. +The program is tested to work with torch {expected_torch_version}. +To reinstall the desired version, run with commandline flag --reinstall-torch. +Beware that this will cause a lot of large files to be downloaded, as well as +there are reports of issues with training tab on the latest version. + +Use --skip-version-check commandline argument to disable this check. + """.strip()) + + if shared.xformers_available: + import xformers + + if version.parse(xformers.__version__) < version.parse(expected_xformers_version): + print_error_explanation(f""" +You are running xformers {xformers.__version__}. +The program is tested to work with xformers {expected_xformers_version}. +To reinstall the desired version, run with commandline flag --reinstall-xformers. + +Use --skip-version-check commandline argument to disable this check. + """.strip()) + + if gradio.__version__ != expected_gradio_version: + print_error_explanation(f""" +You are running gradio {gradio.__version__}. +The program is designed to work with gradio {expected_gradio_version}. +Using a different version of gradio is extremely likely to break the program. + +Reasons why you have the mismatched gradio version can be: + - you use --skip-install flag. + - you use webui.py to start the program instead of launch.py. + - an extension installs the incompatible gradio version. + +Use --skip-version-check commandline argument to disable this check. + """.strip()) + diff --git a/modules/extensions.py b/modules/extensions.py index 09d1e550..bf9a1878 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -1,7 +1,7 @@ import os import threading -from modules import shared, errors, cache +from modules import shared, errors, cache, scripts from modules.gitpython_hack import Repo from modules.paths_internal import extensions_dir, extensions_builtin_dir, script_path # noqa: F401 @@ -11,9 +11,9 @@ os.makedirs(extensions_dir, exist_ok=True) def active(): - if shared.opts.disable_all_extensions == "all": + if shared.cmd_opts.disable_all_extensions or shared.opts.disable_all_extensions == "all": return [] - elif shared.opts.disable_all_extensions == "extra": + elif shared.cmd_opts.disable_extra_extensions or shared.opts.disable_all_extensions == "extra": return [x for x in extensions if x.enabled and x.is_builtin] else: return [x for x in extensions if x.enabled] @@ -61,7 +61,7 @@ class Extension: self.from_dict(d) except FileNotFoundError: pass - self.status = 'unknown' + self.status = 'unknown' if self.status == '' else self.status def do_read_info_from_repo(self): repo = None @@ -90,8 +90,6 @@ class Extension: self.have_info_from_repo = True def list_files(self, subdir, extension): - from modules import scripts - dirpath = os.path.join(self.path, subdir) if not os.path.isdir(dirpath): return [] @@ -141,8 +139,12 @@ def list_extensions(): if not os.path.isdir(extensions_dir): return - if shared.opts.disable_all_extensions == "all": + if shared.cmd_opts.disable_all_extensions: + print("*** \"--disable-all-extensions\" arg was used, will not load any extensions ***") + elif shared.opts.disable_all_extensions == "all": print("*** \"Disable all extensions\" option was set, will not load any extensions ***") + elif shared.cmd_opts.disable_extra_extensions: + print("*** \"--disable-extra-extensions\" arg was used, will only load built-in extensions ***") elif shared.opts.disable_all_extensions == "extra": print("*** \"Disable all extensions\" option was set, will only load built-in extensions ***") diff --git a/modules/extra_networks.py b/modules/extra_networks.py index 6ae07e91..b9533677 100644 --- a/modules/extra_networks.py +++ b/modules/extra_networks.py @@ -1,4 +1,7 @@ +import json +import os import re +import logging from collections import defaultdict from modules import errors @@ -84,27 +87,55 @@ class ExtraNetwork: raise NotImplementedError +def lookup_extra_networks(extra_network_data): + """returns a dict mapping ExtraNetwork objects to lists of arguments for those extra networks. + + Example input: + { + 'lora': [], + 'lyco': [], + 'hypernet': [] + } + + Example output: + + { + : [, ], + : [] + } + """ + + res = {} + + for extra_network_name, extra_network_args in list(extra_network_data.items()): + extra_network = extra_network_registry.get(extra_network_name, None) + alias = extra_network_aliases.get(extra_network_name, None) + + if alias is not None and extra_network is None: + extra_network = alias + + if extra_network is None: + logging.info(f"Skipping unknown extra network: {extra_network_name}") + continue + + res.setdefault(extra_network, []).extend(extra_network_args) + + return res + + def activate(p, extra_network_data): """call activate for extra networks in extra_network_data in specified order, then call activate for all remaining registered networks with an empty argument list""" activated = [] - for extra_network_name, extra_network_args in extra_network_data.items(): - extra_network = extra_network_registry.get(extra_network_name, None) - - if extra_network is None: - extra_network = extra_network_aliases.get(extra_network_name, None) - - if extra_network is None: - print(f"Skipping unknown extra network: {extra_network_name}") - continue + for extra_network, extra_network_args in lookup_extra_networks(extra_network_data).items(): try: extra_network.activate(p, extra_network_args) activated.append(extra_network) except Exception as e: - errors.display(e, f"activating extra network {extra_network_name} with arguments {extra_network_args}") + errors.display(e, f"activating extra network {extra_network.name} with arguments {extra_network_args}") for extra_network_name, extra_network in extra_network_registry.items(): if extra_network in activated: @@ -123,19 +154,16 @@ def deactivate(p, extra_network_data): """call deactivate for extra networks in extra_network_data in specified order, then call deactivate for all remaining registered networks""" - for extra_network_name in extra_network_data: - extra_network = extra_network_registry.get(extra_network_name, None) - if extra_network is None: - continue + data = lookup_extra_networks(extra_network_data) + for extra_network in data: try: extra_network.deactivate(p) except Exception as e: - errors.display(e, f"deactivating extra network {extra_network_name}") + errors.display(e, f"deactivating extra network {extra_network.name}") for extra_network_name, extra_network in extra_network_registry.items(): - args = extra_network_data.get(extra_network_name, None) - if args is not None: + if extra_network in data: continue try: @@ -177,3 +205,20 @@ def parse_prompts(prompts): return res, extra_data + +def get_user_metadata(filename): + if filename is None: + return {} + + basename, ext = os.path.splitext(filename) + metadata_filename = basename + '.json' + + metadata = {} + try: + if os.path.isfile(metadata_filename): + with open(metadata_filename, "r", encoding="utf8") as file: + metadata = json.load(file) + except Exception as e: + errors.display(e, f"reading extra network user metadata from {metadata_filename}") + + return metadata diff --git a/modules/extras.py b/modules/extras.py index e9c0263e..2a310ae3 100644 --- a/modules/extras.py +++ b/modules/extras.py @@ -7,7 +7,7 @@ import json import torch import tqdm -from modules import shared, images, sd_models, sd_vae, sd_models_config +from modules import shared, images, sd_models, sd_vae, sd_models_config, errors from modules.ui_common import plaintext_to_html import gradio as gr import safetensors.torch @@ -72,7 +72,20 @@ def to_half(tensor, enable): return tensor -def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, save_metadata): +def read_metadata(primary_model_name, secondary_model_name, tertiary_model_name): + metadata = {} + + for checkpoint_name in [primary_model_name, secondary_model_name, tertiary_model_name]: + checkpoint_info = sd_models.checkpoints_list.get(checkpoint_name, None) + if checkpoint_info is None: + continue + + metadata.update(checkpoint_info.metadata) + + return json.dumps(metadata, indent=4, ensure_ascii=False) + + +def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format, config_source, bake_in_vae, discard_weights, save_metadata, add_merge_recipe, copy_metadata_fields, metadata_json): shared.state.begin(job="model-merge") def fail(message): @@ -241,11 +254,25 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ shared.state.textinfo = "Saving" print(f"Saving to {output_modelname}...") - metadata = None + metadata = {} + + if save_metadata and copy_metadata_fields: + if primary_model_info: + metadata.update(primary_model_info.metadata) + if secondary_model_info: + metadata.update(secondary_model_info.metadata) + if tertiary_model_info: + metadata.update(tertiary_model_info.metadata) if save_metadata: - metadata = {"format": "pt"} + try: + metadata.update(json.loads(metadata_json)) + except Exception as e: + errors.display(e, "readin metadata from json") + metadata["format"] = "pt" + + if save_metadata and add_merge_recipe: merge_recipe = { "type": "webui", # indicate this model was merged with webui's built-in merger "primary_model_hash": primary_model_info.sha256, @@ -261,7 +288,6 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ "is_inpainting": result_is_inpainting_model, "is_instruct_pix2pix": result_is_instruct_pix2pix_model } - metadata["sd_merge_recipe"] = json.dumps(merge_recipe) sd_merge_models = {} @@ -281,11 +307,12 @@ def run_modelmerger(id_task, primary_model_name, secondary_model_name, tertiary_ if tertiary_model_info: add_model_metadata(tertiary_model_info) + metadata["sd_merge_recipe"] = json.dumps(merge_recipe) metadata["sd_merge_models"] = json.dumps(sd_merge_models) _, extension = os.path.splitext(output_modelname) if extension.lower() == ".safetensors": - safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata) + safetensors.torch.save_file(theta_0, output_modelname, metadata=metadata if len(metadata)>0 else None) else: torch.save(theta_0, output_modelname) diff --git a/modules/fifo_lock.py b/modules/fifo_lock.py new file mode 100644 index 00000000..c35b3ae2 --- /dev/null +++ b/modules/fifo_lock.py @@ -0,0 +1,37 @@ +import threading +import collections + + +# reference: https://gist.github.com/vitaliyp/6d54dd76ca2c3cdfc1149d33007dc34a +class FIFOLock(object): + def __init__(self): + self._lock = threading.Lock() + self._inner_lock = threading.Lock() + self._pending_threads = collections.deque() + + def acquire(self, blocking=True): + with self._inner_lock: + lock_acquired = self._lock.acquire(False) + if lock_acquired: + return True + elif not blocking: + return False + + release_event = threading.Event() + self._pending_threads.append(release_event) + + release_event.wait() + return self._lock.acquire() + + def release(self): + with self._inner_lock: + if self._pending_threads: + release_event = self._pending_threads.popleft() + release_event.set() + + self._lock.release() + + __enter__ = acquire + + def __exit__(self, t, v, tb): + self.release() diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py index 88f4381b..d39f2eba 100644 --- a/modules/generation_parameters_copypaste.py +++ b/modules/generation_parameters_copypaste.py @@ -6,10 +6,10 @@ import re import gradio as gr from modules.paths import data_path -from modules import shared, ui_tempdir, script_callbacks +from modules import shared, ui_tempdir, script_callbacks, processing from PIL import Image -re_param_code = r'\s*([\w ]+):\s*("(?:\\"[^,]|\\"|\\|[^\"])+"|[^,]*)(?:,|$)' +re_param_code = r'\s*([\w ]+):\s*("(?:\\.|[^\\"])+"|[^,]*)(?:,|$)' re_param = re.compile(re_param_code) re_imagesize = re.compile(r"^(\d+)x(\d+)$") re_hypernet_hash = re.compile("\(([0-9a-f]+)\)$") @@ -32,6 +32,7 @@ class ParamBinding: def reset(): paste_fields.clear() + registered_param_bindings.clear() def quote(text): @@ -198,7 +199,6 @@ def restore_old_hires_fix_params(res): height = int(res.get("Size-2", 512)) if firstpass_width == 0 or firstpass_height == 0: - from modules import processing firstpass_width, firstpass_height = processing.old_hires_fix_first_pass_dimensions(width, height) res['Size-1'] = firstpass_width @@ -280,6 +280,9 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model if "Hires sampler" not in res: res["Hires sampler"] = "Use same sampler" + if "Hires checkpoint" not in res: + res["Hires checkpoint"] = "Use same checkpoint" + if "Hires prompt" not in res: res["Hires prompt"] = "" @@ -304,32 +307,28 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model if "Schedule rho" not in res: res["Schedule rho"] = 0 + if "VAE Encoder" not in res: + res["VAE Encoder"] = "Full" + + if "VAE Decoder" not in res: + res["VAE Decoder"] = "Full" + return res infotext_to_setting_name_mapping = [ - ('Clip skip', 'CLIP_stop_at_last_layers', ), + +] +"""Mapping of infotext labels to setting names. Only left for backwards compatibility - use OptionInfo(..., infotext='...') instead. +Example content: + +infotext_to_setting_name_mapping = [ ('Conditional mask weight', 'inpainting_mask_weight'), ('Model hash', 'sd_model_checkpoint'), ('ENSD', 'eta_noise_seed_delta'), ('Schedule type', 'k_sched_type'), - ('Schedule max sigma', 'sigma_max'), - ('Schedule min sigma', 'sigma_min'), - ('Schedule rho', 'rho'), - ('Noise multiplier', 'initial_noise_multiplier'), - ('Eta', 'eta_ancestral'), - ('Eta DDIM', 'eta_ddim'), - ('Discard penultimate sigma', 'always_discard_next_to_last_sigma'), - ('UniPC variant', 'uni_pc_variant'), - ('UniPC skip type', 'uni_pc_skip_type'), - ('UniPC order', 'uni_pc_order'), - ('UniPC lower order final', 'uni_pc_lower_order_final'), - ('Token merging ratio', 'token_merging_ratio'), - ('Token merging ratio hr', 'token_merging_ratio_hr'), - ('RNG', 'randn_source'), - ('NGMS', 's_min_uncond'), - ('Pad conds', 'pad_cond_uncond'), ] +""" def create_override_settings_dict(text_pairs): @@ -350,7 +349,8 @@ def create_override_settings_dict(text_pairs): params[k] = v.strip() - for param_name, setting_name in infotext_to_setting_name_mapping: + mapping = [(info.infotext, k) for k, info in shared.opts.data_labels.items() if info.infotext] + for param_name, setting_name in mapping + infotext_to_setting_name_mapping: value = params.get(param_name, None) if value is None: @@ -399,14 +399,20 @@ def connect_paste(button, paste_fields, input_comp, override_settings_component, return res if override_settings_component is not None: + already_handled_fields = {key: 1 for _, key in paste_fields} + def paste_settings(params): vals = {} - for param_name, setting_name in infotext_to_setting_name_mapping: + mapping = [(info.infotext, k) for k, info in shared.opts.data_labels.items() if info.infotext] + for param_name, setting_name in mapping + infotext_to_setting_name_mapping: + if param_name in already_handled_fields: + continue + v = params.get(param_name, None) if v is None: continue - + if setting_name == "sd_model_checkpoint" and shared.opts.disable_weights_auto_swap: continue @@ -416,7 +422,7 @@ def connect_paste(button, paste_fields, input_comp, override_settings_component, if v == current_value: continue - vals[param_name] = v + vals[param_name] = v vals_pairs = [f"{k}: {v}" for k, v in vals.items()] diff --git a/modules/gradio_extensons.py b/modules/gradio_extensons.py new file mode 100644 index 00000000..aac742ef --- /dev/null +++ b/modules/gradio_extensons.py @@ -0,0 +1,73 @@ +import gradio as gr + +from modules import scripts, ui_tempdir, patches + + +def add_classes_to_gradio_component(comp): + """ + this adds gradio-* to the component for css styling (ie gradio-button to gr.Button), as well as some others + """ + + comp.elem_classes = [f"gradio-{comp.get_block_name()}", *(comp.elem_classes or [])] + + if getattr(comp, 'multiselect', False): + comp.elem_classes.append('multiselect') + + +def IOComponent_init(self, *args, **kwargs): + self.webui_tooltip = kwargs.pop('tooltip', None) + + if scripts.scripts_current is not None: + scripts.scripts_current.before_component(self, **kwargs) + + scripts.script_callbacks.before_component_callback(self, **kwargs) + + res = original_IOComponent_init(self, *args, **kwargs) + + add_classes_to_gradio_component(self) + + scripts.script_callbacks.after_component_callback(self, **kwargs) + + if scripts.scripts_current is not None: + scripts.scripts_current.after_component(self, **kwargs) + + return res + + +def Block_get_config(self): + config = original_Block_get_config(self) + + webui_tooltip = getattr(self, 'webui_tooltip', None) + if webui_tooltip: + config["webui_tooltip"] = webui_tooltip + + config.pop('example_inputs', None) + + return config + + +def BlockContext_init(self, *args, **kwargs): + res = original_BlockContext_init(self, *args, **kwargs) + + add_classes_to_gradio_component(self) + + return res + + +def Blocks_get_config_file(self, *args, **kwargs): + config = original_Blocks_get_config_file(self, *args, **kwargs) + + for comp_config in config["components"]: + if "example_inputs" in comp_config: + comp_config["example_inputs"] = {"serialized": []} + + return config + + +original_IOComponent_init = patches.patch(__name__, obj=gr.components.IOComponent, field="__init__", replacement=IOComponent_init) +original_Block_get_config = patches.patch(__name__, obj=gr.blocks.Block, field="get_config", replacement=Block_get_config) +original_BlockContext_init = patches.patch(__name__, obj=gr.blocks.BlockContext, field="__init__", replacement=BlockContext_init) +original_Blocks_get_config_file = patches.patch(__name__, obj=gr.blocks.Blocks, field="get_config_file", replacement=Blocks_get_config_file) + + +ui_tempdir.install_ui_tempdir_override() diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py index c4821d21..70f1cbd2 100644 --- a/modules/hypernetworks/hypernetwork.py +++ b/modules/hypernetworks/hypernetwork.py @@ -10,7 +10,7 @@ import torch import tqdm from einops import rearrange, repeat from ldm.util import default -from modules import devices, processing, sd_models, shared, sd_samplers, hashes, sd_hijack_checkpoint, errors +from modules import devices, sd_models, shared, sd_samplers, hashes, sd_hijack_checkpoint, errors from modules.textual_inversion import textual_inversion, logging from modules.textual_inversion.learn_schedule import LearnRateScheduler from torch import einsum @@ -469,8 +469,7 @@ def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, def train_hypernetwork(id_task, hypernetwork_name, learn_rate, batch_size, gradient_step, data_root, log_directory, training_width, training_height, varsize, steps, clip_grad_mode, clip_grad_value, shuffle_tags, tag_drop_out, latent_sampling_method, use_weight, create_image_every, save_hypernetwork_every, template_filename, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height): - # images allows training previews to have infotext. Importing it at the top causes a circular import problem. - from modules import images + from modules import images, processing save_hypernetwork_every = save_hypernetwork_every or 0 create_image_every = create_image_every or 0 diff --git a/modules/images.py b/modules/images.py index 38aa933d..eb644733 100644 --- a/modules/images.py +++ b/modules/images.py @@ -21,8 +21,6 @@ from modules import sd_samplers, shared, script_callbacks, errors from modules.paths_internal import roboto_ttf_file from modules.shared import opts -import modules.sd_vae as sd_vae - LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) @@ -318,7 +316,7 @@ def resize_image(resize_mode, im, width, height, upscaler_name=None): return res -invalid_filename_chars = '<>:"/\\|?*\n' +invalid_filename_chars = '<>:"/\\|?*\n\r\t' invalid_filename_prefix = ' ' invalid_filename_postfix = ' .' re_nonletters = re.compile(r'[\s' + string.punctuation + ']+') @@ -342,16 +340,6 @@ def sanitize_filename_part(text, replace_spaces=True): class FilenameGenerator: - def get_vae_filename(self): #get the name of the VAE file. - if sd_vae.loaded_vae_file is None: - return "NoneType" - file_name = os.path.basename(sd_vae.loaded_vae_file) - split_file_name = file_name.split('.') - if len(split_file_name) > 1 and split_file_name[0] == '': - return split_file_name[1] # if the first character of the filename is "." then [1] is obtained. - else: - return split_file_name[0] - replacements = { 'seed': lambda self: self.seed if self.seed is not None else '', 'seed_first': lambda self: self.seed if self.p.batch_size == 1 else self.p.all_seeds[0], @@ -367,7 +355,9 @@ class FilenameGenerator: 'date': lambda self: datetime.datetime.now().strftime('%Y-%m-%d'), 'datetime': lambda self, *args: self.datetime(*args), # accepts formats: [datetime], [datetime], [datetime