mirror of
https://github.com/vladmandic/automatic
synced 2026-09-20 01:31:13 +02:00
Merge pull request #4752 from vladmandic/feat/gallery-ux
Feat/gallery ux
This commit is contained in:
+1
-1
@@ -24,7 +24,7 @@
|
||||
{"id":"xyz_grid_x_list","label":"⊜","localized":"","hint":"Fill","ui":"script_xyz_grid_script"},
|
||||
{"id":"txt2img_caption_output","label":"","localized":"","hint":"Caption image","ui":"txt2img"},
|
||||
{"id":"txt2img_image_fit","label":"⁜","localized":"","hint":"Cycle image fit method","ui":"txt2img"},
|
||||
{"id":"","label":"➠ Control","localized":"","hint":"Transfer image to control interface","ui":"txt2img"},
|
||||
{"id":"","label":"➠ Control","localized":"","hint":"Transfer image to control interface. <br><br> Right-click this button to transfer only the prompt or all generation parameters to the Images tab without sending the image itself.","ui":"txt2img"},
|
||||
{"id":"","label":"➠ Text","localized":"","hint":"Transfer image to text interface","ui":"txt2img"},
|
||||
{"id":"","label":"➠ Image","localized":"","hint":"Transfer image to image interface","ui":"txt2img"},
|
||||
{"id":"","label":"➠ Process","localized":"","hint":"Transfer image to process interface","ui":"txt2img"},
|
||||
|
||||
@@ -67,8 +67,9 @@ const contextMenuInit = () => {
|
||||
if (oldMenu) oldMenu.remove();
|
||||
menuSpecs.forEach((v, k) => {
|
||||
const items = v.filter((item) => item.primary);
|
||||
if (items.length > 0 && e.composedPath()[0].matches(k)) {
|
||||
showContextMenu(e, e.composedPath()[0], items);
|
||||
const matched = e.target.closest(k);
|
||||
if (items.length > 0 && matched) {
|
||||
showContextMenu(e, matched, items);
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
@@ -78,8 +79,9 @@ const contextMenuInit = () => {
|
||||
if (oldMenu) oldMenu.remove();
|
||||
menuSpecs.forEach((v, k) => {
|
||||
const items = v.filter((item) => !item.primary);
|
||||
if (items.length > 0 && e.composedPath()[0].matches(k)) {
|
||||
showContextMenu(e, e.composedPath()[0], items);
|
||||
const matched = e.target.closest(k);
|
||||
if (items.length > 0 && matched) {
|
||||
showContextMenu(e, matched, items);
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
@@ -161,5 +163,17 @@ async function initContextMenu() {
|
||||
appendContextMenuOption(id, 'Refine & HiRes pass', () => reprocessClick(`${tab}`, 'reprocess_refine'), true);
|
||||
appendContextMenuOption(id, 'Detailer pass', () => reprocessClick(`${tab}`, 'reprocess_detail'), true);
|
||||
}
|
||||
// Right-click send-to-control button for prompt/params-only transfer.
|
||||
for (const tab of ['gallery', 'txt2img', 'img2img', 'extras']) {
|
||||
id = `#${tab}_tabitem #control_tab`;
|
||||
appendContextMenuOption(id, 'Transfer only prompt to Images tab', () => {
|
||||
document.querySelector(`#image_buttons_${tab} #control_tab_prompt`)?.click();
|
||||
document.getElementById('control_nav')?.click();
|
||||
});
|
||||
appendContextMenuOption(id, 'Transfer all parameters to Images tab', () => {
|
||||
document.querySelector(`#image_buttons_${tab} #control_tab_params`)?.click();
|
||||
document.getElementById('control_nav')?.click();
|
||||
});
|
||||
}
|
||||
addContextMenuEventListener();
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ param_aliases: dict[str, str] = {}
|
||||
|
||||
|
||||
class ParamBinding:
|
||||
def __init__(self, paste_button, tabname: str, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=None):
|
||||
def __init__(self, paste_button, tabname: str, source_text_component=None, source_image_component=None, source_tabname=None, override_settings_component=None, paste_field_names=None, skip_image: bool = False, only_prompt: bool = False):
|
||||
self.paste_button = paste_button
|
||||
self.tabname = tabname
|
||||
self.source_text_component = source_text_component
|
||||
@@ -32,6 +32,8 @@ class ParamBinding:
|
||||
self.source_tabname = source_tabname
|
||||
self.override_settings_component = override_settings_component
|
||||
self.paste_field_names = paste_field_names or []
|
||||
self.skip_image = skip_image
|
||||
self.only_prompt = only_prompt
|
||||
# debug(f'ParamBinding: {vars(self)}')
|
||||
|
||||
|
||||
@@ -142,23 +144,26 @@ def get_all_fields():
|
||||
return all_fields
|
||||
|
||||
|
||||
def create_buttons(tabs_list: list[str]) -> dict[str, gr.Button]:
|
||||
def create_buttons(tabs_list: list[str], label_prefix: str = "➠", label_override: str | None = None, id_suffix: str = "") -> dict[str, gr.Button]:
|
||||
buttons = {}
|
||||
for tab in tabs_list:
|
||||
name = tab
|
||||
if name == 'txt2img':
|
||||
name = 'Text'
|
||||
elif name == 'img2img':
|
||||
name = 'Image'
|
||||
elif name == 'inpaint':
|
||||
name = 'Inpaint'
|
||||
elif name == 'extras':
|
||||
name = 'Process'
|
||||
elif name == 'control':
|
||||
name = 'Control'
|
||||
elif name == 'caption':
|
||||
name = 'Caption'
|
||||
buttons[tab] = gr.Button(f"➠ {name}", elem_id=f"{tab}_tab")
|
||||
if label_override is not None:
|
||||
display = label_override
|
||||
else:
|
||||
display = tab
|
||||
if display == 'txt2img':
|
||||
display = 'Text'
|
||||
elif display == 'img2img':
|
||||
display = 'Image'
|
||||
elif display == 'inpaint':
|
||||
display = 'Inpaint'
|
||||
elif display == 'extras':
|
||||
display = 'Process'
|
||||
elif display == 'control':
|
||||
display = 'Control'
|
||||
elif display == 'caption':
|
||||
display = 'Caption'
|
||||
buttons[tab] = gr.Button(f"{label_prefix} {display}", elem_id=f"{tab}_tab{id_suffix}")
|
||||
return buttons
|
||||
|
||||
|
||||
@@ -198,7 +203,7 @@ def connect_paste_params_buttons():
|
||||
fields: list[tuple[gr.components.Component, str]] = paste_fields[binding.tabname]["fields"]
|
||||
|
||||
destination_image_component = paste_fields[binding.tabname]["init_img"]
|
||||
if binding.source_image_component:
|
||||
if binding.source_image_component and not binding.skip_image:
|
||||
if isinstance(destination_image_component, gr.Image):
|
||||
binding.paste_button.click(
|
||||
_js="extract_image_from_gallery" if isinstance(binding.source_image_component, gr.Gallery) else None,
|
||||
@@ -216,10 +221,18 @@ def connect_paste_params_buttons():
|
||||
show_progress='hidden',
|
||||
)
|
||||
override_settings_component = binding.override_settings_component or paste_fields[binding.tabname]["override_settings_component"]
|
||||
if binding.source_text_component is not None and fields is not None:
|
||||
connect_paste(binding.paste_button, fields, binding.source_text_component, override_settings_component, binding.tabname)
|
||||
if binding.only_prompt:
|
||||
override_settings_component = None
|
||||
text_fields = fields
|
||||
if binding.only_prompt and fields is not None:
|
||||
text_fields = [(component, key) for component, key in fields if key in ('Prompt', 'Negative prompt')]
|
||||
if binding.source_text_component is not None and text_fields is not None:
|
||||
connect_paste(binding.paste_button, text_fields, binding.source_text_component, override_settings_component, binding.tabname)
|
||||
if binding.source_tabname is not None and fields is not None and binding.source_tabname in paste_fields:
|
||||
paste_field_names = ['Prompt', 'Negative prompt', 'Steps'] + (["Seed"] if shared.opts.send_seed else []) + binding.paste_field_names
|
||||
if binding.only_prompt:
|
||||
paste_field_names = ['Prompt', 'Negative prompt']
|
||||
else:
|
||||
paste_field_names = ['Prompt', 'Negative prompt', 'Steps'] + (["Seed"] if shared.opts.send_seed else []) + binding.paste_field_names
|
||||
if "fields" in paste_fields[binding.source_tabname] and paste_fields[binding.source_tabname]["fields"] is not None:
|
||||
binding.paste_button.click(
|
||||
fn=lambda *x: x,
|
||||
|
||||
@@ -299,8 +299,16 @@ def create_output_panel(tabname, preview=True, prompt=None, height=None, transfe
|
||||
delete = gr.Button('Delete', elem_id=f'delete_{tabname}')
|
||||
if transfer:
|
||||
buttons = generation_parameters_copypaste.create_buttons(["control", "txt2img", "img2img", "extras", "caption"])
|
||||
if tabname in ("gallery", "txt2img", "img2img", "extras"):
|
||||
prompt_buttons = generation_parameters_copypaste.create_buttons(["control"], label_prefix="✎", label_override="prompt", id_suffix="_prompt")
|
||||
params_buttons = generation_parameters_copypaste.create_buttons(["control"], label_prefix="⚙", label_override="params", id_suffix="_params")
|
||||
else:
|
||||
prompt_buttons = None
|
||||
params_buttons = None
|
||||
else:
|
||||
buttons = None
|
||||
prompt_buttons = None
|
||||
params_buttons = None
|
||||
|
||||
download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False, elem_id=f'download_files_{tabname}')
|
||||
with gr.Group():
|
||||
@@ -349,6 +357,31 @@ def create_output_panel(tabname, preview=True, prompt=None, height=None, transfe
|
||||
source_text_component=prompt or generation_info
|
||||
)
|
||||
generation_parameters_copypaste.register_paste_params_button(bindings)
|
||||
if prompt_buttons is not None:
|
||||
for paste_tabname, paste_button in prompt_buttons.items():
|
||||
debug(f'Create output panel prompt-only: source={tabname} target={paste_tabname} button={paste_button}')
|
||||
generation_parameters_copypaste.register_paste_params_button(generation_parameters_copypaste.ParamBinding(
|
||||
paste_button=paste_button,
|
||||
tabname=paste_tabname,
|
||||
source_tabname=tabname,
|
||||
source_image_component=result_gallery,
|
||||
paste_field_names=paste_field_names,
|
||||
source_text_component=prompt or generation_info,
|
||||
skip_image=True,
|
||||
only_prompt=True,
|
||||
))
|
||||
if params_buttons is not None:
|
||||
for paste_tabname, paste_button in params_buttons.items():
|
||||
debug(f'Create output panel params-only: source={tabname} target={paste_tabname} button={paste_button}')
|
||||
generation_parameters_copypaste.register_paste_params_button(generation_parameters_copypaste.ParamBinding(
|
||||
paste_button=paste_button,
|
||||
tabname=paste_tabname,
|
||||
source_tabname=tabname,
|
||||
source_image_component=result_gallery,
|
||||
paste_field_names=paste_field_names,
|
||||
source_text_component=prompt or generation_info,
|
||||
skip_image=True,
|
||||
))
|
||||
return result_gallery, generation_info, html_info, html_info_formatted, html_log
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user