diff --git a/modules/shared_options.py b/modules/shared_options.py index ac050c2e..770592e9 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -372,7 +372,7 @@ options_templates.update( "show_refiner": OptionInfo(False, "Display the Refiner Accordion").info('"deprecated" feature for SDXL').needs_reload_ui(), # "show_rescale_cfg": OptionInfo(False, "Display the Rescale CFG Slider").info("feature for v-pred checkpoints").needs_reload_ui(), # "show_mahiro": OptionInfo(False, "Display the MaHiRo Toggle").info('see blue-arxiv - id: 2024-1208.1').needs_reload_ui(), - # "paste_safe_guard": OptionInfo(False, 'Disable the "Read generation parameters" button (↙️) when negative prompt is not empty'), + "paste_safe_guard": OptionInfo(False, 'Disable the "Read generation parameters" button (↙️) when negative prompt is not empty'), "div_classic": OptionDiv(), "compact_prompt_box": OptionInfo(False, "Compact Prompt Layout").info("put prompts inside the Generate tab, leaving more space for the gallery").needs_reload_ui(), "dimensions_and_batch_together": OptionInfo(True, "Show Width/Height and Batch sliders in same row").needs_reload_ui(), diff --git a/modules/ui.py b/modules/ui.py index 41643d5e..e10e70c6 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -511,6 +511,9 @@ def create_ui(): extra_tabs.__exit__() + if shared.opts.paste_safe_guard: + toprow.hook_paste_guard() + scripts.scripts_current = scripts.scripts_img2img scripts.scripts_img2img.initialize_scripts(is_img2img=True) @@ -857,6 +860,9 @@ def create_ui(): extra_tabs.__exit__() + if shared.opts.paste_safe_guard: + toprow.hook_paste_guard() + scripts.scripts_current = None with gr.Blocks(analytics_enabled=False) as extras_interface: diff --git a/modules/ui_toprow.py b/modules/ui_toprow.py index 6a9055a4..432e4d00 100644 --- a/modules/ui_toprow.py +++ b/modules/ui_toprow.py @@ -1,8 +1,7 @@ import gradio as gr -from modules import shared, ui_prompt_styles import modules.images - +from modules import shared, ui_prompt_styles from modules.ui_components import ToolButton @@ -77,11 +76,11 @@ class Toprow: def create_prompts(self): with gr.Column(elem_id=f"{self.id_part}_prompt_container", elem_classes=["prompt-container-compact"] if self.is_compact else [], scale=6): with gr.Row(elem_id=f"{self.id_part}_prompt_row", elem_classes=["prompt-row"]): - self.prompt = gr.Textbox(label="Prompt", elem_id=f"{self.id_part}_prompt", show_label=False, lines=3, placeholder="Prompt\n(Press Ctrl+Enter to generate, Alt+Enter to skip, Esc to interrupt)", elem_classes=["prompt"], value='') + self.prompt = gr.Textbox(label="Prompt", elem_id=f"{self.id_part}_prompt", show_label=False, lines=3, placeholder="Prompt\n(Press Ctrl+Enter to generate, Alt+Enter to skip, Esc to interrupt)", elem_classes=["prompt"], value="") self.prompt_img = gr.File(label="", elem_id=f"{self.id_part}_prompt_image", file_count="single", type="binary", visible=False) with gr.Row(elem_id=f"{self.id_part}_neg_prompt_row", elem_classes=["prompt-row"]): - self.negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{self.id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt\n(Press Ctrl+Enter to generate, Alt+Enter to skip, Esc to interrupt)", elem_classes=["prompt"], value='') + self.negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{self.id_part}_neg_prompt", show_label=False, lines=3, placeholder="Negative prompt\n(Press Ctrl+Enter to generate, Alt+Enter to skip, Esc to interrupt)", elem_classes=["prompt"], value="") self.prompt_img.change( fn=modules.images.image_data, @@ -94,10 +93,10 @@ class Toprow: with gr.Row(elem_id=f"{self.id_part}_generate_box", elem_classes=["generate-box"] + (["generate-box-compact"] if self.is_compact else []), render=not self.is_compact) as submit_box: self.submit_box = submit_box - self.interrupt = gr.Button('Interrupt', elem_id=f"{self.id_part}_interrupt", elem_classes="generate-box-interrupt", tooltip="End generation immediately or after completing current batch") - self.skip = gr.Button('Skip', elem_id=f"{self.id_part}_skip", elem_classes="generate-box-skip", tooltip="Stop generation of current batch and continues onto next batch") - self.interrupting = gr.Button('Interrupting...', elem_id=f"{self.id_part}_interrupting", elem_classes="generate-box-interrupting", tooltip="Interrupting generation...") - self.submit = gr.Button('Generate', elem_id=f"{self.id_part}_generate", variant='primary', tooltip="Right click generate forever menu") + self.interrupt = gr.Button("Interrupt", elem_id=f"{self.id_part}_interrupt", elem_classes="generate-box-interrupt", tooltip="End generation immediately or after completing current batch") + self.skip = gr.Button("Skip", elem_id=f"{self.id_part}_skip", elem_classes="generate-box-skip", tooltip="Stop generation of current batch and continues onto next batch") + self.interrupting = gr.Button("Interrupting...", elem_id=f"{self.id_part}_interrupting", elem_classes="generate-box-interrupting", tooltip="Interrupting generation...") + self.submit = gr.Button("Generate", elem_id=f"{self.id_part}_generate", variant="primary", tooltip="Right click generate forever menu") def interrupt_function(): if not shared.state.stopping_generation and shared.state.job_count > 1 and shared.opts.interrupt_after_current: @@ -112,7 +111,7 @@ class Toprow: def create_tools_row(self): with gr.Row(elem_id=f"{self.id_part}_tools"): - from modules.ui import paste_symbol, clear_prompt_symbol, restore_progress_symbol + from modules.ui import clear_prompt_symbol, paste_symbol, restore_progress_symbol self.paste = ToolButton(value=paste_symbol, elem_id="paste", tooltip="Read generation parameters from prompt or last generation if prompt is empty into user interface.") self.clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{self.id_part}_clear_prompt", tooltip="Clear prompt") @@ -135,3 +134,17 @@ class Toprow: def create_styles_ui(self): self.ui_styles = ui_prompt_styles.UiPromptStyles(self.id_part, self.prompt, self.negative_prompt) self.ui_styles.setup_apply_button(self.apply_styles) + + def hook_paste_guard(self): + assert self.negative_prompt is not None and self.paste is not None + + def guard(prompt: str) -> bool: + return gr.update(interactive=(not bool(prompt.strip()))) + + self.negative_prompt.change( + fn=guard, + inputs=[self.negative_prompt], + outputs=[self.paste], + show_progress="hidden", + queue=False, + )