Final version

This commit is contained in:
altoiddealer
2024-03-20 15:01:03 -04:00
parent 1cc7212be0
commit e6f150ec19
5 changed files with 418 additions and 446 deletions

View File

@@ -0,0 +1,18 @@
if ("undefined" === typeof arsp__ar_button_titles) {
arsp__ar_button_titles = {};
}
arsp__ar_button_titles[" \u{1F513}"] = 'Toggle to lock the "average" width/height values in the UI\nIt is recommended to "Lock" when switching between ARs in "Offset" mode.\n\n\u{1F512} = Locked\n\u{1F513} = Unlocked';
arsp__ar_button_titles[" \u{025AD}"] = 'For "Offset mode" (default):\n\u{025AF} = Portrait resolutions\n\u{025AD} = Landscape resolutions\n\nFor "One Dimension" mode:\n\u{025AD} = Modify Width\n\u{025AF} = Modify Height';
arsp__ar_button_titles[" \u{02B83}"] = 'Toggle the Mode for updating resolution.\nResolution is always rounded to precision (default 64px).\n\n\u{02B83} = "Offset" updates both Width/Height from the average current resolution\n\u{02B85} = "One Dimension" changes only Width or Height';
arsp__ar_button_titles[" \u{02139}"] = 'Show the Information panel including additional settings.'
arsp__ar_button_titles[" \u{02BC5}"] = 'Hide the Information panel.'
onUiUpdate(function(){
gradioApp().querySelectorAll('#arsp__txt2img_container_aspect_ratio button, #arsp__img2img_container_aspect_ratio button').forEach(function(elem){
tooltip = arsp__ar_button_titles[elem.textContent];
if(tooltip){
elem.title = tooltip;
}
})
})

View File

@@ -1,21 +0,0 @@
if ("undefined" === typeof arsp__ar_button_titles) {
arsp__ar_button_titles = {};
}
arsp__ar_button_titles["Calc"] = "Show or hide the aspect ratio calculator";
arsp__ar_button_titles["\u{21c5}"] = "Swap width and height values";
arsp__ar_button_titles["\u2B07\ufe0f"] = "Get dimensions from txt2img/img2img sliders";
arsp__ar_button_titles["\u{1f5bc}"] = "Get dimensions from image on current img2img tab";
arsp__ar_button_titles["Calculate Height"] = "Calculate new height based on source aspect ratio";
arsp__ar_button_titles["Calculate Width"] = "Calculate new width based on source aspect ratio";
arsp__ar_button_titles["Apply"] = "Apply calculated width and height to txt2img/img2img sliders";
arsp__ar_button_titles["\uD83D\uDD0D"] = "Round dimensions to the nearest multiples of 4 (1023x101 => 1024x100)";
onUiUpdate(function(){
gradioApp().querySelectorAll('#arsp__txt2img_container_aspect_ratio button, #arsp__img2img_container_aspect_ratio button').forEach(function(elem){
tooltip = arsp__ar_button_titles[elem.textContent];
if(tooltip){
elem.title = tooltip;
}
})
})

View File

@@ -0,0 +1,396 @@
import contextlib
from pathlib import Path
import gradio as gr
import modules.scripts as scripts
from modules.ui_components import ToolButton
from fractions import Fraction
from math import gcd, sqrt
BASE_PATH = scripts.basedir()
is_locked = False
# Helper functions for calculating new width/height values
def round_to_precision(val, prec):
return round(val / prec) * prec
def res_to_model_fit(avg, w, h, prec):
mp = w * h
mp_target = avg * avg
scale = sqrt(mp_target / mp)
w = int(round_to_precision(w * scale, prec))
h = int(round_to_precision(h * scale, prec))
return w, h
def calc_width(n, d, w, h, prec):
ar = round((n / d), 2) # Convert AR parts to fraction
if ar > 1.0:
h = w / ar
elif ar < 1.0:
w = h * ar
else:
new_value = max([w, h])
w, h = new_value, new_value
w = int(round_to_precision((w + prec / 2), prec))
h = int(round_to_precision((h + prec / 2), prec))
return w, h
def calc_height(n, d, w, h, prec):
ar = round((n / d), 2) # Convert AR parts to fraction
if ar > 1.0:
w = h * ar
elif ar < 1.0:
h = w / ar
else:
new_value = min([w, h])
w, h = new_value, new_value
w = int(round_to_precision((w + prec / 2), prec))
h = int(round_to_precision((h + prec / 2), prec))
return w, h
def dims_from_ar(avg, n, d, prec):
doubleavg = avg * 2
ar_sum = n+d
# calculate width and height by factoring average with aspect ratio
w = round((n / ar_sum) * doubleavg)
h = round((d / ar_sum) * doubleavg)
# Round to correct megapixel precision
w, h = res_to_model_fit(avg, w, h, prec)
return w, h
def avg_from_dims(w, h):
avg = (w + h) // 2
if (w + h) % 2 != 0:
avg += 1
return avg
# Aspect Ratio buttons
class ARButton(ToolButton):
switched = False
alt_mode = False
def __init__(self, value='1:1', **kwargs):
super().__init__(**kwargs)
self.value = value
def apply(self, avg, prec, w=512, h=512):
ar = self.value
n, d = map(Fraction, ar.split(':')) # split numerator and denominator
if not is_locked:
avg = avg_from_dims(w, h) # Get average of current width/height values
if not ARButton.alt_mode: # True = offset, False = One dimension
w, h = dims_from_ar(avg, n, d, prec) # Calculate new w + h from avg, AR, and precision
if ARButton.switched: # Switch results if switch mode active
w, h = h, w
else: # Calculate w or h from input, AR, and precision
if ARButton.switched: # Switch results if switch mode active
w, h = calc_width(n, d, w, h, prec) # Modify width
else:
w, h = calc_height(n, d, w, h, prec) # Modify height
return avg, w, h
@classmethod
def toggle_switch(cls):
cls.switched = not cls.switched
@classmethod
def toggle_mode(cls):
cls.alt_mode = not cls.alt_mode
# Static Resolution buttons
class ResButton(ToolButton):
def __init__(self, res=(512, 512), **kwargs):
super().__init__(**kwargs)
self.w, self.h = res
def reset(self, avg):
# Get average of current width/height values
if not is_locked:
avg = avg_from_dims(self.w, self.h)
return avg, self.w, self.h
# Get values for Aspect Ratios from file
def parse_aspect_ratios_file(filename):
values, flipvals, comments = [], [], []
file = Path(BASE_PATH, filename)
if not file.exists():
return values, comments, flipvals
with open(file, "r", encoding="utf-8") as f:
lines = f.readlines()
if not lines:
return values, comments, flipvals
for line in lines:
if line.startswith("#"):
continue
value = line.strip()
comment = ""
if "#" in value:
value, comment = value.split("#")
values.append(value)
comments.append(comment)
comp1, comp2 = value.split(':')
flipval = f"{comp2}:{comp1}"
flipvals.append(flipval)
return values, comments, flipvals
# Get values for Static Resolutions from file
def parse_resolutions_file(filename):
labels, values, comments = [], [], []
file = Path(BASE_PATH, filename)
if not file.exists():
return labels, values, comments
with open(file, "r", encoding="utf-8") as f:
lines = f.readlines()
if not lines:
return labels, values, comments
for line in lines:
if line.startswith("#"):
continue
label, width, height = line.strip().split(",")
comment = ""
if "#" in height:
height, comment = height.split("#")
resolution = (width, height)
labels.append(label)
values.append(resolution)
comments.append(comment)
return labels, values, comments
def write_aspect_ratios_file(filename):
aspect_ratios = [
"1:1 # Square\n",
"4:3 # Television Photography\n",
"3:2 # Photography\n",
"8:5 # Widescreen Displays\n",
"16:9 # Widescreen Television\n",
"21:9 # Ultrawide Cinematography"
]
with open(filename, "w", encoding="utf-8") as f:
f.writelines(aspect_ratios)
def write_resolutions_file(filename):
resolutions = [
"512, 512, 512 # 512x512\n",
"768, 768, 768 # 768x768\n",
"1024, 1024, 1024 # 1024x1024\n",
"1280, 1280, 1280 # 1280x1280\n",
"1536, 1536, 1536 # 1536x1536\n",
"2048, 2048, 2048 # 2048x2048",
]
with open(filename, "w", encoding="utf-8") as f:
f.writelines(resolutions)
def write_js_titles_file(button_titles):
filename = Path(BASE_PATH, "javascript", "button_titles.js")
content = ["// Do not put custom titles here. This file is overwritten each time the WebUI is started.\n"]
content.append("arsp__ar_button_titles = {\n")
counter = 0
while counter < len(button_titles[0]):
content.append(f' " {button_titles[0][counter]}" : "{button_titles[1][counter]}",\n')
counter = counter + 1
content.append("}")
with open(filename, "w", encoding="utf-8") as f:
f.writelines(content)
class AspectRatioScript(scripts.Script):
def read_aspect_ratios(self):
ar_file = Path(BASE_PATH, "aspect_ratios.txt")
if not ar_file.exists():
write_aspect_ratios_file(ar_file)
(self.aspect_ratios, self.aspect_ratio_comments, self.flipped_vals) = parse_aspect_ratios_file("aspect_ratios.txt")
self.ar_btns_labels = self.aspect_ratios
def read_resolutions(self):
res_file = Path(BASE_PATH, "resolutions.txt")
if not res_file.exists():
write_resolutions_file(res_file)
self.res_labels, res, self.res_comments = parse_resolutions_file("resolutions.txt")
self.res = [list(map(int, r)) for r in res]
def title(self):
return "Aspect Ratio picker"
def show(self, is_img2img):
return scripts.AlwaysVisible
def ui(self, is_img2img):
self.LOCK_OPEN_ICON = "\U0001F513" # 🔓
self.LOCK_CLOSED_ICON = "\U0001F512" # 🔒
self.LAND_AR_ICON = "\U000025AD" # ▭
self.PORT_AR_ICON = "\U000025AF" # ▯
self.INFO_ICON = "\U00002139" #
self.INFO_CLOSE_ICON = "\U00002BC5" # ⯅
self.OFFSET_ICON = "\U00002B83" # ⮃
self.ONE_DIM_ICON = "\U00002B85" # ⮅
arc_avg = gr.Number(label="Current W/H Avg.", value=0, interactive=False, render=False)
arc_prec = gr.Number(label="Precision (px)", value=64, minimum=4, maximum=128, step=4, precision=0, render=False)
with gr.Accordion(label="Aspect Ratio and Resolution Buttons", open=True):
with gr.Column(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_container_aspect_ratio'):
# Get aspect ratios from file
self.read_aspect_ratios()
# Top row
with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_aspect_ratio'):
# Lock button
arc_lock = ToolButton(value=self.LOCK_OPEN_ICON, visible=True, variant="secondary", elem_id="arsp__arc_lock_button")
# Click event handling for lock button
def toggle_lock(icon, avg, w=512, h=512):
global is_locked
icon = self.LOCK_OPEN_ICON if is_locked else self.LOCK_CLOSED_ICON
is_locked = not is_locked
if not avg:
avg = avg_from_dims(w, h)
return icon, avg
if is_img2img:
lock_w = self.i2i_w
lock_h = self.i2i_h
else:
lock_w = self.t2i_w
lock_h = self.t2i_h
arc_lock.click(toggle_lock, inputs=[arc_lock, arc_avg, lock_w, lock_h], outputs=[arc_lock, arc_avg])
# Switch button
arc_sw = ToolButton(value=self.LAND_AR_ICON, visible=True, variant="secondary", elem_id="arsp__arc_sw_button")
# Click event handling for switch button
def toggle_switch(icon):
icon = self.PORT_AR_ICON if icon == self.LAND_AR_ICON else self.LAND_AR_ICON
ARButton.toggle_switch()
return icon
arc_sw.click(toggle_switch, inputs=[arc_sw], outputs=[arc_sw])
# Aspect Ratio buttons
ar_btns = [ARButton(value=ar) for ar in self.ar_btns_labels]
# Click event handling for AR buttons
with contextlib.suppress(AttributeError):
for b in ar_btns:
if is_img2img:
w = self.i2i_w
h = self.i2i_h
else:
w = self.t2i_w
h = self.t2i_h
b.click(b.apply, inputs=[arc_avg, arc_prec, w, h], outputs=[arc_avg, w, h])
# Get resolutions from file
self.read_resolutions()
# Bottom row
with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_resolutions'):
# Info button to toggle info window
arc_show_info = ToolButton(value=self.INFO_ICON, visible=True, variant="secondary", elem_id="arsp__arc_show_info_button")
arc_hide_info = ToolButton(value=self.INFO_CLOSE_ICON, visible=False, variant="secondary", elem_id="arsp__arc_hide_info_button")
# Click event handling for info window
# Handled after everything else
# Mode button
arc_mode = ToolButton(value=self.OFFSET_ICON, visible=True, variant="secondary", elem_id="arsp__arc_mode_button")
# Click event handling for Mode button
def toggle_mode(icon):
icon = self.ONE_DIM_ICON if icon == self.OFFSET_ICON else self.OFFSET_ICON
ARButton.toggle_mode()
return icon
arc_mode.click(toggle_mode, inputs=[arc_mode], outputs=[arc_mode])
# Static resolution buttons
btns = [ResButton(res=res, value=label) for res, label in zip(self.res, self.res_labels)]
# Click event handling for static res buttons
with contextlib.suppress(AttributeError):
for b in btns:
b.click(b.reset, inputs=[arc_avg], outputs=[arc_avg, w, h])
# Write button_titles.js with labels and comments read from aspect ratios and resolutions files
button_titles = [self.aspect_ratios + self.res_labels]
button_titles.append(self.aspect_ratio_comments + self.res_comments)
write_js_titles_file(button_titles)
# Information panel
with gr.Column(visible=False, variant="panel", elem_id="arsp__arc_panel") as arc_panel:
with gr.Row():
with gr.Column(scale=2, min_width=100):
# render the current average number box
arc_avg.render()
# render the precision input box
arc_prec.render()
# Information blurb
gr.Column(scale=1, min_width=10)
with gr.Column(scale=12):
arc_title_heading = gr.Markdown(value=
'''
### AR and Static Res buttons can be customized in the 'aspect_ratios.txt' and 'resolutions.txt' files
**Aspect Ratio buttons (Top Row)**:
(1) Averages the current width/height in the UI; (2) Offsets to the exact aspect ratio; (3) Rounds to precision.
**Static Resolution buttons (Bottom Row)**:
Recommended to use 1:1 values for these, to serve as a start point before clicking AR buttons.
**64px Precision is recommended, the same rounding applied for image "bucketing" when model training.**
'''
)
# Toggle info panel
arc_show_info.click(
lambda: [
gr.update(visible=True),
gr.update(visible=False),
gr.update(visible=True),
],
None,
[
arc_panel,
arc_show_info,
arc_hide_info,
],
)
# Hide info pane
arc_hide_info.click(
lambda: [
gr.update(visible=False),
gr.update(visible=True),
gr.update(visible=False),
],
None,
[arc_panel, arc_show_info, arc_hide_info],
)
## Function to update the values in appropriate Width/Height fields
# https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/7456#issuecomment-1414465888
def after_component(self, component, **kwargs):
if kwargs.get("elem_id") == "txt2img_width":
self.t2i_w = component
if kwargs.get("elem_id") == "txt2img_height":
self.t2i_h = component
if kwargs.get("elem_id") == "img2img_width":
self.i2i_w = component
if kwargs.get("elem_id") == "img2img_height":
self.i2i_h = component

View File

@@ -1,422 +0,0 @@
import contextlib
from pathlib import Path
import gradio as gr
import modules.scripts as scripts
from modules.ui_components import ToolButton
from fractions import Fraction
from math import gcd, sqrt
BASE_PATH = scripts.basedir()
SWITCH_SYMBOL = "\U0001F501" # 🔁
LOCK_OPEN_SYMBOL = "\U0001F513" # 🔓
LOCK_SYMBOL = "\U0001F512" # 🔒
LAND_AR_SYMBOL = "\U000025AD" # ▭
PORT_AR_SYMBOL = "\U000025AF" # ▯
INFO_SYMBOL = "\U00002139" #
is_lock_mode = False # FIXME: Global value
is_switch_mode = False # FIXME: Global value
is_locked = False
## Aspect Ratio buttons
# Helper functions for calculating new width/height from aspect ratio
def round_to_precision(val, prec):
return round(val / prec) * prec
def res_to_model_fit(w, h, mp_target, prec):
mp = w * h
scale = sqrt(mp_target / mp)
w = int(round_to_precision(w * scale, prec))
h = int(round_to_precision(h * scale, prec))
return w, h
def dims_from_ar(avg, ar, prec):
mp_target = avg*avg
doubleavg = avg*2
ar_parts = tuple(map(Fraction, ar.split(':')))
ar_sum = ar_parts[0]+ar_parts[1]
# calculate width and height by factoring average with aspect ratio
w = round((ar_parts[0]/ar_sum)*doubleavg)
h = round((ar_parts[1]/ar_sum)*doubleavg)
# Round to correct megapixel precision
w, h = res_to_model_fit(w, h, mp_target, prec)
return w, h
def avg_from_dims(w, h):
avg = (w + h) // 2
if (w + h) % 2 != 0:
avg += 1
return avg
class ARButton(ToolButton):
switched = False
def __init__(self, value='1:1', **kwargs):
super().__init__(**kwargs)
self.value = value
def apply(self, avg, prec, w=512, h=512):
# Get average of current width/height values
if not is_locked:
avg = avg_from_dims(w, h)
# Calculate new w/h from avg, AR, and precision
w, h = dims_from_ar(avg, self.value, prec)
if ARButton.switched:
w, h = h, w # return switched results
return avg, w, h
@classmethod
def toggle_switch(cls):
cls.switched = not cls.switched
## Static Resolution buttons
class ResButton(ToolButton):
def __init__(self, res=(512, 512), **kwargs):
super().__init__(**kwargs)
self.w, self.h = res
def reset(self, avg):
# Get average of current width/height values
if not is_locked:
avg = avg_from_dims(self.w, self.h)
return avg, self.w, self.h
## Get values for Aspect Ratios from file
def parse_aspect_ratios_file(filename):
values, flipvals, comments = [], [], []
file = Path(BASE_PATH, filename)
if not file.exists():
return values, comments, flipvals
with open(file, "r", encoding="utf-8") as f:
lines = f.readlines()
if not lines:
return values, comments, flipvals
for line in lines:
if line.startswith("#"):
continue
value = line.strip()
comment = ""
if "#" in value:
value, comment = value.split("#")
values.append(value)
comments.append(comment)
comp1, comp2 = value.split(':')
flipval = f"{comp2}:{comp1}"
flipvals.append(flipval)
return values, comments, flipvals
## Get values for Static Resolutions from file
def parse_resolutions_file(filename):
labels, values, comments = [], [], []
file = Path(BASE_PATH, filename)
if not file.exists():
return labels, values, comments
with open(file, "r", encoding="utf-8") as f:
lines = f.readlines()
if not lines:
return labels, values, comments
for line in lines:
if line.startswith("#"):
continue
label, width, height = line.strip().split(",")
comment = ""
if "#" in height:
height, comment = height.split("#")
resolution = (width, height)
labels.append(label)
values.append(resolution)
comments.append(comment)
return labels, values, comments
# TODO: write a generic function handling both cases
def write_aspect_ratios_file(filename):
aspect_ratios = [
"3:2 # Photography\n",
"4:3 # Television photography\n",
"16:9 # Television photography\n",
"1.85:1 # Cinematography\n",
"2.39:1 # Cinematography",
]
with open(filename, "w", encoding="utf-8") as f:
f.writelines(aspect_ratios)
def write_resolutions_file(filename):
resolutions = [
"512, 512, 512 # 512x512\n",
"640, 640, 640 # 640x640\n",
"768, 768, 768 # 768x768\n",
"896, 896, 896 # 896x896\n",
"1024, 1024, 1024 # 1024x1024",
]
with open(filename, "w", encoding="utf-8") as f:
f.writelines(resolutions)
def write_js_titles_file(button_titles):
filename = Path(BASE_PATH, "javascript", "button_titles.js")
content = ["// Do not put custom titles here. This file is overwritten each time the WebUI is started.\n"]
content.append("arsp__ar_button_titles = {\n")
counter = 0
while counter < len(button_titles[0]):
content.append(f' " {button_titles[0][counter]}" : "{button_titles[1][counter]}",\n')
counter = counter + 1
content.append("}")
with open(filename, "w", encoding="utf-8") as f:
f.writelines(content)
class AspectRatioScript(scripts.Script):
def read_aspect_ratios(self):
ar_file = Path(BASE_PATH, "aspect_ratios.txt")
if not ar_file.exists():
write_aspect_ratios_file(ar_file)
(self.aspect_ratios, self.aspect_ratio_comments, self.flipped_vals) = parse_aspect_ratios_file("aspect_ratios.txt")
self.ar_btns_labels = self.aspect_ratios
def read_resolutions(self):
res_file = Path(BASE_PATH, "resolutions.txt")
if not res_file.exists():
write_resolutions_file(res_file)
self.res_labels, res, self.res_comments = parse_resolutions_file("resolutions.txt")
self.res = [list(map(int, r)) for r in res]
def title(self):
return "Aspect Ratio picker"
def show(self, is_img2img):
return scripts.AlwaysVisible
def ui(self, is_img2img):
arc_avg = gr.Number(label="Current W/H Avg.", value=0, interactive=False, render=False)
arc_prec = gr.Number(label="Precision (px)", info='64px is recommended, the same rounding applied for image "bucketing" when model training.', value=64, minimum=4, maximum=128, precision=0, render=False)
with gr.Column(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_container_aspect_ratio'):
# Get aspect ratios from file
self.read_aspect_ratios()
# Top row
with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_aspect_ratio'):
# Lock button
arc_show_lock = ToolButton(value=LOCK_SYMBOL, min_width=84, scale = 0, visible=True, variant="secondary", elem_id="arsp__arc_show_lock_button")
arc_hide_lock = ToolButton(value=LOCK_SYMBOL, min_width=84, scale = 0, visible=False, variant="primary", elem_id="arsp__arc_hide_lock_button")
# Click event handling for lock button
def toggle_lock(avg, w=512, h=512):
global is_locked
is_locked = not is_locked
if not avg:
avg = avg_from_dims(w, h)
return avg
if is_img2img:
lock_w = self.i2i_w
lock_h = self.i2i_h
else:
lock_w = self.t2i_w
lock_h = self.t2i_h
arc_show_lock.click(toggle_lock, inputs=[arc_avg, lock_w, lock_h], outputs=[arc_avg])
arc_hide_lock.click(toggle_lock, inputs=[arc_avg, lock_w, lock_h], outputs=[arc_avg])
# Switch button
arc_sw_on = ToolButton(value=SWITCH_SYMBOL, min_width=84, scale = 0, visible=True, variant="secondary", elem_id="arsp__arc_sw_on_button")
arc_sw_off = ToolButton(value=SWITCH_SYMBOL, min_width=84, scale = 0, visible=False, variant="primary", elem_id="arsp__arc_sw_off_button")
# Click event handling for switch button
def toggle_switch():
ARButton.toggle_switch()
# def toggle_switch():
# if self.ar_btns_labels == self.aspect_ratios:
# self.ar_btns_labels = self.flipped_vals
# else:
# self.ar_btns_labels = self.aspect_ratios
arc_sw_on.click(toggle_switch)
arc_sw_off.click(toggle_switch)
# Aspect Ratio buttons
ar_btns = [ARButton(value=ar) for ar in self.ar_btns_labels]
# Click event handling for AR buttons
with contextlib.suppress(AttributeError):
for b in ar_btns:
if is_img2img:
w = self.i2i_w
h = self.i2i_h
else:
w = self.t2i_w
h = self.t2i_h
b.click(b.apply, inputs=[arc_avg, arc_prec, w, h], outputs=[arc_avg, w, h])
# Get resolutions from file
self.read_resolutions()
# Bottom row
with gr.Row(elem_id=f'arsp__{"img" if is_img2img else "txt"}2img_row_resolutions'):
# Info button to toggle info window
arc_show_info = ToolButton(value=INFO_SYMBOL, min_width=84, scale = 1.0, visible=True, variant="secondary", elem_id="arsp__arc_show_info_button")
arc_hide_info = ToolButton(value=INFO_SYMBOL, min_width=84, scale = 1.0, visible=False, variant="primary", elem_id="arsp__arc_hide_info_button")
# Click event handling for info window
def toggle_info():
arc_panel.visible = not arc_panel.visible
arc_show_info.visible = not arc_show_info.visible
arc_hide_info.visible = not arc_hide_info.visible
arc_show_info.click(toggle_info)
arc_hide_info.click(toggle_info)
# Static resolution buttons
btns = [ResButton(res=res, value=label) for res, label in zip(self.res, self.res_labels)]
# Click event handling for static res buttons
with contextlib.suppress(AttributeError):
for b in btns:
b.click(b.reset, inputs=[arc_avg], outputs=[arc_avg, w, h])
# Write button_titles.js with labels and comments read from aspect ratios and resolutions files
button_titles = [self.aspect_ratios + self.res_labels]
button_titles.append(self.aspect_ratio_comments + self.res_comments)
write_js_titles_file(button_titles)
# Information panel
with gr.Column(visible=False, variant="panel", elem_id="arsp__arc_panel") as arc_panel:
with gr.Row():
with gr.Column(scale=2, min_width=100):
# render the current average number box
arc_avg.render()
# render the precision input box
arc_prec.render()
# Information blurb
gr.Column(scale=1, min_width=10)
with gr.Column(scale=12):
arc_title_heading = gr.Markdown(value=
'''
### AR and Static Res buttons can be customized in the 'aspect_ratios.txt' and 'resolutions.txt' files
### Top Row:
**Aspect Ratio (AR) buttons** - calculate and apply desireable width/height by: (1) Averaging the current width/height in the UI; (2) Offsetting to the exact AR; (3) Rounding to precision.
**Lock button** - captures the current average width/height in the UI. This is good when switching between ARs. When unlocked, the average will change due to rounding.
**Switch button** - toggles between landscape and portrait orientation for ease of use.
### Bottom Row:
**Static Resolution buttons** - recommended to use 1:1 values for these, to serve as a start point before clicking AR buttons.
**Mode button** will change the method of the AR buttons to calculate only one value, rather than offsetting.
'''
)
# Show info pane
arc_show_info.click(
lambda: [
gr.update(visible=True),
gr.update(visible=False),
gr.update(visible=True),
],
None,
[
arc_panel,
arc_show_info,
arc_hide_info,
],
)
# Hide info pane
arc_hide_info.click(
lambda: [
gr.update(visible=False),
gr.update(visible=True),
gr.update(visible=False),
],
None,
[arc_panel, arc_show_info, arc_hide_info],
)
def _arc_show_lock_update():
global is_lock_mode
is_lock_mode = not is_lock_mode
return [
arc_show_lock.update(visible=False),
arc_hide_lock.update(visible=True),
]
def _arc_hide_lock_update():
global is_lock_mode
is_lock_mode = not is_lock_mode
return [
arc_show_lock.update(visible=True),
arc_hide_lock.update(visible=False),
]
arc_show_lock.click(
_arc_show_lock_update,
None,
[arc_show_lock, arc_hide_lock],
)
arc_hide_lock.click(
_arc_hide_lock_update,
None,
[arc_show_lock, arc_hide_lock],
)
def _arc_sw_on_update():
global is_switch_mode
is_switch_mode = not is_switch_mode
return [
arc_sw_on.update(visible=False),
arc_sw_off.update(visible=True),
]
def _arc_sw_off_update():
global is_switch_mode
is_switch_mode = not is_switch_mode
return [
arc_sw_on.update(visible=True),
arc_sw_off.update(visible=False),
]
arc_sw_on.click(
_arc_sw_on_update,
None,
[arc_sw_on, arc_sw_off],
)
arc_sw_off.click(
_arc_sw_off_update,
None,
[arc_sw_on, arc_sw_off],
)
## Function to update the values in appropriate Width/Height fields
# https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/7456#issuecomment-1414465888
def after_component(self, component, **kwargs):
if kwargs.get("elem_id") == "txt2img_width":
self.t2i_w = component
if kwargs.get("elem_id") == "txt2img_height":
self.t2i_h = component
if kwargs.get("elem_id") == "img2img_width":
self.i2i_w = component
if kwargs.get("elem_id") == "img2img_height":
self.i2i_h = component
if kwargs.get("elem_id") == "img2img_image":
self.image = [component]
if kwargs.get("elem_id") == "img2img_sketch":
self.image.append(component)
if kwargs.get("elem_id") == "img2maskimg":
self.image.append(component)
if kwargs.get("elem_id") == "inpaint_sketch":
self.image.append(component)
if kwargs.get("elem_id") == "img_inpaint_base":
self.image.append(component)

View File

@@ -20,10 +20,11 @@
max-width: unset !important;
}
button#arsp__arc_lock_button,
button#arsp__arc_mode_button,
button#arsp__arc_sw_button,
button#arsp__arc_show_info_button,
button#arsp__arc_hide_info_button,
button#arsp__arc_show_logic_button,
button#arsp__arc_hide_logic_button {
button#arsp__arc_hide_info_button {
max-width: 40px !important;
min-width: unset !important;
padding: var(--size-0-5) var(--size-2) !important;