diff --git a/aspect_ratio_helper/_constants.py b/aspect_ratio_helper/_constants.py
index e497af6..e4b6a40 100644
--- a/aspect_ratio_helper/_constants.py
+++ b/aspect_ratio_helper/_constants.py
@@ -6,6 +6,7 @@ MIN_DIMENSION = 64
ARH_EXPAND_BY_DEFAULT_KEY = 'arh_expand_by_default'
ARH_HIDE_ACCORDION_BY_DEFAULT_KEY = 'arh_hide_accordion_by_default'
ARH_UI_COMPONENT_ORDER_KEY = 'arh_ui_component_order_key'
+ARH_UI_JAVASCRIPT_SELECTION_METHOD = 'arh_ui_javascript_selection_method'
ARH_JAVASCRIPT_ASPECT_RATIO_SHOW_KEY = 'arh_javascript_aspect_ratio_show'
ARH_JAVASCRIPT_ASPECT_RATIOS_KEY = 'arh_javascript_aspect_ratio'
ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY = 'arh_show_max_width_or_height'
diff --git a/aspect_ratio_helper/_settings.py b/aspect_ratio_helper/_settings.py
index ad453ef..b1fa5b7 100644
--- a/aspect_ratio_helper/_settings.py
+++ b/aspect_ratio_helper/_settings.py
@@ -28,10 +28,10 @@ OPT_KEY_TO_DEFAULT_MAP = {
_constants.ARH_HIDE_ACCORDION_BY_DEFAULT_KEY: True,
_constants.ARH_UI_COMPONENT_ORDER_KEY:
DEFAULT_UI_COMPONENT_ORDER_KEY,
+ _constants.ARH_UI_JAVASCRIPT_SELECTION_METHOD: 'Aspect Ratios Dropdown',
_constants.ARH_JAVASCRIPT_ASPECT_RATIO_SHOW_KEY: True,
_constants.ARH_JAVASCRIPT_ASPECT_RATIOS_KEY:
- '1:1, 3:2, 4:3, 5:4, 16:9, 1.85:1, 2.35:1, 2.39:1, 2.40:1, '
- '21:9, 1.375:1, 1.66:1, 1.75:1',
+ '1:1, 3:2, 4:3, 5:4, 16:9',
_constants.ARH_SHOW_MAX_WIDTH_OR_HEIGHT_KEY: False,
_constants.ARH_MAX_WIDTH_OR_HEIGHT_KEY:
_constants.MAX_DIMENSION / 2,
@@ -110,6 +110,23 @@ def on_ui_settings():
section=_constants.SECTION,
),
)
+ shared.opts.add_option(
+ key=_constants.ARH_UI_JAVASCRIPT_SELECTION_METHOD,
+ info=shared.OptionInfo(
+ default=OPT_KEY_TO_DEFAULT_MAP.get(
+ _constants.ARH_UI_JAVASCRIPT_SELECTION_METHOD,
+ ),
+ label='JavaScript selection method',
+ component=gr.Dropdown,
+ component_args=lambda: {
+ 'choices': [
+ 'Aspect Ratios Dropdown',
+ 'Default Options Button',
+ ],
+ },
+ section=_constants.SECTION,
+ ),
+ )
# accordion options
shared.opts.add_option(
diff --git a/javascript/aspectRatioController.js b/javascript/aspectRatioController.js
index 75edf5d..8a78c6c 100644
--- a/javascript/aspectRatioController.js
+++ b/javascript/aspectRatioController.js
@@ -26,13 +26,11 @@ const getCurrentImage = () => {
return document.getElementById(currentTabImageId).querySelector('img');
}
-// utility functions
const roundToClosestMultiple = (num, multiple) => {
- const rounded = Math.round(Number(num) / multiple) * multiple;
+ const rounded = Math.round(Number(num) / multiple) * multiple;
return rounded;
}
-
const aspectRatioFromStr = (ar) => {
if (!ar.includes(':')) return;
return ar.split(':').map(x => Number(x));
@@ -80,34 +78,35 @@ const reverseAllOptions = () => {
});
}
-class SelectController {
+class OptionPickingController {
constructor(page, defaultOptions, controller) {
this.page = page;
- this.options = [...new Set([...defaultOptions, ...getOptions()])];
+ this.options = this.getOptions(defaultOptions);
this.switchButton = gradioApp().getElementById(page + '_res_switch_btn');
const wrapperDiv = document.createElement('div');
wrapperDiv.setAttribute("id", `${this.page}_size_toolbox`);
wrapperDiv.setAttribute("class", "flex flex-col relative col gap-4");
wrapperDiv.setAttribute("style", "min-width: min(320px, 100%); flex-grow: 0");
- wrapperDiv.innerHTML = `
-
-
-
- `;
+ wrapperDiv.innerHTML = this.getElementInnerHTML();
const parent = this.switchButton.parentNode;
parent.removeChild(this.switchButton);
wrapperDiv.appendChild(this.switchButton);
parent.insertBefore(wrapperDiv, parent.lastChild.previousElementSibling);
+ this.getPickerElement().onchange = this.pickerChanged(controller);
+ this.switchButton.onclick = this.switchButtonOnclick(controller);
+ }
+
+ getOptions(defaultOptions) {
+ return [...new Set([...defaultOptions, ...getOptions()])];
+ }
+
+ pickerChanged(controller) {
const originalBGC = this.switchButton.style.backgroundColor;
- this.getSelectElement().onchange = () => {
- const picked = this.getCurrentOption();
+ return () => {
+ const picked = this.getCurrentOption();
if (_IMAGE === picked) {
this.switchButton.disabled = true;
this.switchButton.style.backgroundColor = 'black';
@@ -118,8 +117,10 @@ class SelectController {
controller.setAspectRatio(picked);
};
+ }
- this.switchButton.onclick = () => {
+ switchButtonOnclick(controller) {
+ return () => {
reverseAllOptions();
const picked = this.getCurrentOption();
if (_LOCK === picked) {
@@ -130,17 +131,88 @@ class SelectController {
};
}
- getSelectElement() {
+ getElementInnerHTML() {
+ throw new Error('Not implemented');
+ }
+
+ getPickerElement() {
+ throw new Error('Not implemented');
+ }
+
+ getCurrentOption() {
+ throw new Error('Not implemented');
+ }
+}
+
+
+class SelectOptionPickingController extends OptionPickingController {
+ constructor(page, defaultOptions, controller) {
+ super(page, defaultOptions, controller);
+ }
+
+ getElementInnerHTML() {
+ return `
+
+
+
+ `;
+ }
+
+ getPickerElement() {
return gradioApp().getElementById(`${this.page}_select_aspect_ratio`);
}
getCurrentOption() {
- const selectElement = this.getSelectElement();
+ const selectElement = this.getPickerElement();
const options = Array.from(selectElement);
return options[selectElement.selectedIndex].value;
}
}
+class DefaultOptionsButtonOptionPickingController extends OptionPickingController {
+ constructor(page, defaultOptions, controller) {
+ super(page, defaultOptions, controller);
+ this.currentIndex = 0;
+ this.getPickerElement().onclick = this.pickerChanged(controller);
+ }
+
+ pickerChanged(controller) {
+ return () => {
+ this.currentIndex = (this.currentIndex + 1) % this.options.length;
+ this.getPickerElement().querySelector('button').textContent = this.getCurrentOption();
+ super.pickerChanged(controller)();
+ }
+ }
+
+ getElementInnerHTML() {
+ const classes = Array.from(this.switchButton.classList);
+ return `
+
+
+
+ `;
+ }
+
+ getPickerElement() {
+ return gradioApp().getElementById(`${this.page}_ar_default_options_button`);
+ }
+
+ getOptions(defaultOptions) {
+ return defaultOptions;
+ }
+
+ getCurrentOption() {
+ return this.options[this.currentIndex || 0];
+ }
+}
+
+
class SliderController {
constructor(element) {
this.element = element
@@ -201,7 +273,12 @@ class AspectRatioController {
});
})
- this.selectController = new SelectController(page, defaultOptions, this);
+ if (window.opts.arh_ui_javascript_selection_method === 'Default Options Button') {
+ this.optionPickingControler = new DefaultOptionsButtonOptionPickingController(page, defaultOptions, this);
+ } else {
+ this.optionPickingControler = new SelectOptionPickingController(page, defaultOptions, this);
+ }
+
this.setAspectRatio(_OFF);
}
@@ -278,11 +355,17 @@ class AspectRatioController {
const [width, height] = clampToBoundaries(w, h)
- const inputEvent = new Event("input", { bubbles: true});
+ const inputEvent = new Event("input", {bubbles: true});
this.widthContainer.setVal(width);
this.widthContainer.triggerEvent(inputEvent);
this.heightContainer.setVal(height);
this.heightContainer.triggerEvent(inputEvent);
+ this.heightContainer.inputs.forEach(input => {
+ dimensionChange({target: input}, false, true);
+ });
+ this.widthContainer.inputs.forEach(input => {
+ dimensionChange({target: input}, true, false);
+ });
}
static observeStartup(key, page, defaultOptions, postSetup = (_) => {}) {
@@ -291,7 +374,7 @@ class AspectRatioController {
const heightContainer = gradioApp().querySelector(`#${page}_height`);
// wait for width and height containers to exist.
- if (widthContainer && heightContainer) {
+ if (widthContainer && heightContainer) {
observer.disconnect();
if (!window.opts.arh_javascript_aspect_ratio_show) {
return;
@@ -319,7 +402,7 @@ const addImg2ImgTabSwitchClickListeners = (controller) => {
img2imgTabButtons.forEach(button => {
button.addEventListener('click', (_) => {
// set aspect ratio is RECALLED to change to the image specific to the newly selected tab.
- if (controller.selectController.getCurrentOption() === _IMAGE) {
+ if (controller.optionPickingControler.getCurrentOption() === _IMAGE) {
controller.setAspectRatio(_IMAGE);
}
@@ -332,7 +415,7 @@ const addImg2ImgTabSwitchClickListeners = (controller) => {
const postImageControllerSetupFunction = (controller) => {
const scaleToImg2ImgImage = (e) => {
- const picked = controller.selectController.getCurrentOption();
+ const picked = controller.optionPickingControler.getCurrentOption();
if (picked !== _IMAGE) return;
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files;
const img = new Image();
@@ -361,7 +444,7 @@ document.addEventListener("DOMContentLoaded", () => {
AspectRatioController.observeStartup(
"__img2imgAspectRatioController",
"img2img",
- [_OFF, _IMAGE, _LOCK],
+ [_OFF, _LOCK, _IMAGE],
postImageControllerSetupFunction
);
});
diff --git a/style.css b/style.css
index 1dab878..88c5a86 100644
--- a/style.css
+++ b/style.css
@@ -26,6 +26,7 @@
margin-bottom: 10px;
padding-left: 2px;
text-align: center;
+ min-width: 2.5em;
}
.arh-btn-row button {