context menus

This commit is contained in:
Vladimir Mandic
2023-11-03 11:41:08 -04:00
parent 996344c6f7
commit da3d5d0fc7
8 changed files with 105 additions and 32 deletions
+2
View File
@@ -75,6 +75,8 @@
//extraNetworks.js
"requestGet": "readonly",
"getENActiveTab": "readonly",
"quickApplyStyle": "readonly",
"quickSaveStyle": "readonly",
// from python
"localization": "readonly",
// progressbar.js
+25 -17
View File
@@ -86,25 +86,33 @@ const removeContextMenuOption = initResponse[1];
const addContextMenuEventListener = initResponse[2];
function initContextMenu() {
// Start example Context Menu Items
const generateOnRepeat = (genbuttonid, interruptbuttonid) => {
const genbutton = gradioApp().querySelector(genbuttonid);
const busy = document.getElementById('progressbar')?.style.display === 'block';
if (!busy) genbutton.click();
clearInterval(window.generateOnRepeatInterval);
window.generateOnRepeatInterval = setInterval(() => {
const pbBusy = document.getElementById('progressbar')?.style.display === 'block';
if (!pbBusy) genbutton.click();
}, 500);
const generateForever = (genbuttonid, interruptbuttonid) => {
if (window.generateOnRepeatInterval) {
log('generateForever: cancel');
clearInterval(window.generateOnRepeatInterval);
window.generateOnRepeatInterval = null;
} else {
log('generateForever: start');
const genbutton = gradioApp().querySelector(genbuttonid);
const busy = document.getElementById('progressbar')?.style.display === 'block';
if (!busy) genbutton.click();
window.generateOnRepeatInterval = setInterval(() => {
const pbBusy = document.getElementById('progressbar')?.style.display === 'block';
if (!pbBusy) genbutton.click();
}, 500);
}
};
const cancelGenerateForever = () => clearInterval(window.generateOnRepeatInterval);
appendContextMenuOption('#txt2img_generate', 'Generate forever', () => generateOnRepeat('#txt2img_generate', '#txt2img_interrupt'));
appendContextMenuOption('#img2img_generate', 'Generate forever', () => generateOnRepeat('#img2img_generate', '#img2img_interrupt'));
appendContextMenuOption('#txt2img_generate', 'Cancel generate forever', cancelGenerateForever);
appendContextMenuOption('#img2img_generate', 'Cancel generate forever', cancelGenerateForever);
appendContextMenuOption('#txt2img_generate', 'Show NVML overlay', initNVML);
appendContextMenuOption('#txt2img_generate', 'Hide NVML overlay', disableNVML);
for (const tab of ['txt2img', 'img2img']) {
for (const el of ['prompt > label > textarea', 'generate']) {
const id = `#${tab}_${el}`;
appendContextMenuOption(id, 'Copy to clipboard', () => navigator.clipboard.writeText(document.querySelector(`#${tab}_prompt > label > textarea`).value));
appendContextMenuOption(id, 'Generate forever', () => generateForever(`#${tab}_generate`));
appendContextMenuOption(id, 'Apply selected style', quickApplyStyle);
appendContextMenuOption(id, 'Quick save style', quickSaveStyle);
appendContextMenuOption(id, 'nVidia overlay', initNVML);
}
}
}
onUiLoaded(initContextMenu);
+20
View File
@@ -216,6 +216,18 @@ function applyStyles(styles) {
return newStyles.join('|');
}
function quickApplyStyle() {
const tabname = getENActiveTab();
const btnApply = gradioApp().getElementById(`${tabname}_extra_apply`);
if (btnApply) btnApply.click();
}
function quickSaveStyle() {
const tabname = getENActiveTab();
const btnSave = gradioApp().getElementById(`${tabname}_extra_quicksave`);
if (btnSave) btnSave.click();
}
// init
function setupExtraNetworksForTab(tabname) {
@@ -243,6 +255,14 @@ function setupExtraNetworksForTab(tabname) {
btnModel.onclick = () => btnModel.classList.toggle('toolbutton-selected');
tabs.appendChild(buttons);
// details
const detailsImg = gradioApp().getElementById(`${tabname}_extra_details_img`);
const detailsClose = gradioApp().getElementById(`${tabname}_extra_details_close`);
if (detailsImg && detailsClose) {
detailsImg.title = 'Close details';
detailsImg.onclick = () => detailsClose.click();
}
// search and description
const div = document.createElement('div');
div.classList.add('second-line');
+8 -2
View File
@@ -1,4 +1,4 @@
let nvmlInterval = true; // eslint-disable-line prefer-const
let nvmlInterval = null; // eslint-disable-line prefer-const
let nvmlEl = null;
let nvmlTable = null;
@@ -60,7 +60,13 @@ async function initNVML() {
gradioApp().appendChild(nvmlEl);
log('initNVML');
}
nvmlInterval = setInterval(updateNVML, 1000);
if (nvmlInterval) {
clearInterval(nvmlInterval);
nvmlInterval = null;
nvmlEl.style.display = 'none';
} else {
nvmlInterval = setInterval(updateNVML, 1000);
}
}
async function disableNVML() {
+2 -1
View File
@@ -157,7 +157,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
/* context menu (ie for the generate button) */
#context-menu { z-index: 9999; position: absolute; display: block; padding: var(--spacing-md); border: 2px solid var(--highlight-color); background: var(--background-fill-primary); color: var(--body-text-color); }
.context-menu-items { list-style: none; margin: 0; padding: 0; }
.context-menu-items { list-style: none; margin: 0; padding: 0; font-size: 0.9em; }
.context-menu-items a { display: block; padding: var(--spacing-md); cursor: pointer; font-weight: normal; }
.context-menu-items a:hover { background: var(--highlight-color) }
@@ -204,6 +204,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
.extra-network-cards .card:hover .actions { display: block; }
.extra-network-cards .card:hover .overlay .tags { display: block; }
.extra-network-cards .card .actions { font-size: 3em; display: none; text-align-last: right; cursor: pointer; font-variant: unicase; position: absolute; z-index: 100; right: 0; height: 0.7em; width: 100%; background: rgba(0, 0, 0, 0.40); }
.extra-details-close { position: fixed; top: 0.2em; right: 0.2em; z-index: 99; background: var(--button-secondary-background-fill) !important; }
#txt2img_description, #img2img_description { max-height: 63px; overflow-y: auto !important; }
#txt2img_description > label > textarea, #img2img_description > label > textarea { font-size: 0.9em }
+1 -1
View File
@@ -879,7 +879,7 @@ def load_diffuser(checkpoint_info=None, already_loaded_state_dict=None, timer=No
shared.log.error(f'Failed loading {op}: {checkpoint_info.path} auto={err1} diffusion={err2}')
return
elif os.path.isfile(checkpoint_info.path) and checkpoint_info.path.lower().endswith('.safetensors'):
diffusers_load_config["local_files_only"] = True
# diffusers_load_config["local_files_only"] = True
diffusers_load_config["extract_ema"] = shared.opts.diffusers_extract_ema
pipeline, model_type = detect_pipeline(checkpoint_info.path, op)
if pipeline is None:
+4 -1
View File
@@ -126,7 +126,7 @@ def process_interrogate(interrogation_function, mode, ii_input_files, ii_input_d
images = [f.name for f in ii_input_files]
else:
if not os.path.isdir(ii_input_dir):
log.error(f"Input directory not found: {ii_input_dir}")
log.error(f"Interrogate: Input directory not found: {ii_input_dir}")
return [gr.update(), None]
images = modules.shared.listfiles(ii_input_dir)
if ii_output_dir != "":
@@ -142,6 +142,9 @@ def process_interrogate(interrogation_function, mode, ii_input_files, ii_input_d
def interrogate(image):
if image is None:
log.error("Interrogate: no image selected")
return gr.update()
prompt = modules.shared.interrogator.interrogate(image.convert("RGB"))
return gr.update() if prompt is None else prompt
+43 -10
View File
@@ -393,6 +393,7 @@ class ExtraNetworksUi:
self.button_details: gr.Button = None
self.button_refresh: gr.Button = None
self.button_scan: gr.Button = None
self.button_quicksave: gr.Button = None
self.button_save: gr.Button = None
self.button_sort: gr.Button = None
self.button_apply: gr.Button = None
@@ -449,14 +450,14 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
return is_visible, gr.update(visible=is_visible), gr.update(variant=("secondary-down" if is_visible else "secondary"))
with ui.details:
details_close = ToolButton(symbols.close, elem_id=tabname+"_extra_details_close")
details_close = ToolButton(symbols.close, elem_id=tabname+"_extra_details_close", elem_classes=['extra-details-close'])
details_close.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[ui.details])
with gr.Row():
with gr.Column(scale=1):
text = gr.HTML('<div>title</div>')
ui.details_components.append(text)
with gr.Column(scale=1):
img = gr.Image(value=None, show_label=False, interactive=False, container=True)
img = gr.Image(value=None, show_label=False, interactive=False, container=False, show_download_button=False, show_info=False, elem_id=tabname+"_extra_details_img", elem_classes=['extra-details-img'])
ui.details_components.append(img)
with gr.Row():
btn_save_img = gr.Button('Replace', elem_classes=['small-button'])
@@ -468,12 +469,16 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
with gr.Row():
btn_save_desc = gr.Button('Save', elem_classes=['small-button'])
btn_delete_desc = gr.Button('Delete', elem_classes=['small-button'])
btn_close_info = gr.Button('Close', elem_classes=['small-button'])
btn_close_info.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[ui.details])
with gr.Tab('Model metadata'):
info = gr.JSON({}, show_label=False)
ui.details_components.append(info)
with gr.Row():
btn_save_info = gr.Button('Save', elem_classes=['small-button'])
btn_delete_info = gr.Button('Delete', elem_classes=['small-button'])
btn_close_info = gr.Button('Close', elem_classes=['small-button'])
btn_close_info.click(fn=lambda: gr.update(visible=False), inputs=[], outputs=[ui.details])
with gr.Tab('Embedded metadata'):
meta = gr.JSON({}, show_label=False)
ui.details_components.append(meta)
@@ -487,6 +492,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
ui.button_refresh = ToolButton(symbols.refresh, elem_id=tabname+"_extra_refresh")
ui.button_scan = ToolButton(symbols.scan, elem_id=tabname+"_extra_scan", visible=True)
ui.button_quicksave = ToolButton(symbols.book, elem_id=tabname+"_extra_quicksave", visible=False)
ui.button_save = ToolButton(symbols.book, elem_id=tabname+"_extra_save", visible=False)
ui.button_sort = ToolButton(symbols.sort, elem_id=tabname+"_extra_sort", visible=True)
ui.button_close = ToolButton(symbols.close, elem_id=tabname+"_extra_close", visible=True)
@@ -531,9 +537,9 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
image.thumbnail((512, 512), Image.HAMMING)
try:
image.save(ui.last_item.local_preview, quality=50)
shared.log.debug(f'Extra network save image: item={ui.last_item.name} filename={ui.last_item.local_preview}')
shared.log.debug(f'Extra network save image: item={ui.last_item.name} filename="{ui.last_item.local_preview}"')
except Exception as e:
shared.log.error(f'Extra network save image: item={ui.last_item.name} filename={ui.last_item.local_preview} {e}')
shared.log.error(f'Extra network save image: item={ui.last_item.name} filename="{ui.last_item.local_preview}" {e}')
return image
def fn_delete_img():
@@ -542,7 +548,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
for file in [f'{fn}{mid}{ext}' for ext in preview_extensions for mid in ['.thumb.', '.preview.', '.']]:
if os.path.exists(file):
os.remove(file)
shared.log.debug(f'Extra network delete image: item={ui.last_item.name} filename={file}')
shared.log.debug(f'Extra network delete image: item={ui.last_item.name} filename="{file}"')
return 'html/card-no-preview.png'
def fn_save_desc(desc):
@@ -554,7 +560,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
fn = os.path.splitext(ui.last_item.filename)[0] + '.txt'
with open(fn, 'w', encoding='utf-8') as f:
f.write(desc)
shared.log.debug(f'Extra network save desc: item={ui.last_item.name} filename={fn}')
shared.log.debug(f'Extra network save desc: item={ui.last_item.name} filename="{fn}"')
return desc
def fn_delete_desc(desc):
@@ -565,7 +571,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
else:
fn = os.path.splitext(ui.last_item.filename)[0] + '.txt'
if os.path.exists(fn):
shared.log.debug(f'Extra network delete desc: item={ui.last_item.name} filename={fn}')
shared.log.debug(f'Extra network delete desc: item={ui.last_item.name} filename="{fn}"')
os.remove(fn)
return ''
return desc
@@ -573,7 +579,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
def fn_save_info(info):
fn = os.path.splitext(ui.last_item.filename)[0] + '.json'
shared.writefile(info, fn, silent=True)
shared.log.debug(f'Extra network save info: item={ui.last_item.name} filename={fn}')
shared.log.debug(f'Extra network save info: item={ui.last_item.name} filename="{fn}"')
return info
def fn_delete_info(info):
@@ -581,7 +587,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
return info
fn = os.path.splitext(ui.last_item.filename)[0] + '.json'
if os.path.exists(fn):
shared.log.debug(f'Extra network delete info: item={ui.last_item.name} filename={fn}')
shared.log.debug(f'Extra network delete info: item={ui.last_item.name} filename="{fn}"')
os.remove(fn)
return ''
return info
@@ -656,7 +662,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
'''
desc = f'Name: {os.path.basename(item.name)}\nDescription: {item.description}\nPrompt: {item.prompt}\nNegative: {item.negative}\nExtra: {item.extra}\n'
text = f'''
<h2 style="border-bottom: 1px solid var(--button-primary-border-color); margin-bottom: 1em; margin-top: -1.3em !important;">{item.name}</h2>
<h2 style="border-bottom: 1px solid var(--button-primary-border-color); margin: 0em 0px 1em 0 !important">{item.name}</h2>
<table style="width: 100%; line-height: 1.3em;"><tbody>
<tr><td>Type</td><td>{page.title}</td></tr>
<tr><td>Alias</td><td>{getattr(item, 'alias', 'N/A')}</td></tr>
@@ -704,6 +710,32 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
res = show_details(text=None, img=None, desc=None, info=None, meta=None, params=params)
return res
def ui_quicksave_click(name):
from modules import paths, generation_parameters_copypaste
fn = os.path.join(paths.data_path, "params.txt")
if os.path.exists(fn):
with open(fn, "r", encoding="utf8") as file:
prompt = file.read()
else:
prompt = ''
params = generation_parameters_copypaste.parse_generation_parameters(prompt)
fn = os.path.join(shared.opts.styles_dir, os.path.splitext(name)[0] + '.json')
item = {
"type": 'Style',
"name": name,
"title": name,
"filename": fn,
"search_term": None,
"preview": None,
"description": '',
"prompt": params.get('Prompt', ''),
"negative": params.get('Negative prompt', ''),
"extra": '',
"local_preview": None,
}
shared.writefile(item, fn, silent=True)
shared.log.debug(f"Extra network quick save style: item={item['name']} filename='{fn}'")
def ui_sort_cards(msg):
shared.log.debug(f'Extra networks: {msg}')
return msg
@@ -715,6 +747,7 @@ def create_ui(container, button_parent, tabname, skip_indexing = False):
ui.button_refresh.click(fn=ui_refresh_click, _js='getENActivePage', inputs=[ui.search], outputs=ui.pages)
ui.button_scan.click(fn=ui_scan_click, _js='getENActivePage', inputs=[ui.search], outputs=ui.pages)
ui.button_save.click(fn=ui_save_click, inputs=[], outputs=ui.details_components + [ui.details])
ui.button_quicksave.click(fn=ui_quicksave_click, _js="() => prompt('Prompt name', '')", inputs=[ui.search], outputs=[])
ui.button_details.click(show_details, _js="getCardDetails", inputs=ui.details_components + [dummy_state], outputs=ui.details_components + [ui.details])
ui.state.change(state_change, inputs=[ui.state], outputs=[])
return ui