aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAUTOMATIC1111 <16777216c@gmail.com>2023-02-19 10:55:39 +0300
committerGitHub <noreply@github.com>2023-02-19 10:55:39 +0300
commitfd4ac5187a1ae42be3f131770ea21e2158f75dcd (patch)
treea88d9720514409a59e3f51a28189a38279161dba
parentb20f28eea9a2f71bb001064f51f1982382bdf568 (diff)
Revert "Aspect ratio sliders"
-rw-r--r--javascript/ComponentControllers.js259
-rw-r--r--javascript/aspectRatioSliders.js181
-rw-r--r--modules/shared.py21
-rw-r--r--modules/ui.py12
-rw-r--r--style.css46
5 files changed, 2 insertions, 517 deletions
diff --git a/javascript/ComponentControllers.js b/javascript/ComponentControllers.js
deleted file mode 100644
index 2888679b..00000000
--- a/javascript/ComponentControllers.js
+++ /dev/null
@@ -1,259 +0,0 @@
-/* This is a basic library that allows controlling elements that take some form of user input.
-
-This was previously written in typescript, where all controllers implemented an interface. Not
-all methods were needed in all the controllers, but it was done to keep a common interface, so
-your main app can serve as a controller of controllers.
-
-These controllers were built to work on the shapes of html elements that gradio components use.
-
-There may be some notes in it that only applied to my use case, but I left them to help others
-along.
-
-You will need the parent element for these to work.
-The parent element can be defined as the element (div) that gets the element id when assigning
-an element id to a gradio component.
-
-Example:
- gr.TextBox(value="...", elem_id="THISID")
-
-Basic usage, grab an element that is the parent container for the component.
-
-Send it in to the class, like a function, don't forget the "new" keyword so it calls the constructor
-and sends back a new object.
-
-Example:
-
-let txt2imgPrompt = new TextComponentController(gradioApp().querySelector("#txt2img_prompt"))
-
-Then use the getVal() method to get the value, or use the setVal(myValue) method to set the value.
-
-Input types that are groups, like Checkbox groups (not individual checkboxes), take in an array of values.
-
-Checkbox group has to reset all values to False (unchecked), then set the values in your array to true (checked).
-If you don't hold a reference to the values (the labels in string format), you can acquire them using the getVal() method.
-*/
-class DropdownComponentController {
- constructor(element) {
- this.element = element;
- this.childSelector = this.element.querySelector('select');
- this.children = new Map();
- Array.from(this.childSelector.querySelectorAll('option')).forEach(opt => this.children.set(opt.value, opt));
- }
- getVal() {
- return this.childSelector.value;
- }
- updateVal(optionElement) {
- optionElement.selected = true;
- }
- setVal(name) {
- this.updateVal(this.children.get(name));
- this.eventHandler();
- }
- eventHandler() {
- this.childSelector.dispatchEvent(new Event("change"));
- }
-}
-class CheckboxComponentController {
- constructor(element) {
- this.element = element;
- this.child = this.element.querySelector('input');
- }
- getVal() {
- return this.child.checked;
- }
- updateVal(checked) {
- this.child.checked = checked;
- }
- setVal(checked) {
- this.updateVal(checked);
- this.eventHandler();
- }
- eventHandler() {
- this.child.dispatchEvent(new Event("change"));
- }
-}
-class CheckboxGroupComponentController {
- constructor(element) {
- this.element = element;
- //this.checkBoxes = new Object;
- this.children = new Map();
- Array.from(this.element.querySelectorAll('input')).forEach(input => this.children.set(input.nextElementSibling.innerText, input));
- /* element id gets use fieldset, grab all inputs (the bool val) get the userfriendly label, use as key, put bool value in mapping */
- //Array.from(this.component.querySelectorAll("input")).forEach( _input => this.checkBoxes[_input.nextElementSibling.innerText] = _input)
- /*Checkboxgroup structure
- <fieldset>
- <div> css makes translucent
- <span>
- serves as label for component
- </span>
- <div data-testid='checkbox-group'> container for checkboxes
- <label>
- <input type=checkbox>
- <span>checkbox words</span>
- </label>
- ...
- </div>
- </fieldset>
- */
- }
- updateVal(label) {
- /*********
- calls updates using a throttle or else the backend does not get updated properly
- * ********/
- setTimeout(() => this.conditionalToggle(true, this.children.get(label)), 2);
- }
- setVal(labels) {
- /* Handles reset and updates all in array to true */
- this.reupdateVals();
- labels.forEach(l => this.updateVal(l));
- }
- getVal() {
- //return the list of values that are true
- return [...this.children].filter(([k, v]) => v.checked).map(arr => arr[0]);
- }
- reupdateVals() {
- /**************
- * for reupdating all vals, first set to false
- **************/
- this.children.forEach(inputChild => this.conditionalToggle(false, inputChild));
- }
- conditionalToggle(desiredVal, inputChild) {
- //This method behaves like 'set this value to this'
- //Using element.checked = true/false, does not register the change, even if you called change afterwards,
- // it only sets what it looks like in our case, because there is no form submit, a person then has to click on it twice.
- //Options are to use .click() or dispatch an event
- if (desiredVal != inputChild.checked) {
- inputChild.dispatchEvent(new Event("change")); //using change event instead of click, in case browser ad-blockers blocks the click method
- }
- }
- eventHandler(checkbox) {
- checkbox.dispatchEvent(new Event("change"));
- }
-}
-class RadioComponentController {
- constructor(element) {
- this.element = element;
- this.children = new Map();
- Array.from(this.element.querySelectorAll("input")).forEach(input => this.children.set(input.value, input));
- }
- getVal() {
- //radio groups have a single element that's checked is true
- // as array arr k,v pair element.checked ) -> array of len(1) with [k,v] so either [0] [1].value
- return [...this.children].filter(([l, e]) => e.checked)[0][0];
- //return Array.from(this.children).filter( ([label, input]) => input.checked)[0][1].value
- }
- updateVal(child) {
- this.eventHandler(child);
- }
- setVal(name) {
- //radio will trigger all false except the one that get the event change
- //to keep the api similar, other methods are still called
- this.updateVal(this.children.get(name));
- }
- eventHandler(child) {
- child.dispatchEvent(new Event("change"));
- }
-}
-class NumberComponentController {
- constructor(element) {
- this.element = element;
- this.childNumField = element.querySelector('input[type=number]');
- }
- getVal() {
- return this.childNumField.value;
- }
- updateVal(text) {
- this.childNumField.value = text;
- }
- eventHandler() {
- this.element.dispatchEvent(new Event("input"));
- }
- setVal(text) {
- this.updateVal(text);
- this.eventHandler();
- }
-}
-class SliderComponentController {
- constructor(element) {
- this.element = element;
- this.childNumField = this.element.querySelector('input[type=number]');
- this.childRangeField = this.element.querySelector('input[type=range]');
- }
- getVal() {
- return this.childNumField.value;
- }
- updateVal(text) {
- //both are not needed, either works, both are left in so one is a fallback in case of gradio changes
- this.childNumField.value = text;
- this.childRangeField.value = text;
- }
- eventHandler() {
- this.element.dispatchEvent(new Event("input"));
- this.childNumField.dispatchEvent(new Event("input"));
- this.childRangeField.dispatchEvent(new Event("input"));
- }
- setVal(text) {
- this.updateVal(text);
- this.eventHandler();
- }
-}
-class TextComponentController {
- constructor(element) {
- this.element = element;
- this.child = element.querySelector('textarea');
- }
- getVal() {
- return this.child.value;
- }
- eventHandler() {
- this.element.dispatchEvent(new Event("input"));
- this.child.dispatchEvent(new Event("change"));
- //Workaround to solve no target with v(o) on eventhandler, define my own target
- let ne = new Event("input");
- Object.defineProperty(ne, "target", { value: this.child });
- this.child.dispatchEvent(ne);
- }
- updateVal(text) {
- this.child.value = text;
- }
- appendValue(text) {
- //might add delimiter option
- this.child.value += ` ${text}`;
- }
- setVal(text, append = false) {
- if (append) {
- this.appendValue(text);
- }
- else {
- this.updateVal(text);
- }
- this.eventHandler();
- }
-}
-class JsonComponentController extends TextComponentController {
- constructor(element) {
- super(element);
- }
- getVal() {
- return JSON.parse(this.child.value);
- }
-}
-class ColorComponentController {
- constructor(element) {
- this.element = element;
- this.child = this.element.querySelector('input[type=color]');
- }
- updateVal(text) {
- this.child.value = text;
- }
- getVal() {
- return this.child.value;
- }
- setVal(text) {
- this.updateVal(text);
- this.eventHandler();
- }
- eventHandler() {
- this.child.dispatchEvent(new Event("input"));
- }
-}
diff --git a/javascript/aspectRatioSliders.js b/javascript/aspectRatioSliders.js
deleted file mode 100644
index 3def5158..00000000
--- a/javascript/aspectRatioSliders.js
+++ /dev/null
@@ -1,181 +0,0 @@
-class AspectRatioSliderController {
- constructor(widthSlider, heightSlider, ratioSource, roundingSource, roundingMethod) {
- //References
- this.widthSlider = new SliderComponentController(widthSlider);
- this.heightSlider = new SliderComponentController(heightSlider);
- this.ratioSource = new DropdownComponentController(ratioSource);
- this.roundingSource = new CheckboxComponentController(roundingSource);
- this.roundingMethod = new RadioComponentController(roundingMethod);
- this.roundingIndicatorBadge = document.createElement("div");
- // Badge implementation
- this.roundingIndicatorBadge.innerText = "📐";
- this.roundingIndicatorBadge.classList.add("rounding-badge");
- this.ratioSource.element.appendChild(this.roundingIndicatorBadge);
- // Check initial value of ratioSource to set badge visbility
- let initialRatio = this.ratioSource.getVal();
- if (!initialRatio.includes(":")) {
- this.roundingIndicatorBadge.style.display = "none";
- }
- //Adjust badge icon if rounding is on
- if (this.roundingSource.getVal()) {
- //this.roundingIndicatorBadge.classList.add("active");
- this.roundingIndicatorBadge.innerText = "📏";
- }
- //Make badge clickable to toggle setting
- this.roundingIndicatorBadge.addEventListener("click", () => {
- this.roundingSource.setVal(!this.roundingSource.getVal());
- });
- //Make rounding setting toggle badge text and style if setting changes
- this.roundingSource.child.addEventListener("change", () => {
- if (this.roundingSource.getVal()) {
- //this.roundingIndicatorBadge.classList.add("active");
- this.roundingIndicatorBadge.innerText = "📏";
- }
- else {
- //this.roundingIndicatorBadge.classList.remove("active");
- this.roundingIndicatorBadge.innerText = "📐";
- }
- this.adjustStepSize();
- });
- //Other event listeners
- this.widthSlider.childRangeField.addEventListener("change", (e) => { e.preventDefault(); this.resize("width"); });
- this.widthSlider.childNumField.addEventListener("change", (e) => { e.preventDefault(); this.resize("width"); });
- this.heightSlider.childRangeField.addEventListener("change", (e) => { e.preventDefault(); this.resize("height"); });
- this.heightSlider.childNumField.addEventListener("change", (e) => { e.preventDefault(); this.resize("height"); });
- this.ratioSource.childSelector.addEventListener("change", (e) => {
- e.preventDefault();
- //Check and toggle display of badge conditionally on dropdown selection
- if (!this.ratioSource.getVal().includes(":")) {
- this.roundingIndicatorBadge.style.display = 'none';
- }
- else {
- this.roundingIndicatorBadge.style.display = 'block';
- }
- this.adjustStepSize();
- });
- }
- resize(dimension) {
- //For moving slider or number field
- let val = this.ratioSource.getVal();
- if (!val.includes(":")) {
- return;
- }
- let [width, height] = val.split(":").map(Number);
- let ratio = width / height;
- if (dimension == 'width') {
- let newHeight = parseInt(this.widthSlider.getVal()) / ratio;
- if (this.roundingSource.getVal()) {
- switch (this.roundingMethod.getVal()) {
- case 'Round':
- newHeight = Math.round(newHeight / 8) * 8;
- break;
- case 'Ceiling':
- newHeight = Math.ceil(newHeight / 8) * 8;
- break;
- case 'Floor':
- newHeight = Math.floor(newHeight / 8) * 8;
- break;
- }
- }
- this.heightSlider.setVal(newHeight.toString());
- }
- else if (dimension == "height") {
- let newWidth = parseInt(this.heightSlider.getVal()) * ratio;
- if (this.roundingSource.getVal()) {
- switch (this.roundingMethod.getVal()) {
- case 'Round':
- newWidth = Math.round(newWidth / 8) * 8;
- break;
- case 'Ceiling':
- newWidth = Math.ceil(newWidth / 8) * 8;
- break;
- case 'Floor':
- newWidth = Math.floor(newWidth / 8) * 8;
- break;
- }
- }
- this.widthSlider.setVal(newWidth.toString());
- }
- }
- adjustStepSize() {
- /* Sets scales/precision/rounding steps;*/
- let val = this.ratioSource.getVal();
- if (!val.includes(":")) {
- //If ratio unlocked
- this.widthSlider.childRangeField.step = "8";
- this.widthSlider.childRangeField.min = "64";
- this.widthSlider.childNumField.step = "8";
- this.widthSlider.childNumField.min = "64";
- this.heightSlider.childRangeField.step = "8";
- this.heightSlider.childRangeField.min = "64";
- this.heightSlider.childNumField.step = "8";
- this.heightSlider.childNumField.min = "64";
- return;
- }
- //Format string and calculate step sizes
- let [width, height] = val.split(":").map(Number);
- let decimalPlaces = (width.toString().split(".")[1] || []).length;
- //keep upto 6 decimal points of precision of ratio
- //euclidean gcd does not support floats, so we scale it up
- decimalPlaces = decimalPlaces > 6 ? 6 : decimalPlaces;
- let gcd = this.gcd(width * 10 ** decimalPlaces, height * 10 ** decimalPlaces) / 10 ** decimalPlaces;
- let stepSize = 8 * height / gcd;
- let stepSizeOther = 8 * width / gcd;
- if (this.roundingSource.getVal()) {
- //If rounding is on set/keep default stepsizes
- this.widthSlider.childRangeField.step = "8";
- this.widthSlider.childRangeField.min = "64";
- this.widthSlider.childNumField.step = "8";
- this.widthSlider.childNumField.min = "64";
- this.heightSlider.childRangeField.step = "8";
- this.heightSlider.childRangeField.min = "64";
- this.heightSlider.childNumField.step = "8";
- this.heightSlider.childNumField.min = "64";
- }
- else {
- //if rounding is off, set step sizes so they enforce snapping
- //min is changed, because it offsets snap positions
- this.widthSlider.childRangeField.step = stepSizeOther.toString();
- this.widthSlider.childRangeField.min = stepSizeOther.toString();
- this.widthSlider.childNumField.step = stepSizeOther.toString();
- this.widthSlider.childNumField.min = stepSizeOther.toString();
- this.heightSlider.childRangeField.step = stepSize.toString();
- this.heightSlider.childRangeField.min = stepSize.toString();
- this.heightSlider.childNumField.step = stepSize.toString();
- this.heightSlider.childNumField.min = stepSize.toString();
- }
- let currentWidth = parseInt(this.widthSlider.getVal());
- //Rounding treated kinda like pythons divmod
- let stepsTaken = Math.round(currentWidth / stepSizeOther);
- //this snaps it to closest rule matches (rules being html step points, and ratio)
- let newWidth = stepsTaken * stepSizeOther;
- this.widthSlider.setVal(newWidth.toString());
- this.heightSlider.setVal(Math.round(newWidth / (width / height)).toString());
- }
- gcd(a, b) {
- //euclidean gcd
- if (b === 0) {
- return a;
- }
- return this.gcd(b, a % b);
- }
- static observeStartup(widthSliderId, heightSliderId, ratioSourceId, roundingSourceId, roundingMethodId) {
- let observer = new MutationObserver(() => {
- let widthSlider = document.querySelector("gradio-app").shadowRoot.getElementById(widthSliderId);
- let heightSlider = document.querySelector("gradio-app").shadowRoot.getElementById(heightSliderId);
- let ratioSource = document.querySelector("gradio-app").shadowRoot.getElementById(ratioSourceId);
- let roundingSource = document.querySelector("gradio-app").shadowRoot.getElementById(roundingSourceId);
- let roundingMethod = document.querySelector("gradio-app").shadowRoot.getElementById(roundingMethodId);
- if (widthSlider && heightSlider && ratioSource && roundingSource && roundingMethod) {
- observer.disconnect();
- new AspectRatioSliderController(widthSlider, heightSlider, ratioSource, roundingSource, roundingMethod);
- }
- });
- observer.observe(gradioApp(), { childList: true, subtree: true });
- }
-}
-document.addEventListener("DOMContentLoaded", () => {
- //Register mutation observer for self start-up;
- AspectRatioSliderController.observeStartup("txt2img_width", "txt2img_height", "txt2img_ratio", "setting_aspect_ratios_rounding", "setting_aspect_ratios_rounding_method");
- AspectRatioSliderController.observeStartup("img2img_width", "img2img_height", "img2img_ratio", "setting_aspect_ratios_rounding", "setting_aspect_ratios_rounding_method");
-});
diff --git a/modules/shared.py b/modules/shared.py
index 2983ee44..e324a48a 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -139,24 +139,6 @@ ui_reorder_categories = [
"scripts",
]
-aspect_ratio_defaults = [
- "🔓",
- "1:1",
- "3:2",
- "4:3",
- "5:4",
- "16:9",
- "9:16",
- "1.85:1",
- "2.35:1",
- "2.39:1",
- "2.40:1",
- "21:9",
- "1.375:1",
- "1.66:1",
- "1.75:1"
-]
-
cmd_opts.disable_extension_access = (cmd_opts.share or cmd_opts.listen or cmd_opts.server_name) and not cmd_opts.enable_insecure_extension_access
devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_esrgan, devices.device_codeformer = \
@@ -477,9 +459,6 @@ options_templates.update(options_section(('ui', "User interface"), {
"keyedit_precision_extra": OptionInfo(0.05, "Ctrl+up/down precision when editing <extra networks:0.9>", gr.Slider, {"minimum": 0.01, "maximum": 0.2, "step": 0.001}),
"quicksettings": OptionInfo("sd_model_checkpoint", "Quicksettings list"),
"ui_reorder": OptionInfo(", ".join(ui_reorder_categories), "txt2img/img2img UI item order"),
- "aspect_ratios_rounding": OptionInfo(True, "Round aspect ratios for more flexibility?", gr.Checkbox),
- "aspect_ratios_rounding_method": OptionInfo("Ceiling", "Aspect ratios rounding method", gr.Radio,{"choices": ["Round", "Ceiling", "Floor"]}),
- "aspect_ratios": OptionInfo(", ".join(aspect_ratio_defaults), "txt2img/img2img aspect ratios"),
"ui_extra_networks_tab_reorder": OptionInfo("", "Extra networks tab order"),
"localization": OptionInfo("None", "Localization (requires restart)", gr.Dropdown, lambda: {"choices": ["None"] + list(localization.localizations.keys())}, refresh=lambda: localization.list_localizations(cmd_opts.localizations_dir)),
}))
diff --git a/modules/ui.py b/modules/ui.py
index 2fc1fee5..2fdbda42 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -424,10 +424,6 @@ def ordered_ui_categories():
yield category
-def aspect_ratio_list():
- return [ratio.strip() for ratio in shared.opts.aspect_ratios.split(",")]
-
-
def get_value_for_setting(key):
value = getattr(opts, key)
@@ -483,9 +479,7 @@ def create_ui():
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="txt2img_width")
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="txt2img_height")
- with gr.Column(elem_id="txt2img_size_toolbox", scale=0):
- aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="txt2img_ratio", show_label=False, label="Aspect Ratio")
- res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn")
+ res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="txt2img_res_switch_btn")
if opts.dimensions_and_batch_together:
with gr.Column(elem_id="txt2img_column_batch"):
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="txt2img_batch_count")
@@ -763,9 +757,7 @@ def create_ui():
width = gr.Slider(minimum=64, maximum=2048, step=8, label="Width", value=512, elem_id="img2img_width")
height = gr.Slider(minimum=64, maximum=2048, step=8, label="Height", value=512, elem_id="img2img_height")
- with gr.Column(elem_id="img2img_size_toolbox", scale=0):
- aspect_ratio_dropdown = gr.Dropdown(value="🔓", choices=aspect_ratio_list(), interactive=True, type="value", elem_id="img2img_ratio", show_label=False, label="Aspect Ratio")
- res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
+ res_switch_btn = ToolButton(value=switch_values_symbol, elem_id="img2img_res_switch_btn")
if opts.dimensions_and_batch_together:
with gr.Column(elem_id="img2img_column_batch"):
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id="img2img_batch_count")
diff --git a/style.css b/style.css
index 55baefb7..05572f66 100644
--- a/style.css
+++ b/style.css
@@ -747,52 +747,6 @@ footer {
margin-left: 0em;
}
-#txt2img_size_toolbox, #img2img_size_toolbox{
- min-width: unset !important;
- gap: 0;
-}
-
-#txt2img_ratio, #img2img_ratio {
- padding: 0px;
- min-width: unset;
- max-width: fit-content;
-}
-#txt2img_ratio select, #img2img_ratio select{
- -o-appearance: none;
- -ms-appearance: none;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- background-image: unset;
- padding-right: unset;
- min-width: 40px;
- max-width: 40px;
- min-height: 40px;
- max-height: 40px;
- line-height: 40px;
- padding: 0;
- text-align: center;
-}
-.rounding-badge {
- display: inline-block;
- border-radius: 0px;
- /*background-color: #ccc;*/
- cursor: pointer;
- position: absolute;
- top: -10px;
- right: -10px;
- width: 20px;
- height: 20px;
- padding: 1px;
- line-height: 16px;
- font-size: 14px;
-}
-
-.rounding-badge.active {
- background-color: #007bff;
- border-radius: 50%;
-}
-
.inactive{
opacity: 0.5;
}