mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 17:24:32 +02:00
fix(ui): debounce aspect-ratio linked width/height controls
A single handler bound to the AR dropdown, width and height (in the shared create_resolution_inputs and the resize section) wrote both sliders on every change. With a ratio selected it locked one axis and snapped it back on each edit, the two sliders looped, and the math ran server-side one round-trip per keystroke, echoing a value back into the field being typed in and yanking it. Move aspect-ratio linking to the browser (ui/resolutionLock.ts): a debounced edit writes only the partner axis, never the field being edited, and commits immediately on blur, enter, or slider release. Keep the kanvas notify on notifyKanvasResize wired to the resize sliders' gradio .change, so it still fires on programmatic size updates (detect, paste, swap) that client-side listeners miss. Drop the per-change AR wiring, res_apply, and the resolutionChange* helpers.
This commit is contained in:
+5
-37
@@ -1,4 +1,3 @@
|
||||
import time
|
||||
import gradio as gr
|
||||
from modules import shared, modelloader, ui_symbols, ui_common, sd_samplers
|
||||
from modules.logger import log
|
||||
@@ -65,42 +64,11 @@ def create_toprow(is_img2img: bool = False, id_part: str | None = None, generate
|
||||
return prompt, styles, negative_prompt, submit, reprocess, button_paste, button_extra, token_counter, token_button, negative_token_counter, negative_token_button
|
||||
|
||||
|
||||
def ar_change(ar, width, height):
|
||||
if ar == 'AR':
|
||||
return gr.update(), gr.update()
|
||||
try:
|
||||
parts = [float(x) for x in ar.split(':')]
|
||||
if len(parts) != 2:
|
||||
raise ValueError(f"Expected 2 values, got {len(parts)}")
|
||||
w, h = parts
|
||||
except Exception as e:
|
||||
log.warning(f"Invalid aspect ratio: {ar} {e}")
|
||||
return gr.update(), gr.update()
|
||||
if w > h:
|
||||
return gr.update(), gr.update(value=int(width * h / w))
|
||||
elif w < h:
|
||||
return gr.update(value=int(height * w / h)), gr.update()
|
||||
else:
|
||||
return gr.update(), gr.update()
|
||||
|
||||
last_ar_update = None
|
||||
def ar_update(_ar, width, height):
|
||||
global last_ar_update # pylint: disable=global-statement
|
||||
if _ar == 'AR':
|
||||
return gr.update(), gr.update()
|
||||
if (last_ar_update is not None and time.time()) - (last_ar_update < 0.5):
|
||||
return gr.update(), gr.update()
|
||||
last_ar_update = time.time()
|
||||
return gr.update(value=width), gr.update(value=height)
|
||||
|
||||
|
||||
def create_resolution_inputs(tab, default_width=1024, default_height=1024):
|
||||
width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=default_width, elem_id=f"{tab}_width")
|
||||
height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=default_height, elem_id=f"{tab}_height")
|
||||
ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != '']
|
||||
ar_dropdown = gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_ar", elem_classes=["ar-dropdown"])
|
||||
for c in [ar_dropdown, width, height]:
|
||||
c.change(fn=ar_change, inputs=[ar_dropdown, width, height], outputs=[width, height], show_progress='hidden')
|
||||
gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_ar", elem_classes=["ar-dropdown"]) # aspect-ratio linking wired client-side in ui/resolutionLock.ts
|
||||
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_res_btn_swap")
|
||||
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress='hidden')
|
||||
return width, height
|
||||
@@ -415,15 +383,15 @@ def create_resize_inputs(tab, images, accordion=True, latent=False, non_zero=Tru
|
||||
height = gr.Slider(minimum=64 if non_zero else 0, maximum=8192, step=8, label=f"Height{prefix}" if non_zero else "Resize height", value=1024 if non_zero else 0, elem_id=f"{tab}{suffix}_height")
|
||||
with gr.Column(elem_id=f"{tab}_column_fixed2", scale=1):
|
||||
ar_list = ['AR'] + [x.strip() for x in shared.opts.aspect_ratios.split(',') if x.strip() != '']
|
||||
ar_dropdown = gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_resize_ar", elem_classes=["ar-dropdown"])
|
||||
for c in [ar_dropdown, width, height]:
|
||||
# c.change(fn=ar_change, inputs=[ar_dropdown, width, height], outputs=[width, height], show_progress='hidden')
|
||||
c.change(fn=ar_update, _js='resolutionChange', inputs=[ar_dropdown, width, height], outputs=[width, height], show_progress='hidden')
|
||||
gr.Dropdown(show_label=False, interactive=True, choices=ar_list, value=ar_list[0], elem_id=f"{tab}_resize_ar", elem_classes=["ar-dropdown"]) # aspect-ratio linking wired client-side in ui/resolutionLock.ts
|
||||
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_resize_size_swap")
|
||||
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress='hidden')
|
||||
detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_resize_detect_size")
|
||||
el = tab.split('_')[0]
|
||||
detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js=f'currentImageResolution{el}', inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress='hidden')
|
||||
# keep the kanvas stage synced to the resize sliders; .change fires on user and programmatic updates (detect, paste, swap) and writes nothing back
|
||||
width.change(fn=None, _js='notifyKanvasResize', inputs=[width, height], outputs=[], show_progress='hidden')
|
||||
height.change(fn=None, _js='notifyKanvasResize', inputs=[width, height], outputs=[], show_progress='hidden')
|
||||
with gr.Tab(label="Scale", id=1, elem_id=f"{tab}_scale_tab_scale") as tab_scale_by:
|
||||
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label=f"Scale{prefix}" if non_zero else "Resize scale", value=1.0, elem_id=f"{tab}_scale")
|
||||
if images is not None:
|
||||
|
||||
Reference in New Issue
Block a user