Skip to content

Commit

Permalink
add categories to settings
Browse files Browse the repository at this point in the history
  • Loading branch information
AUTOMATIC1111 committed Nov 26, 2023
1 parent 500de91 commit f0f100e
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 28 deletions.
25 changes: 25 additions & 0 deletions javascript/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,28 @@ onUiLoaded(function() {

buttonShowAllPages.addEventListener("click", settingsShowAllTabs);
});


onOptionsChanged(function() {
if (gradioApp().querySelector('#settings .settings-category')) return;

var sectionMap = {};
gradioApp().querySelectorAll('#settings > div > button').forEach(function(x) {
sectionMap[x.textContent.trim()] = x;
});

opts._categories.forEach(function(x) {
var section = x[0];
var category = x[1];

var span = document.createElement('SPAN');
span.textContent = category;
span.className = 'settings-category';

var sectionElem = sectionMap[section];
if (!sectionElem) return;

sectionElem.parentElement.insertBefore(span, sectionElem);
});
});

75 changes: 68 additions & 7 deletions modules/options.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import sys
from dataclasses import dataclass

import gradio as gr

Expand All @@ -8,13 +9,14 @@


class OptionInfo:
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, section=None, refresh=None, comment_before='', comment_after='', infotext=None, restrict_api=False):
def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, section=None, refresh=None, comment_before='', comment_after='', infotext=None, restrict_api=False, category_id=None):
self.default = default
self.label = label
self.component = component
self.component_args = component_args
self.onchange = onchange
self.section = section
self.category_id = category_id
self.refresh = refresh
self.do_not_save = False

Expand Down Expand Up @@ -63,7 +65,11 @@ def __init__(self, text):

def options_section(section_identifier, options_dict):
for v in options_dict.values():
v.section = section_identifier
if len(section_identifier) == 2:
v.section = section_identifier
elif len(section_identifier) == 3:
v.section = section_identifier[0:2]
v.category_id = section_identifier[2]

return options_dict

Expand Down Expand Up @@ -206,6 +212,17 @@ def dumpjson(self):
d = {k: self.data.get(k, v.default) for k, v in self.data_labels.items()}
d["_comments_before"] = {k: v.comment_before for k, v in self.data_labels.items() if v.comment_before is not None}
d["_comments_after"] = {k: v.comment_after for k, v in self.data_labels.items() if v.comment_after is not None}

item_categories = {}
for item in self.data_labels.values():
category = categories.mapping.get(item.category_id)
category = "Uncategorized" if category is None else category.label
if category not in item_categories:
item_categories[category] = item.section[1]

# _categories is a list of pairs: [section, category]. Each section (a setting page) will get a special heading above it with the category as text.
d["_categories"] = [[v, k] for k, v in item_categories.items()] + [["Defaults", "Other"]]

return json.dumps(d)

def add_option(self, key, info):
Expand All @@ -214,15 +231,40 @@ def add_option(self, key, info):
self.data[key] = info.default

def reorder(self):
"""reorder settings so that all items related to section always go together"""
"""Reorder settings so that:
- all items related to section always go together
- all sections belonging to a category go together
- sections inside a category are ordered alphabetically
- categories are ordered by creation order
Category is a superset of sections: for category "postprocessing" there could be multiple sections: "face restoration", "upscaling".
This function also changes items' category_id so that all items belonging to a section have the same category_id.
"""

category_ids = {}
section_categories = {}

section_ids = {}
settings_items = self.data_labels.items()
for _, item in settings_items:
if item.section not in section_ids:
section_ids[item.section] = len(section_ids)
if item.section not in section_categories:
section_categories[item.section] = item.category_id

for _, item in settings_items:
item.category_id = section_categories.get(item.section)

for category_id in categories.mapping:
if category_id not in category_ids:
category_ids[category_id] = len(category_ids)

self.data_labels = dict(sorted(settings_items, key=lambda x: section_ids[x[1].section]))
def sort_key(x):
item: OptionInfo = x[1]
category_order = category_ids.get(item.category_id, len(category_ids))
section_order = item.section[1]

return category_order, section_order

self.data_labels = dict(sorted(settings_items, key=sort_key))

def cast_value(self, key, value):
"""casts an arbitrary to the same type as this setting's value with key
Expand All @@ -245,3 +287,22 @@ def cast_value(self, key, value):
value = expected_type(value)

return value


@dataclass
class OptionsCategory:
id: str
label: str

class OptionsCategories:
def __init__(self):
self.mapping = {}

def register_category(self, category_id, label):
if category_id in self.mapping:
return category_id

self.mapping[category_id] = OptionsCategory(category_id, label)


categories = OptionsCategories()
Loading

0 comments on commit f0f100e

Please sign in to comment.