From 6e0b7927cdee2006c9b2bc55dbd34885b2ae80cc Mon Sep 17 00:00:00 2001 From: anapnoe <124302297+anapnoe@users.noreply.github.com> Date: Fri, 3 Mar 2023 17:30:42 +0200 Subject: [PATCH] extra networks aside menu alternative --- html/svg/stack-line.svg | 1 + javascript/ui.js | 223 +++++++++++++++++++++++----------------- modules/shared.py | 1 + modules/ui.py | 1 + style.css | 127 +++++++++++++++++++++-- 5 files changed, 249 insertions(+), 104 deletions(-) create mode 100644 html/svg/stack-line.svg diff --git a/html/svg/stack-line.svg b/html/svg/stack-line.svg new file mode 100644 index 00000000..1bd316f6 --- /dev/null +++ b/html/svg/stack-line.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/javascript/ui.js b/javascript/ui.js index 5f7820ea..4cf1cb43 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -385,6 +385,59 @@ onUiUpdate(function(){ }) + let selectedTabItemId = "tab_txt2img"; + let net_container = gradioApp().querySelector('#txt2img_extra_networks_row'); + let net_menu_open = false; + const net_menu = gradioApp().querySelector('#extra_networks_menu'); + + /* switch tab item from instance button, this is the only method that works i havent found a workaround yet */ + const Observe = (sel, opt, cb) => { + const Obs = new MutationObserver((m) => [...m].forEach(cb)); + gradioApp().querySelectorAll(sel).forEach(el => Obs.observe(el, opt)); + } + Observe("#tabs > div.tabitem", { + attributesList: ["style"], attributeOldValue: true, }, (m) => { + if(m.target.style.display === 'block'){ + let idx = parseInt(m.target.getAttribute("tab-item")); + selectedTabItemId = m.target.id; + tabItemChanged(idx); + } + }) + + function tabItemChanged(idx){ + gradioApp().querySelectorAll('#tabs > div > button.bg-white, #nav_menu_header_tabs > button.bg-white').forEach(function (tab){ + tab.classList.remove("bg-white"); + }) + + gradioApp().querySelectorAll('#tabs > div > button:nth-child('+(idx+1)+'), #nav_menu_header_tabs > button:nth-child('+(idx+1)+')').forEach(function (tab){ + tab.classList.add("bg-white"); + }) + //gardio removes listeners and attributes from tab buttons we add them again here + gradioApp().querySelectorAll('#tabs > div > button').forEach(function (tab, index){ + tab.setAttribute("tab-id", index); + tab.removeEventListener('mouseup', navTabClicked); + tab.addEventListener('mouseup', navTabClicked); + }) + + netMenuVisibility(); + } + + function netMenuVisibility(){ + if(selectedTabItemId.indexOf("2img") != -1){ + net_menu.style.display = "block"; + let nid = selectedTabItemId.split("_")[1]; + net_container = gradioApp().querySelector('#'+nid+'_extra_networks_row'); + if(net_container.classList.contains("aside")){ + toggleMenu(net_menu_open, net_menu, net_container, null); + net_menu.style.display = "block"; + }else{ + net_menu.style.display = "none"; + } + }else{ + net_menu.style.display = "none"; + } + } + // menu function disableScroll() { scrollTop = window.pageYOffset || document.documentElement.scrollTop; @@ -398,8 +451,12 @@ onUiUpdate(function(){ function enableScroll() { window.onscroll = function() {} - } + } + function getPos(el) { + let rect=el.getBoundingClientRect(); + return {x:rect.left,y:rect.top}; + } function toggleMenu(isopen, icon, panel, func) { if(isopen){ @@ -414,27 +471,16 @@ onUiUpdate(function(){ enableScroll(); } } - - function getPos(el) { - let rect=el.getBoundingClientRect(); - return {x:rect.left,y:rect.top}; - } - + // mobile nav menu const tabs_menu = gradioApp().querySelector('#tabs > div:first-child'); - const nav_menu = gradioApp().querySelector('#nav_menu'); + const nav_menu = gradioApp().querySelector('#nav_menu'); const header = gradioApp().querySelector('#header-top'); let menu_open = false; - let z_menu = nav_menu.cloneNode(true); -/* let pos = getPos(nav_menu); - clone.style.position = 'fixed'; - clone.style.left = pos.x+'px'; - clone.style.top = pos.y+'px'; - clone.style.zIndex = 99999; */ + const z_menu = nav_menu.cloneNode(true); z_menu.id = "clone_nav_menu"; - header.parentElement.append(z_menu); - function toggleNavMenu(e) { - //e.preventDefault(); + header.parentElement.append(z_menu); + function toggleNavMenu(e) { e.stopPropagation(); menu_open = !menu_open; toggleMenu(menu_open, nav_menu, tabs_menu, toggleNavMenu); @@ -458,6 +504,18 @@ onUiUpdate(function(){ } quick_menu.addEventListener('click', toggleQuickMenu); + function toggleNetMenu(e) { + net_menu_open = !net_menu_open; + e.preventDefault(); + e.stopPropagation(); + toggleMenu(net_menu_open, net_menu, net_container, null); + + } + net_menu.addEventListener('click', toggleNetMenu); + gradioApp().querySelectorAll('button[id$="2img_extra_networks"]').forEach((elem) => { + elem.addEventListener('click', toggleNetMenu); + }) + // additional ui styles let styleobj = {}; @@ -500,7 +558,6 @@ onUiUpdate(function(){ }) viewportOrder(opts.ui_views_order.toLowerCase()); - // sd max resolution output function sdMaxOutputResolution(value) { gradioApp().querySelectorAll('[id$="2img_width"] input,[id$="2img_height"] input').forEach((elem) => { @@ -514,14 +571,13 @@ onUiUpdate(function(){ }) sdMaxOutputResolution(opts.sd_max_resolution); - function extra_networks_visibility(value){ - gradioApp().querySelectorAll('[id$="2img_extra_networks_row"]').forEach((elem) => { + gradioApp().querySelectorAll('[id$="2img_extra_networks_row"]').forEach((elem) => { if(value){ elem.classList.remove("!hidden"); }else{ elem.classList.add("!hidden"); - } + } }) } gradioApp().querySelector("#setting_extra_networks_default_visibility input").addEventListener('click', function (e) { @@ -550,8 +606,24 @@ onUiUpdate(function(){ }) }) extra_networks_cards_visible_rows(opts.extra_networks_cards_visible_rows); + + function extra_networks_aside(value){ + gradioApp().querySelectorAll('[id$="2img_extra_networks_row"]').forEach((elem) => { + if(value){ + elem.classList.add("aside"); + }else{ + elem.classList.remove("aside"); + } + netMenuVisibility(); + }) + } + gradioApp().querySelector("#setting_extra_networks_aside input").addEventListener('click', function (e) { + extra_networks_aside(e.target.checked); + }) + extra_networks_aside(opts.extra_networks_aside); + - //hidden ui tabs + // hidden - header ui tabs let radio_hidden_html=""; let radio_header_html=""; let hiddentabs={}; @@ -563,8 +635,7 @@ onUiUpdate(function(){ setting_ui_header_tabs.style.display = "none"; const maintabs = gradioApp().querySelectorAll('#tabs > div:first-child > button'); - const tabitem = gradioApp().querySelectorAll('#tabs > div.tabitem'); - + const tabitems = gradioApp().querySelectorAll('#tabs > div.tabitem'); function tabOpsSave(setting){ const iEvent = new Event("input"); @@ -584,13 +655,10 @@ onUiUpdate(function(){ styleobj[key] = "#tabs > div:first-child > button:nth-child("+(index+1)+"){display:block;}"; } }) - - + tabOpsSave(setting_ui_hidden_tabs); tabsHeaderChange(); - - } - + } function tabsHeaderChange() { const keys = Object.keys(headertabs); setting_ui_header_tabs.value = ""; @@ -609,39 +677,24 @@ onUiUpdate(function(){ } - const Observe = (sel, opt, cb) => { - const Obs = new MutationObserver((m) => [...m].forEach(cb)); - gradioApp().querySelectorAll(sel).forEach(el => Obs.observe(el, opt)); - } - - Observe("#tabs > div.tabitem", { - attributesList: ["style"], attributeOldValue: true, }, (m) => { - if(m.target.style.display === 'block'){ - let idx = parseInt(m.target.getAttribute("tab-item")); - tabSelected(idx); - } - }) - - function tabSelected(idx){ - - gradioApp().querySelectorAll('#tabs > div > button.bg-white, #nav_menu_header_tabs > button.bg-white').forEach(function (tab){ - tab.classList.remove("bg-white"); - }) - - gradioApp().querySelectorAll('#tabs > div > button:nth-child('+(idx+1)+'), #nav_menu_header_tabs > button:nth-child('+(idx+1)+')').forEach(function (tab){ - tab.classList.add("bg-white"); - }) - } - - function navigate2Tab(idx){ + function navigate2TabItem(idx){ gradioApp().querySelectorAll('#tabs > div.tabitem').forEach(function (tabitem, index){ if(idx == index){ tabitem.style.display = "block"; + //tabitem.classList.add("wtf"); }else{ tabitem.style.display = "none"; + //tabitem.classList.remove("wtf"); } }) } + + function navTabClicked(e){ + const idx = parseInt(e.currentTarget.getAttribute("tab-id")); + console.log(idx); + navigate2TabItem(idx); + } + maintabs.forEach(function (elem, index) { let tabvalue = elem.innerText.replaceAll(" ", ""); @@ -660,21 +713,17 @@ onUiUpdate(function(){ radio_hidden_html += ''; radio_header_html += ''; - tabitem[index].setAttribute("tab-item", index); + tabitems[index].setAttribute("tab-item", index); + elem.setAttribute("tab-id", index); let clonetab = elem.cloneNode(true); clonetab.id = tabvalue+"_clone"; - parent_header_tabs.append(clonetab); - clonetab.setAttribute("tab-id", index); - - clonetab.addEventListener('click', function (e) { - const idx = parseInt(e.currentTarget.getAttribute("tab-id")); - navigate2Tab(idx); - }) + parent_header_tabs.append(clonetab); + clonetab.addEventListener('click', navTabClicked); + }) - let div = document.createElement("div"); div.id = "hidden_radio_tabs_container"; div.classList.add("flex", "flex-wrap", "gap-2"); @@ -687,7 +736,6 @@ onUiUpdate(function(){ div.innerHTML = radio_header_html; setting_ui_header_tabs.parentElement.appendChild(div); - // hidden tabs gradioApp().querySelector("#hidden_radio_tabs_container").addEventListener('click', function (e) { if (e.target && e.target.matches("input[type='checkbox']")) { @@ -709,7 +757,7 @@ onUiUpdate(function(){ tabsHiddenChange(); - // add to quick settings + // add - remove quicksettings const settings_submit = gradioApp().querySelector('#settings_submit'); const quick_parent = gradioApp().querySelector("#quicksettings_overflow_container"); @@ -752,9 +800,19 @@ onUiUpdate(function(){ }) - + // draggable reordable quicksettings const container = gradioApp().querySelector("#quicksettings_overflow_container"); let draggables; + let lastElemAfter; + let islastChild; + let timeout; + + function preventBehavior(e){ + e.stopPropagation(); + e.preventDefault(); + return false; + } + // function that gets the element next of cursor/touch function getElementAfter(container, y){ return draggables.reduce((closest, child) => { @@ -768,18 +826,6 @@ onUiUpdate(function(){ }, { offset: Number.NEGATIVE_INFINITY } ).element; } - - let lastElemAfter; - let islastChild; - let timeout; - - function preventBehavior(e){ - e.stopPropagation(); - e.preventDefault(); - return false; - } - - function dragOrderChange(elementAfter, isComplete, delem) { if(lastElemAfter !== elementAfter || islastChild){ @@ -832,7 +878,6 @@ onUiUpdate(function(){ let elementAfter = getElementAfter(container, y); dragOrderChange(elementAfter); } - function touchstart(e){ e.currentTarget.draggable = "false"; let target = e.currentTarget; @@ -846,8 +891,7 @@ onUiUpdate(function(){ target.addEventListener('touchend', touchend); target.addEventListener('touchcancel', touchcancel); - } - + } function touchend(e){ e.currentTarget.draggable = "true"; clearTimeout(timeout); @@ -857,7 +901,6 @@ onUiUpdate(function(){ let elementAfter = getElementAfter(container, y); dragOrderChange(elementAfter, true, e.currentTarget); } - function touchcancel(e){ e.currentTarget.draggable = "true"; clearTimeout(timeout); @@ -870,7 +913,6 @@ onUiUpdate(function(){ e.currentTarget.draggable = "false"; e.currentTarget.classList.add("dragging"); } - function dragend(e){ e.stopPropagation(); e.preventDefault(); @@ -879,7 +921,6 @@ onUiUpdate(function(){ let elementAfter = getElementAfter(container, y); dragOrderChange(elementAfter, true, e.currentTarget); } - function dragOver(e) { e.preventDefault(); let y = e.clientY; @@ -887,10 +928,7 @@ onUiUpdate(function(){ dragOrderChange(elementAfter); } - - function actionQuickSettingsDraggable(checked){ - - + function actionQuickSettingsDraggable(checked){ if(checked){ draggables = Array.from(gradioApp().querySelectorAll('#quicksettings_overflow_container > div:not(.dragging)')); gradioApp().addEventListener('drop', preventBehavior); @@ -898,12 +936,8 @@ onUiUpdate(function(){ gradioApp().removeEventListener('drop', preventBehavior); } - gradioApp().querySelectorAll('#quicksettings_overflow_container > div').forEach(function (elem){ - - //elem.setAttribute("draggable", checked); elem.draggable = checked; - if(checked){ elem.addEventListener('touchstart', touchstart); @@ -920,12 +954,10 @@ onUiUpdate(function(){ elem.removeEventListener('dragstart', dragstart, false); elem.removeEventListener('dragend', dragend, false); elem.removeEventListener('dragover', dragOver, false); - } }) } - gradioApp().querySelector('#quicksettings_draggable').addEventListener('click', function (e) { if (e.target && e.target.matches("input[type='checkbox']")) { actionQuickSettingsDraggable(e.target.checked); @@ -933,9 +965,8 @@ onUiUpdate(function(){ }) - updateOpStyles(); - + /* anapnoe ui end */ diff --git a/modules/shared.py b/modules/shared.py index 5e3de28c..b131faf5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -445,6 +445,7 @@ options_templates.update(options_section(('extra_networks', "Extra Networks"), { "extra_networks_default_visibility": OptionInfo(True, "Extra Networks default visibility"), "extra_networks_cards_size": OptionInfo(1, "Card size for extra networks", gr.Slider, {"minimum": 0.8, "maximum": 2, "step": 0.1}), "extra_networks_cards_visible_rows": OptionInfo(1, "Visible card rows for extra networks", gr.Slider, {"minimum": 1, "maximum": 3, "step": 1}), + "extra_networks_aside": OptionInfo(True, "Extra Networks aside view"), })) diff --git a/modules/ui.py b/modules/ui.py index 8d1a5416..e5a6d53d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -1733,6 +1733,7 @@ def create_ui(): component = create_setting_component(k, item.section[0], is_quicksettings=True) component_dict[k] = component + gr.Row(elem_id="extra_networks_menu") gr.Row(elem_id="quick_menu") parameters_copypaste.connect_paste_params_buttons() diff --git a/style.css b/style.css index 465d3e68..fbeddae3 100644 --- a/style.css +++ b/style.css @@ -14,6 +14,7 @@ License: GNU General Public License --extra-networks-height: calc((var(--extra-networks-card-real-size) * var(--extra-networks-visible-rows)) + ( var(--inside-padding-size) * 2 ) ); --extra-networks-name-size: calc(var(--extra-networks-card-size) * 1em); + --top-header-padding-top:1rem; --top-header-height:60px; @@ -47,6 +48,7 @@ body { /* padding: 10px; */ padding-left: 1rem; padding-right: 1rem; + padding-top: var(--top-header-padding-top); } @@ -73,6 +75,7 @@ body { right: 0; } +#extra_networks_menu, #quick_menu { z-index: 9999; background-color: var(--input-bg-color); @@ -441,8 +444,8 @@ body { [id$="2img_extra_networks"]::before { - -webkit-mask: url(./file=html/svg/pantone-line.svg) no-repeat 50% 50%; - mask: url(./file=html/svg/pantone-line.svg) no-repeat 50% 50%; + -webkit-mask: url(./file=html/svg/stack-line.svg) no-repeat 50% 50%; + mask: url(./file=html/svg/stack-line.svg) no-repeat 50% 50%; } #img2img_actions_column [id$="interrogate"]::before @@ -514,9 +517,15 @@ body { - - - +/* +.tabitem.wtf +{ + display:block !important; +} +.tabitem:not(.wtf){ + display:none !important; +} +*/ .livePreview > img, #img2img_gallery .overflow-y-auto, @@ -716,7 +725,7 @@ body { position:fixed; z-index:10000; left:1rem; - top: calc((var(--top-header-height) - 38px) / 2); + top: calc((var(--top-header-padding-top) + var(--top-header-height) - 38px) / 2); } /* offcanvas quicksettings menu */ @@ -779,7 +788,7 @@ min-height: 34px; } - +#extra_networks_menu::before, #quick_menu::before { content: ' '; display: inline-block; @@ -797,10 +806,17 @@ min-height: 34px; transform: translate(-50%, -50%) scale(1.0); } - +#extra_networks_menu::before{ + -webkit-mask: url(./file=html/svg/stack-line.svg) no-repeat 50% 50%; + mask: url(./file=html/svg/stack-line.svg) no-repeat 50% 50%; +} +#extra_networks_menu.fixed, +#extra_networks_menu:hover, #quick_menu:hover { background-color: var(--primary-color); } +#extra_networks_menu.fixed::before, +#extra_networks_menu:hover::before, #quick_menu:hover::before { background-color: var(--main-bg-color); } @@ -2295,6 +2311,89 @@ ul.list-none { /******************/ /* extra-network-cards */ /******************/ +/* +#quicksettings_overflow { + position: fixed; + z-index: 9999; + display: block; + width: 90%; + background-color: var(--main-bg-color) !important; + top: var(--top-header-height); + bottom: 0px; + padding: 16px; + + right: 0; + max-width: 480px; + transform: translateX(100%); + transition: all 0.25s ease 0s; + box-shadow: rgba(0,0,0,0) -30px 0 30px -30px; + overflow: hidden; + +} + +#quicksettings_overflow_container { + overflow-y: auto; + height: calc(100% - 45px); +} + +#quicksettings_overflow.open { + transform: translateX(0); + box-shadow: rgba(0,0,0,0.4) -30px 0 30px -30px; +} + +#quicksettings_overflow > div { + margin-bottom: var(--outside-gap-size); +} +*/ + +[id$="2img_extra_networks_row"].aside +{ + position: fixed; + top: var(--top-header-height); + width: 90%; + right: 0; + height: calc(100% - var(--top-header-height)); + max-width: 480px; + z-index: 9999; + transform: translateX(100%); + transition: all 0.25s ease 0s; + box-shadow: rgba(0,0,0,0) -30px 0 30px -30px; + padding: calc(1rem - var(--outside-gap-size)); + background-color: var(--main-bg-color) !important; +} + +[id$="2img_extra_networks_row"].aside.open +{ + transform: translateX(0); + box-shadow: rgba(0,0,0,0.4) -30px 0 30px -30px; +} + + + +[id$="2img_extra_networks_row"].aside > div:first-child +{ + border: 0 !important; +} + +[id$="2img_extra_networks_row"].aside > div:first-child > div:first-child +{ + display: none; + border: 0; +} +[id$="2img_extra_networks_row"].aside.\!hidden, +[id$="2img_extra_networks_row"].aside > div:first-child > div:last-child +{ + display: block !important; +} +[id$="2img_extra_close"]{ + display:none; +} + +[id$="2img_checkpoints_subdirs"] button{ + max-height:34px; + margin-bottom: var(--inside-padding-size); +} + .extra-network-cards .nocards, .extra-network-thumbs .nocards { @@ -2362,6 +2461,18 @@ ul.list-none { scroll-snap-type: x mandatory; } +[id$="2img_extra_networks_row"].aside .extra-network-cards +{ + /*grid-template-columns: repeat(auto-fill, var(--extra-networks-card-real-size)); */ + /*grid-template-columns: repeat(calc( var(--extra-networks-card-size) * 4), calc( var(--extra-networks-card-size) * 25%));*/ + grid-template-columns: repeat(auto-fit, minmax(calc(var(--extra-networks-card-size) * 25%), 1fr)); + overflow-y: auto; + scroll-snap-type: y mandatory; + overflow-x: hidden; + grid-template-rows: auto; + grid-auto-flow: row; + max-height: calc(100vh - 216px); +} .extra-network-cards .card {