diff options
-rw-r--r-- | extensions-builtin/mobile/javascript/mobile.js | 6 | ||||
-rw-r--r-- | extensions-builtin/resize-handle/javascript/resize-handle.js | 106 | ||||
-rw-r--r-- | extensions-builtin/resize-handle/style.css | 10 | ||||
-rw-r--r-- | javascript/progressbar.js | 47 | ||||
-rw-r--r-- | modules/progress.py | 3 | ||||
-rw-r--r-- | scripts/xyz_grid.py | 25 | ||||
-rw-r--r-- | style.css | 17 |
7 files changed, 168 insertions, 46 deletions
diff --git a/extensions-builtin/mobile/javascript/mobile.js b/extensions-builtin/mobile/javascript/mobile.js index 12cae4b7..652f07ac 100644 --- a/extensions-builtin/mobile/javascript/mobile.js +++ b/extensions-builtin/mobile/javascript/mobile.js @@ -20,7 +20,13 @@ function reportWindowSize() { var button = gradioApp().getElementById(tab + '_generate_box'); var target = gradioApp().getElementById(currentlyMobile ? tab + '_results' : tab + '_actions_column'); target.insertBefore(button, target.firstElementChild); + + gradioApp().getElementById(tab + '_results').classList.toggle('mobile', currentlyMobile); } } window.addEventListener("resize", reportWindowSize); + +onUiLoaded(function() { + reportWindowSize(); +}); diff --git a/extensions-builtin/resize-handle/javascript/resize-handle.js b/extensions-builtin/resize-handle/javascript/resize-handle.js new file mode 100644 index 00000000..a07a01d2 --- /dev/null +++ b/extensions-builtin/resize-handle/javascript/resize-handle.js @@ -0,0 +1,106 @@ +onUiLoaded(async() => { + const GRADIO_MIN_WIDTH = 320; + const GRID_TEMPLATE_COLUMNS = '1fr 16px 1fr'; + const PAD = 16; + const DEBOUNCE_TIME = 100; + + const R = { + tracking: false, + parent: null, + parentWidth: null, + leftCol: null, + leftColStartWidth: null, + screenX: null, + }; + + let resizeTimer; + + const leftCols = [ + gradioApp().querySelector('#txt2img_settings'), + gradioApp().querySelector('#img2img_settings'), + ]; + + function setLeftColGridTemplate(el, width) { + el.style.gridTemplateColumns = `${width}px 16px 1fr`; + } + + function displayResizeHandle(parent) { + if (window.innerWidth < GRADIO_MIN_WIDTH * 2 + PAD * 4) { + parent.style.display = 'flex'; + if (R.handle != null) { + R.handle.style.opacity = '0'; + } + return false; + } else { + parent.style.display = 'grid'; + if (R.handle != null) { + R.handle.style.opacity = '100'; + } + return true; + } + } + + function setup() { + for (const leftCol of leftCols) { + const parent = leftCol.parentElement; + const rightCol = parent.lastElementChild; + + if (!displayResizeHandle(parent)) { + return; + } + + parent.style.display = 'grid'; + parent.style.gap = '0'; + parent.style.gridTemplateColumns = GRID_TEMPLATE_COLUMNS; + + const resizeHandle = document.createElement('div'); + resizeHandle.classList.add('resize-handle'); + parent.insertBefore(resizeHandle, rightCol); + + resizeHandle.addEventListener('mousedown', (evt) => { + R.tracking = true; + R.parent = parent; + R.parentWidth = parent.offsetWidth; + R.handle = resizeHandle; + R.leftCol = leftCol; + R.leftColStartWidth = leftCol.offsetWidth; + R.screenX = evt.screenX; + }); + } + } + + window.addEventListener('mousemove', (evt) => { + if (R.tracking) { + const delta = R.screenX - evt.screenX; + const leftColWidth = Math.max(Math.min(R.leftColStartWidth - delta, R.parent.offsetWidth - GRADIO_MIN_WIDTH - PAD), GRADIO_MIN_WIDTH); + setLeftColGridTemplate(R.parent, leftColWidth); + } + }); + + window.addEventListener('mouseup', () => R.tracking = false); + + window.addEventListener('resize', () => { + clearTimeout(resizeTimer); + + resizeTimer = setTimeout(() => { + for (const leftCol of leftCols) { + const parent = leftCol.parentElement; + + if (displayResizeHandle(parent) && parent.style.gridTemplateColumns != GRID_TEMPLATE_COLUMNS) { + const oldParentWidth = R.parentWidth; + const newParentWidth = parent.offsetWidth; + const widthL = parseInt(parent.style.gridTemplateColumns.split(' ')[0]); + + const ratio = newParentWidth / oldParentWidth; + + const newWidthL = Math.max(Math.floor(ratio * widthL), GRADIO_MIN_WIDTH); + setLeftColGridTemplate(parent, newWidthL); + + R.parentWidth = newParentWidth; + } + } + }, DEBOUNCE_TIME); + }); + + setup(); +}); diff --git a/extensions-builtin/resize-handle/style.css b/extensions-builtin/resize-handle/style.css new file mode 100644 index 00000000..0e18267a --- /dev/null +++ b/extensions-builtin/resize-handle/style.css @@ -0,0 +1,10 @@ +.resize-handle{ + cursor: col-resize; + grid-column: 2 / 3; + min-width: 8px !important; + max-width: 8px !important; + height: 100%; + border-left: 1px dashed var(--border-color-primary); + user-select: none; + margin-left: 8px; +}
\ No newline at end of file diff --git a/javascript/progressbar.js b/javascript/progressbar.js index 29299787..a7c69937 100644 --- a/javascript/progressbar.js +++ b/javascript/progressbar.js @@ -69,7 +69,6 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre var dateStart = new Date(); var wasEverActive = false; var parentProgressbar = progressbarContainer.parentNode; - var parentGallery = gallery ? gallery.parentNode : null; var divProgress = document.createElement('div'); divProgress.className = 'progressDiv'; @@ -80,32 +79,26 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre divProgress.appendChild(divInner); parentProgressbar.insertBefore(divProgress, progressbarContainer); - if (parentGallery) { + if (gallery) { var livePreview = document.createElement('div'); livePreview.className = 'livePreview'; - parentGallery.insertBefore(livePreview, gallery); + gallery.insertBefore(livePreview, gallery.firstElementChild); } var removeProgressBar = function() { setTitle(""); parentProgressbar.removeChild(divProgress); - if (parentGallery) parentGallery.removeChild(livePreview); + if (gallery) gallery.removeChild(livePreview); atEnd(); }; - var fun = function(id_task, id_live_preview) { - request("./internal/progress", {id_task: id_task, id_live_preview: id_live_preview}, function(res) { + var funProgress = function(id_task) { + request("./internal/progress", {id_task: id_task, live_preview: false}, function(res) { if (res.completed) { removeProgressBar(); return; } - var rect = progressbarContainer.getBoundingClientRect(); - - if (rect.width) { - divProgress.style.width = rect.width + "px"; - } - let progressText = ""; divInner.style.width = ((res.progress || 0) * 100.0) + '%'; @@ -119,7 +112,6 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre progressText += " ETA: " + formatTime(res.eta); } - setTitle(progressText); if (res.textinfo && res.textinfo.indexOf("\n") == -1) { @@ -142,14 +134,21 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre return; } + if (onProgress) { + onProgress(res); + } - if (res.live_preview && gallery) { - rect = gallery.getBoundingClientRect(); - if (rect.width) { - livePreview.style.width = rect.width + "px"; - livePreview.style.height = rect.height + "px"; - } + setTimeout(() => { + funProgress(id_task, res.id_live_preview); + }, opts.live_preview_refresh_period || 500); + }, function() { + removeProgressBar(); + }); + }; + var funLivePreview = function(id_task, id_live_preview) { + request("./internal/progress", {id_task: id_task, id_live_preview: id_live_preview}, function(res) { + if (res.live_preview && gallery) { var img = new Image(); img.onload = function() { livePreview.appendChild(img); @@ -160,18 +159,14 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre img.src = res.live_preview; } - - if (onProgress) { - onProgress(res); - } - setTimeout(() => { - fun(id_task, res.id_live_preview); + funLivePreview(id_task, res.id_live_preview); }, opts.live_preview_refresh_period || 500); }, function() { removeProgressBar(); }); }; - fun(id_task, 0); + funProgress(id_task, 0); + funLivePreview(id_task, 0); } diff --git a/modules/progress.py b/modules/progress.py index f405f07f..e32b59dd 100644 --- a/modules/progress.py +++ b/modules/progress.py @@ -48,6 +48,7 @@ def add_task_to_queue(id_job): class ProgressRequest(BaseModel):
id_task: str = Field(default=None, title="Task ID", description="id of the task to get progress for")
id_live_preview: int = Field(default=-1, title="Live preview image ID", description="id of last received last preview image")
+ live_preview: bool = Field(default=True, title="Include live preview", description="boolean flag indicating whether to include the live preview image")
class ProgressResponse(BaseModel):
@@ -91,7 +92,7 @@ def progressapi(req: ProgressRequest): id_live_preview = req.id_live_preview
shared.state.set_current_image()
- if opts.live_previews_enable and shared.state.id_live_preview != req.id_live_preview:
+ if opts.live_previews_enable and req.live_preview and shared.state.id_live_preview != req.id_live_preview:
image = shared.state.current_image
if image is not None:
buffered = io.BytesIO()
diff --git a/scripts/xyz_grid.py b/scripts/xyz_grid.py index 3d52591b..3d9fe691 100644 --- a/scripts/xyz_grid.py +++ b/scripts/xyz_grid.py @@ -200,6 +200,10 @@ def list_to_csv_string(data_list): return o.getvalue().strip()
+def csv_string_to_list_strip(data_str):
+ return list(map(str.strip, chain.from_iterable(csv.reader(StringIO(data_str)))))
+
+
class AxisOption:
def __init__(self, label, type, apply, format_value=format_value_add_label, confirm=None, cost=0.0, choices=None):
self.label = label
@@ -438,7 +442,6 @@ class Script(scripts.Script): with gr.Column():
csv_mode = gr.Checkbox(label='Use text inputs instead of dropdowns', value=False, elem_id=self.elem_id("csv_mode"))
-
with gr.Row(variant="compact", elem_id="swap_axes"):
swap_xy_axes_button = gr.Button(value="Swap X/Y axes", elem_id="xy_grid_swap_axes_button")
swap_yz_axes_button = gr.Button(value="Swap Y/Z axes", elem_id="yz_grid_swap_axes_button")
@@ -472,19 +475,19 @@ class Script(scripts.Script): choices = self.current_axis_options[axis_type].choices
has_choices = choices is not None
- current_values = axis_values
- current_dropdown_values = axis_values_dropdown
if has_choices:
choices = choices()
if csv_mode:
- current_dropdown_values = list(filter(lambda x: x in choices, current_dropdown_values))
- current_values = list_to_csv_string(current_dropdown_values)
+ if axis_values_dropdown:
+ axis_values = list_to_csv_string(list(filter(lambda x: x in choices, axis_values_dropdown)))
+ axis_values_dropdown = []
else:
- current_dropdown_values = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(axis_values)))]
- current_dropdown_values = list(filter(lambda x: x in choices, current_dropdown_values))
+ if axis_values:
+ axis_values_dropdown = list(filter(lambda x: x in choices, csv_string_to_list_strip(axis_values)))
+ axis_values = ""
- return (gr.Button.update(visible=has_choices), gr.Textbox.update(visible=not has_choices or csv_mode, value=current_values),
- gr.update(choices=choices if has_choices else None, visible=has_choices and not csv_mode, value=current_dropdown_values))
+ return (gr.Button.update(visible=has_choices), gr.Textbox.update(visible=not has_choices or csv_mode, value=axis_values),
+ gr.update(choices=choices if has_choices else None, visible=has_choices and not csv_mode, value=axis_values_dropdown))
x_type.change(fn=select_axis, inputs=[x_type, x_values, x_values_dropdown, csv_mode], outputs=[fill_x_button, x_values, x_values_dropdown])
y_type.change(fn=select_axis, inputs=[y_type, y_values, y_values_dropdown, csv_mode], outputs=[fill_y_button, y_values, y_values_dropdown])
@@ -501,7 +504,7 @@ class Script(scripts.Script): def get_dropdown_update_from_params(axis, params):
val_key = f"{axis} Values"
vals = params.get(val_key, "")
- valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals))) if x]
+ valslist = csv_string_to_list_strip(vals)
return gr.update(value=valslist)
self.infotext_fields = (
@@ -532,7 +535,7 @@ class Script(scripts.Script): if opt.choices is not None and not csv_mode:
valslist = vals_dropdown
else:
- valslist = [x.strip() for x in chain.from_iterable(csv.reader(StringIO(vals))) if x]
+ valslist = csv_string_to_list_strip(vals)
if opt.type == int:
valslist_ext = []
@@ -499,11 +499,15 @@ table.popup-table .link{ /* live preview */
.progressDiv{
- position: relative;
+ position: absolute;
height: 20px;
background: #b4c0cc;
border-radius: 3px !important;
- margin-bottom: -3px;
+ top: -20px;
+}
+
+[id$=_results].mobile{
+ margin-top: 28px;
}
.dark .progressDiv{
@@ -528,12 +532,9 @@ table.popup-table .link{ .livePreview{
position: absolute;
z-index: 300;
- background-color: white;
- margin: -4px;
-}
-
-.dark .livePreview{
- background-color: rgb(17 24 39 / var(--tw-bg-opacity));
+ background: var(--background-fill-primary);
+ width: 100%;
+ height: 100%;
}
.livePreview img{
|