From 6d076522c48f7bc347ff4e893f9e80e17d50e737 Mon Sep 17 00:00:00 2001 From: Sj-Si Date: Wed, 8 May 2024 18:24:49 -0400 Subject: [PATCH] Add option to change left click behavior for directory filter. --- javascript/extraNetworks.js | 59 ++++++++++++++++++++++++--- javascript/extraNetworksClusterize.js | 18 +------- modules/shared_options.py | 1 + style.css | 10 ++--- 4 files changed, 61 insertions(+), 27 deletions(-) diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index 88a1d79f7..5d7399c2b 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -34,6 +34,7 @@ const storedPopupIds = {}; const extraPageUserMetadataEditors = {}; const extra_networks_tabs = {}; var extra_networks_refresh_internal_debounce_timer; +let extra_networks_curr_options = {}; /** Boolean flags used along with utils.js::waitForBool(). */ // Set true when we first load the UI options. @@ -740,13 +741,22 @@ class ExtraNetworksTab { async selectTreeListRow(elem) { elem.dataset.selected = ""; + + const left_click_opt = opts.extra_networks_directory_filter_click_behavior.toLowerCase().trim(); + let recurse; + if (left_click_opt === "click") { + recurse = elem.classList.contains("short-pressed") && !elem.classList.contains("long-pressed"); + } else { + recurse = elem.classList.contains("long-pressed"); + } + elem.classList.toggle("recurse", recurse); + this.tree_list.setRowSelected(elem); let directory_filter = elem.dataset.path; if ("directoryFilterOverride" in elem.dataset) { directory_filter = elem.dataset.directoryFilterOverride; } - const recurse = elem.classList.contains("short-pressed") && !elem.classList.contains("long-pressed"); this.setTreeListRecursionDepth(elem.dataset.divId, recurse); this.addDirectoryFilter(elem.dataset.divId, directory_filter, recurse); await this.tree_list.update(); @@ -754,6 +764,7 @@ class ExtraNetworksTab { this.list_button_states[elem.dataset.divId] = { short_pressed: elem.classList.contains("short-pressed"), long_pressed: elem.classList.contains("long-pressed"), + recurse: elem.classList.contains("recurse"), }; } @@ -761,6 +772,7 @@ class ExtraNetworksTab { delete elem.dataset.selected; elem.classList.remove("short-pressed"); elem.classList.remove("long-pressed"); + elem.classList.remove("recurse"); this.tree_list.setRowDeselected(elem); this.setTreeListRecursionDepth(elem.dataset.divId, false); this.removeDirectoryFilter(elem.dataset.divId); @@ -775,12 +787,21 @@ class ExtraNetworksTab { directory_filter = elem.dataset.directoryFilterOverride; } - const recurse = elem.classList.contains("short-pressed") && !elem.classList.contains("long-pressed"); + const left_click_opt = opts.extra_networks_directory_filter_click_behavior.toLowerCase().trim(); + let recurse; + if (left_click_opt === "click") { + recurse = elem.classList.contains("short-pressed") && !elem.classList.contains("long-pressed"); + } else { + recurse = elem.classList.contains("long-pressed"); + } + elem.classList.toggle("recurse", recurse); + this.addDirectoryFilter(elem.dataset.divId, directory_filter, recurse); this.list_button_states[elem.dataset.divId] = { short_pressed: elem.classList.contains("short-pressed"), long_pressed: elem.classList.contains("long-pressed"), + recurse: elem.classList.contains("recurse"), }; } @@ -788,6 +809,7 @@ class ExtraNetworksTab { delete elem.dataset.selected; elem.classList.remove("short-pressed"); elem.classList.remove("long-pressed"); + elem.classList.remove("recurse"); this.removeDirectoryFilter(elem.dataset.divId); delete this.list_button_states[elem.dataset.divId]; } @@ -813,7 +835,8 @@ class ExtraNetworksTab { if (tree_btn_exists) { tree_btn.classList.toggle("short-pressed", state.short_pressed); tree_btn.classList.toggle("long-pressed", state.long_pressed); - if (state.short_pressed || state.long_pressed) { + tree_btn.classList.toggle("recurse", state.recurse); + if (state.short_pressed || state.long_pressed || state.recurse) { await this.selectTreeListRow(tree_btn); } else { await this.deselectTreeListRow(tree_btn); @@ -825,7 +848,8 @@ class ExtraNetworksTab { if (dirs_btn_exists) { dirs_btn.classList.toggle("short-pressed", state.short_pressed); dirs_btn.classList.toggle("long-pressed", state.long_pressed); - if (state.short_pressed || state.long_pressed) { + dirs_btn.classList.toggle("recurse", state.recurse); + if (state.short_pressed || state.long_pressed || state.recurse) { this.selectDirsViewButton(dirs_btn); } else { this.deselectDirsViewButton(dirs_btn); @@ -1379,6 +1403,7 @@ async function extraNetworksBtnTreeViewChevronOnClick(event) { const pane = btn.closest(".extra-network-pane"); const tab = extra_networks_tabs[pane.dataset.tabnameFull]; + tab.setTreeListRecursionDepth(btn.dataset.divId, !("expanded" in btn.dataset)); await tab.tree_list.toggleRowExpanded(btn.dataset.divId); tab.applyListButtonStates(); @@ -1492,6 +1517,30 @@ function extraNetworksBtnCopyPathOnClick(event) { // ==== MAIN SETUP ==== +function extraNetworksOnOptionsChanged() { + initialUiOptionsLoaded.state = true; + + try { + const keys = Object.keys(opts).filter(k => k.startsWith("extra_networks_")); + const changes = {}; + for (const k of keys) { + if (!(k in opts) || isNullOrUndefined(opts[k])) { + continue; + } + if (!(k in extra_networks_curr_options)) { + extra_networks_curr_options[k] = opts[k]; + } else { + if (extra_networks_curr_options[k] !== opts[k]) { + changes[k] = extra_networks_curr_options[k]; + } + extra_networks_curr_options[k] = opts[k]; + } + } + } catch (error) { + console.warn("Error parsing options:", error); + } +} + function extraNetworksSetupEventDelegators() { /** Sets up event delegators for all extraNetworks tabs. * @@ -1867,4 +1916,4 @@ window.addEventListener("keyup", (event) => { }); onUiLoaded(extraNetworksSetup); -onOptionsChanged(() => initialUiOptionsLoaded.state = true); +onOptionsChanged(extraNetworksOnOptionsChanged); diff --git a/javascript/extraNetworksClusterize.js b/javascript/extraNetworksClusterize.js index e57e1d28b..7c5ed9fe7 100644 --- a/javascript/extraNetworksClusterize.js +++ b/javascript/extraNetworksClusterize.js @@ -628,23 +628,7 @@ class ExtraNetworksClusterizeCardList extends ExtraNetworksClusterize { if (!v.visible) { continue; } - /* - if (this.directory_filter_str && this.directory_filter_recurse) { - // Filter as directory with recurse shows all nested children. - // Case sensitive comparison against the relative directory of each object. - v.visible = v.rel_parent_dir.startsWith(this.directory_filter_str); - if (!v.visible) { - continue; - } - } else { - // Filtering as directory without recurse only shows direct children. - // Case sensitive comparison against the relative directory of each object. - if (this.directory_filter_str && this.directory_filter_str !== v.rel_parent_dir) { - v.visible = false; - continue; - } - } - */ + // Narrow the filtered items based on the search string. // Custom filter for items marked search_only=true. if (v.search_only) { diff --git a/modules/shared_options.py b/modules/shared_options.py index efcbe49b5..ff98f3276 100644 --- a/modules/shared_options.py +++ b/modules/shared_options.py @@ -254,6 +254,7 @@ options_templates.update(options_section(('extra_networks', "Extra Networks", "s "extra_networks_show_hidden_models_cards": OptionInfo("Never", "Show cards for models in hidden directories", gr.Radio, {"choices": ["Always", "When searched", "Never"]}).info("\"When searched\" will only show cards when the search string has 4 characters or more and the search string matches either the model name or the hidden directory name (or any of its subdirectories).").needs_reload_ui(), "extra_networks_show_hidden_models_in_tree_view": OptionInfo(False, "Show entries for models inside hidden directories in the tree view.").info("This option only applies if the \"Show buttons for hidden directories\" option is enabled.").needs_reload_ui(), "extra_networks_tree_view_expand_depth_default": OptionInfo(1, "Expand the tree view to this folder depth by default.").needs_reload_ui(), + "extra_networks_directory_filter_click_behavior": OptionInfo("Long Press", "Filter directory recursively left mouse button action.", gr.Radio, {"choices": ["Click", "Long Press"]}).info("Sets the default left mouse button action required to filter a directory recursively (show children in all subdirectories) vs filtering to only show direct children of the selected directory."), "extra_networks_default_multiplier": OptionInfo(1.0, "Default multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 2.0, "step": 0.01}), "extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks").info("in pixels"), "extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks").info("in pixels"), diff --git a/style.css b/style.css index c95a8752d..c3341a2ac 100644 --- a/style.css +++ b/style.css @@ -1706,12 +1706,12 @@ body.resizing .resize-handle { background: var(--button-secondary-background-fill-hover); } -.extra-network-dirs-view-button.short-pressed:not(.long-pressed) { +.extra-network-dirs-view-button.recurse { background: var(--button-primary-background-fill); border-color: var(--button-primary-border-color); } -.extra-network-dirs-view-button.short-pressed:not(.long-pressed,.pressed):hover { +.extra-network-dirs-view-button.recurse:not(.pressed):hover { -webkit-transition: all 0.05s ease-in-out; transition: all 0.05s ease-in-out; background: var(--button-primary-background-fill-hover); @@ -1728,11 +1728,11 @@ body.resizing .resize-handle { z-index: -1; } -.extra-network-dirs-view-button:not(.short-pressed:not(.long-pressed))::after { +.extra-network-dirs-view-button:not(.recurse)::after { background: var(--button-secondary-background-fill-hover); } -.extra-network-dirs-view-button.short-pressed:not(.long-pressed)::after { +.extra-network-dirs-view-button.recurse::after { background: var(--button-primary-background-fill-hover); } @@ -1786,7 +1786,7 @@ body.resizing .resize-handle { transition: all 0.8s cubic-bezier(0.215, 0.61, 0.355, 1); } -.tree-list-item.short-pressed:not(.long-pressed) .tree-list-item-action--chevron .chevron-icon-single { +.tree-list-item.recurse .tree-list-item-action--chevron .chevron-icon-single { stroke: var(--button-primary-border-color); }