Add a resizable grid component and apply to extra networks tabs.

This commit is contained in:
Sj-Si 2024-05-20 16:34:53 -04:00
parent 4e9760c49f
commit 50a5ad88d7
7 changed files with 1352 additions and 92 deletions

View File

@ -153,33 +153,41 @@
</div> </div>
</div> </div>
<div class="extra-network-content--container"> <div class="extra-network-content--container">
<div class="extra-network-content extra-network-content--dirs-view styled-scrollbar"> <div class="extra-network-content--main-view resize-grid">
{dirs_html} <div class="resize-grid--row" style="{dirs_view_row_style}" {dirs_view_row_data_attributes}>
</div> <div class="resize-grid--col" style="flex: 1;">
<div class="extra-network-content--tree-and-cards-view resize-handle-row"> <div class="extra-network-content extra-network-content--dirs-view styled-scrollbar">
<div class="extra-network-content extra-network-content--tree-view resize-handle-col" {dirs_html}
style="{tree_view_style}"> </div>
<div id='{tabname}_{extra_networks_tabname}_tree_list_loading_splash' class='extra-network-list-splash'>
{tree_list_loading_splash_content}</div>
<div id='{tabname}_{extra_networks_tabname}_tree_list_no_data_splash'
class='extra-network-list-splash hidden'>{tree_list_no_data_splash_content}</div>
<div id='{tabname}_{extra_networks_tabname}_tree_list_scroll_area'
class='styled-scrollbar clusterize-scroll'>
<div id='{tabname}_{extra_networks_tabname}_tree_list_content_area'
class='extra-network-tree-content clusterize-content'></div>
</div> </div>
</div> </div>
<div class="extra-network-content extra-network-content--card-view extra-network-cards resize-handle-col" <div class="resize-grid--row" style="{tree_and_card_view_row_style}" {tree_and_card_view_row_data_attributes}>
style="{card_view_style}"> <div class="resize-grid--col extra-network-content extra-network-content--tree-view"
<div id='{tabname}_{extra_networks_tabname}_card_list_loading_splash' class='extra-network-list-splash'> style="{tree_view_style}" {tree_view_data_attributes}>
{card_list_loading_splash_content}</div> <div id='{tabname}_{extra_networks_tabname}_tree_list_loading_splash'
<div id='{tabname}_{extra_networks_tabname}_card_list_no_data_splash' class='extra-network-list-splash'>
class='extra-network-list-splash hidden'>{card_list_no_data_splash_content} {tree_list_loading_splash_content}</div>
<div id='{tabname}_{extra_networks_tabname}_tree_list_no_data_splash'
class='extra-network-list-splash hidden'>{tree_list_no_data_splash_content}</div>
<div id='{tabname}_{extra_networks_tabname}_tree_list_scroll_area'
class='styled-scrollbar clusterize-scroll'>
<div id='{tabname}_{extra_networks_tabname}_tree_list_content_area'
class='extra-network-tree-content clusterize-content'></div>
</div>
</div> </div>
<div id='{tabname}_{extra_networks_tabname}_card_list_scroll_area' <div class="resize-grid--col extra-network-content extra-network-content--card-view extra-network-cards"
class='styled-scrollbar clusterize-scroll'> style="{card_view_style}" {card_view_data_attributes}>
<div id='{tabname}_{extra_networks_tabname}_card_list_content_area' <div id='{tabname}_{extra_networks_tabname}_card_list_loading_splash'
class='extra-network-card-content clusterize-content'></div> class='extra-network-list-splash'>
{card_list_loading_splash_content}</div>
<div id='{tabname}_{extra_networks_tabname}_card_list_no_data_splash'
class='extra-network-list-splash hidden'>{card_list_no_data_splash_content}
</div>
<div id='{tabname}_{extra_networks_tabname}_card_list_scroll_area'
class='styled-scrollbar clusterize-scroll'>
<div id='{tabname}_{extra_networks_tabname}_card_list_content_area'
class='extra-network-card-content clusterize-content'></div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -15,6 +15,7 @@
debounce, debounce,
waitForBool, waitForBool,
copyToClipboard, copyToClipboard,
resizeGridSetup,
*/ */
/*eslint no-undef: "error"*/ /*eslint no-undef: "error"*/
@ -115,6 +116,7 @@ class ExtraNetworksTab {
tree_list_splash_state = null; tree_list_splash_state = null;
directory_filters = {}; directory_filters = {};
list_button_states = {}; list_button_states = {};
resize_grid = null;
constructor({tabname, extra_networks_tabname}) { constructor({tabname, extra_networks_tabname}) {
this.tabname = tabname; this.tabname = tabname;
this.extra_networks_tabname = extra_networks_tabname; this.extra_networks_tabname = extra_networks_tabname;
@ -195,6 +197,8 @@ class ExtraNetworksTab {
this.card_view_en = false; this.card_view_en = false;
this.directory_filters = {}; this.directory_filters = {};
this.list_button_states = {}; this.list_button_states = {};
this.resize_grid.destroy();
this.resize_grid = null;
} }
async registerPrompt() { async registerPrompt() {
@ -360,19 +364,9 @@ class ExtraNetworksTab {
const div_dirs = this.container_elem.querySelector(".extra-network-content--dirs-view"); const div_dirs = this.container_elem.querySelector(".extra-network-content--dirs-view");
const div_tree = this.container_elem.querySelector(".extra-network-content--tree-view"); const div_tree = this.container_elem.querySelector(".extra-network-content--tree-view");
const div_card = this.container_elem.querySelector(".extra-network-content--card-view"); const div_card = this.container_elem.querySelector(".extra-network-content--card-view");
// Remove "hidden" class if button is enabled, otherwise add it. this.resize_grid.toggleElem(div_dirs, this.dirs_view_en);
div_dirs.classList.toggle("hidden", !this.dirs_view_en); this.resize_grid.toggleElem(div_tree, this.tree_view_en);
div_tree.classList.toggle("hidden", !this.tree_view_en); this.resize_grid.toggleElem(div_card, this.card_view_en);
div_card.classList.toggle("hidden", !this.card_view_en);
// Apply the current resize handle classes.
const resize_handle_row = div_tree.closest(".resize-handle-row");
resize_handle_row.classList.toggle("resize-handle-hidden", !this.tree_view_en || !this.card_view_en);
if (this.tree_view_en && !this.card_view_en) {
div_tree.style.flexGrow = 1;
} else {
div_tree.style.flexGrow = null;
}
await Promise.all([this.setupTreeList(), this.setupCardList()]); await Promise.all([this.setupTreeList(), this.setupCardList()]);
this.tree_list.enable(this.tree_view_en); this.tree_list.enable(this.tree_view_en);
@ -404,21 +398,17 @@ class ExtraNetworksTab {
}); });
this.showControls(); this.showControls();
if (isNullOrUndefined(this.resize_grid)) {
const elem = this.container_elem.querySelector(".resize-grid");
this.resize_grid = resizeGridSetup(elem, {id: `${this.tabname_full}_resize_grid`});
}
const div_dirs = this.container_elem.querySelector(".extra-network-content--dirs-view"); const div_dirs = this.container_elem.querySelector(".extra-network-content--dirs-view");
const div_tree = this.container_elem.querySelector(".extra-network-content--tree-view"); const div_tree = this.container_elem.querySelector(".extra-network-content--tree-view");
const div_card = this.container_elem.querySelector(".extra-network-content--card-view"); const div_card = this.container_elem.querySelector(".extra-network-content--card-view");
div_dirs.classList.toggle("hidden", !this.dirs_view_en); this.resize_grid.toggleElem(div_dirs, this.dirs_view_en);
div_tree.classList.toggle("hidden", !this.tree_view_en); this.resize_grid.toggleElem(div_tree, this.tree_view_en);
div_card.classList.toggle("hidden", !this.card_view_en); this.resize_grid.toggleElem(div_card, this.card_view_en);
// Apply the current resize handle classes.
const resize_handle_row = div_tree.closest(".resize-handle-row");
resize_handle_row.classList.toggle("resize-handle-hidden", !this.tree_view_en || !this.card_view_en);
if (this.tree_view_en && !this.card_view_en) {
div_tree.style.flexGrow = 1;
} else {
div_tree.style.flexGrow = null;
}
this.tree_list.enable(this.tree_view_en); this.tree_list.enable(this.tree_view_en);
this.card_list.enable(this.card_view_en); this.card_list.enable(this.card_view_en);
@ -1195,22 +1185,9 @@ async function extraNetworksControlTreeViewOnClick(event) {
tab.tree_view_en = "selected" in btn.dataset; tab.tree_view_en = "selected" in btn.dataset;
const div_tree = tab.container_elem.querySelector(".extra-network-content--tree-view"); const div_tree = tab.container_elem.querySelector(".extra-network-content--tree-view");
div_tree.classList.toggle("hidden", !tab.tree_view_en); tab.resize_grid.toggleElem(div_tree, tab.tree_view_en);
tab.tree_list.enable(tab.tree_view_en); tab.tree_list.enable(tab.tree_view_en);
// Apply the resize-handle-hidden class to the resize-handle-row.
// NOTE: This can be simplified using only css with the ":has" selector however
// this is only recently supported in firefox. So for now we just add a class
// to the resize-handle-row instead.
const resize_handle_row = div_tree.closest(".resize-handle-row");
resize_handle_row.classList.toggle("resize-handle-hidden", !tab.card_view_en || !tab.tree_view_en);
if (tab.tree_view_en && !tab.card_view_en) {
div_tree.style.flexGrow = 1;
} else {
div_tree.style.flexGrow = null;
}
// If the tree list hasn't loaded yet, we need to force it to load. // If the tree list hasn't loaded yet, we need to force it to load.
// This can happen if tree view is disabled by default or before refresh. // This can happen if tree view is disabled by default or before refresh.
// Then after refresh, enabling the tree view will require a load. // Then after refresh, enabling the tree view will require a load.
@ -1232,9 +1209,8 @@ function extraNetworksControlDirsViewOnClick(event) {
btn.toggleAttribute("data-selected"); btn.toggleAttribute("data-selected");
tab.dirs_view_en = "selected" in btn.dataset; tab.dirs_view_en = "selected" in btn.dataset;
tab.container_elem.querySelector( const div_dirs = tab.container_elem.querySelector(".extra-network-content--dirs-view");
".extra-network-content--dirs-view" tab.resize_grid.toggleElem(div_dirs, tab.dirs_view_en);
).classList.toggle("hidden", !tab.dirs_view_en);
tab.applyListButtonStates(); tab.applyListButtonStates();
} }
@ -1250,24 +1226,10 @@ async function extraNetworksControlCardViewOnClick(event) {
btn.toggleAttribute("data-selected"); btn.toggleAttribute("data-selected");
tab.card_view_en = "selected" in btn.dataset; tab.card_view_en = "selected" in btn.dataset;
const div_tree = tab.container_elem.querySelector(".extra-network-content--tree-view");
const div_card = tab.container_elem.querySelector(".extra-network-content--card-view"); const div_card = tab.container_elem.querySelector(".extra-network-content--card-view");
div_card.classList.toggle("hidden", !tab.card_view_en); tab.resize_grid.toggleElem(div_card, tab.card_view_en);
tab.card_list.enable(tab.card_view_en); tab.card_list.enable(tab.card_view_en);
// Apply the resize-handle-hidden class to the resize-handle-row.
// NOTE: This can be simplified using only css with the ":has" selector however
// this is only recently supported in firefox. So for now we just add a class
// to the resize-handle-row instead.
const resize_handle_row = div_card.closest(".resize-handle-row");
resize_handle_row.classList.toggle("resize-handle-hidden", !tab.card_view_en || !tab.tree_view_en);
if (tab.tree_view_en && !tab.card_view_en) {
div_tree.style.flexGrow = 1;
} else {
div_tree.style.flexGrow = null;
}
// If the tree list hasn't loaded yet, we need to force it to load. // If the tree list hasn't loaded yet, we need to force it to load.
// This can happen if tree view is disabled by default or before refresh. // This can happen if tree view is disabled by default or before refresh.
// Then after refresh, enabling the tree view will require a load. // Then after refresh, enabling the tree view will require a load.

1165
javascript/resizeGrid.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -665,3 +665,27 @@ function waitForVisible(elem, callback) {
}).observe(elem); }).observe(elem);
if (!callback) return new Promise(resolve => callback = resolve); if (!callback) return new Promise(resolve => callback = resolve);
} }
function cssRelativeUnitToPx(css_value, target) {
// https://stackoverflow.com/a/66569574
// doesnt work on `%` unit.
target = target || document.body;
const units = {
px: x => x, // no conversion needed here
rem: x => x * parseFloat(getComputedStyle(document.documentElement).fontSize),
em: x => x * parseFloat(getComputedStyle(target).fontSize),
vw: x => x / 100 * window.innerWidth,
vh: x => x / 100 * window.innerHeight,
};
const re = new RegExp(`^([-+]?(?:\\d+(?:\\.\\d+)?))(${Object.keys(units).join('|')})$`, 'i');
const matches = css_value.toString().trim().match(re);
if (matches) {
const value = Number(matches[1]);
const unit = matches[2].toLocaleLowerCase();
if (unit in units) {
return units[unit](value);
}
}
return css_value;
}

View File

@ -267,7 +267,8 @@ options_templates.update(options_section(('extra_networks', "Extra Networks", "s
"extra_networks_tree_view_default_enabled": OptionInfo(False, "Show the Extra Networks tree view by default").needs_reload_ui(), "extra_networks_tree_view_default_enabled": OptionInfo(False, "Show the Extra Networks tree view by default").needs_reload_ui(),
"extra_networks_card_view_default_enabled": OptionInfo(True, "Show the Extra Networks card view by default").needs_reload_ui(), "extra_networks_card_view_default_enabled": OptionInfo(True, "Show the Extra Networks card view by default").needs_reload_ui(),
"extra_networks_tree_view_show_files": OptionInfo(True, "Show files in tree view.").info("Disabling this option will remove file entries from the tree view and only show directories.").needs_reload_ui(), "extra_networks_tree_view_show_files": OptionInfo(True, "Show files in tree view.").info("Disabling this option will remove file entries from the tree view and only show directories.").needs_reload_ui(),
"extra_networks_tree_view_default_width": OptionInfo(180, "Default width for the Extra Networks directory tree view", gr.Number).needs_reload_ui(), "extra_networks_dirs_view_default_height": OptionInfo(90, "Default height for the Directory Buttons view", gr.Number).info("in pixels").needs_reload_ui(),
"extra_networks_tree_view_default_width": OptionInfo(180, "Default width for the Extra Networks directory tree view", gr.Number).info("in pixels").needs_reload_ui(),
"extra_networks_add_text_separator": OptionInfo(" ", "Extra networks separator").info("extra text to add before <...> when adding extra network to prompt"), "extra_networks_add_text_separator": OptionInfo(" ", "Extra networks separator").info("extra text to add before <...> when adding extra network to prompt"),
"ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order").needs_reload_ui(), "ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order").needs_reload_ui(),
"textual_inversion_print_at_load": OptionInfo(False, "Print a list of Textual Inversion embeddings when loading model"), "textual_inversion_print_at_load": OptionInfo(False, "Print a list of Textual Inversion embeddings when loading model"),

View File

@ -842,6 +842,13 @@ class ExtraNetworksPage:
tree_view_en = shared.opts.extra_networks_tree_view_default_enabled tree_view_en = shared.opts.extra_networks_tree_view_default_enabled
card_view_en = shared.opts.extra_networks_card_view_default_enabled card_view_en = shared.opts.extra_networks_card_view_default_enabled
dirs_view_row_size = shared.opts.extra_networks_dirs_view_default_height
tree_view_size = shared.opts.extra_networks_tree_view_default_width
if shared.opts.extra_networks_card_width:
card_view_size = shared.opts.extra_networks_card_width
else:
card_view_size = 50
return self.pane_tpl.format( return self.pane_tpl.format(
**{ **{
"tabname": tabname, "tabname": tabname,
@ -855,8 +862,14 @@ class ExtraNetworksPage:
"btn_dirs_view_data_attributes": "data-selected" if dirs_view_en else "", "btn_dirs_view_data_attributes": "data-selected" if dirs_view_en else "",
"btn_tree_view_data_attributes": "data-selected" if tree_view_en else "", "btn_tree_view_data_attributes": "data-selected" if tree_view_en else "",
"btn_card_view_data_attributes": "data-selected" if card_view_en else "", "btn_card_view_data_attributes": "data-selected" if card_view_en else "",
"tree_view_style": f"flex-basis: {shared.opts.extra_networks_tree_view_default_width}px;", "dirs_view_row_style": f"flex: 0 0 {dirs_view_row_size}px;",
"card_view_style": "flex-grow: 1;", "tree_and_card_view_row_style": "flex: 1 0 0px;", # expand to fill
"tree_view_style": f"flex: 0 0 {tree_view_size}px;",
"card_view_style": f"flex: 1 0 {card_view_size}px;",
"dirs_view_row_data_attributes": "data-min-size=\"5vh\"",
"tree_and_card_view_row_data_attributes": "data-min-size=\"5vh\"",
"tree_view_data_attributes": "data-min-size=\"10vw\"",
"card_view_data_attributes": "data-min-size=\"10vw\"",
"dirs_html": dirs_html, "dirs_html": dirs_html,
"card_list_loading_splash_content": card_list_loading_splash_content, "card_list_loading_splash_content": card_list_loading_splash_content,
"card_list_no_data_splash_content": card_list_no_data_splash_content, "card_list_no_data_splash_content": card_list_no_data_splash_content,

103
style.css
View File

@ -1156,6 +1156,8 @@ div.accordions > div.input-accordion.input-accordion-open{
top: 0.5em; top: 0.5em;
} }
/* ==== RESIZING EVENT FLAGS ==== */
body.resizing { body.resizing {
cursor: col-resize !important; cursor: col-resize !important;
} }
@ -1164,10 +1166,21 @@ body.resizing * {
pointer-events: none !important; pointer-events: none !important;
} }
body.resizing .resize-handle { body.resizing .resize-handle,
body.resizing .resize-grid--handle {
pointer-events: initial !important; pointer-events: initial !important;
} }
body.resizing.resize-grid-col {
cursor: col-resize !important;
}
body.resizing.resize-grid-row {
cursor: row-resize !important;
}
/* ==== RESIZE HANDLE ==== */
.resize-handle { .resize-handle {
position: relative; position: relative;
cursor: col-resize; cursor: col-resize;
@ -1186,6 +1199,78 @@ body.resizing .resize-handle {
border-left: 1px dashed var(--border-color-primary); border-left: 1px dashed var(--border-color-primary);
} }
/* ==== RESIZE HANDLE GRID ==== */
.resize-grid {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
/* prevent elements from oversizing the container. */
min-width: 0;
min-height: 0;
}
.resize-grid--row {
display: flex;
flex-direction: row;
overflow: hidden;
flex-wrap: nowrap;
/* prevent elements from oversizing the container. */
min-width: 0;
min-height: 0;
}
.resize-grid--col {
position: relative;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
flex-wrap: nowrap;
/* prevent elements from oversizing the container. */
min-width: 0;
min-height: 0;
}
.resize-grid--handle {
position: relative;
height: 100%;
width: 100%;
z-index: 0;
background: transparent;
}
.resize-grid--handle::after {
content: "";
position: absolute;
z-index: -1;
}
.resize-grid--row-handle {
cursor: row-resize;
}
.resize-grid--row-handle::after {
left: 0;
right: 0;
top: 50%;
transform: translateY(-50%);
border-top: 1px dashed var(--border-color-primary);
}
.resize-grid--col-handle {
cursor: col-resize;
}
.resize-grid--col-handle::after {
top: 0;
bottom: 0;
left: 50%;
transform: translateX(-50%);
border-left: 1px dashed var(--border-color-primary);
}
/* ========================= */ /* ========================= */
.clusterize-scroll { .clusterize-scroll {
width: 100%; width: 100%;
@ -1246,18 +1331,18 @@ body.resizing .resize-handle {
} }
.extra-network-content--dirs-view { .extra-network-content--dirs-view {
flex: 0 1 min-content; display: block;
flex-flow: row wrap; flex: 1;
max-height: 20%;
gap: var(--spacing-sm);
overflow: clip auto; overflow: clip auto;
border: 1px solid var(--block-border-color); border: 1px solid var(--block-border-color);
padding: var(--spacing-md); padding: var(--spacing-md);
} }
.extra-network-content--tree-and-cards-view { .extra-network-content--dirs-view > button {
flex: 1; margin: var(--spacing-xs) !important;
flex-direction: row; }
.extra-network-content--main-view {
min-height: 0; /* prevent children from oversizing this container */ min-height: 0; /* prevent children from oversizing this container */
} }
@ -1493,6 +1578,8 @@ body.resizing .resize-handle {
grid-gap: var(--spacing-sm); grid-gap: var(--spacing-sm);
place-items: center stretch; place-items: center stretch;
text-align: center; text-align: center;
/* prevents height from changing on overflow */
min-width: 0;
} }
.tree-list-item:hover { .tree-list-item:hover {