Redesign client settings
ClientSettings replaces ConfigEditor: a section list on the left (General, UI Style, Animations) and the chosen section's settings on the right, each with a Reset for that section. UI Style shows four theme presets, the theme colors as a two-column grid, then the radii and font. New pieces: SectionNav, ThemePresetCard, ColorGrid and Theme.PRESETS. Theme keeps its config like AnimationConfig does, Divider can be vertical, and PropertyList's section titles are public. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
package org.saturnclient.ui.screens;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.saturnclient.common.ref.asset.IdentifierRef;
|
||||
import org.saturnclient.config.AnimationConfig;
|
||||
import org.saturnclient.config.Config;
|
||||
import org.saturnclient.config.Theme;
|
||||
import org.saturnclient.config.property.ColorProperty;
|
||||
import org.saturnclient.config.property.NamespaceProperty;
|
||||
import org.saturnclient.config.property.Property;
|
||||
import org.saturnclient.ui.PanelScreen;
|
||||
import org.saturnclient.ui.components.ColorGrid;
|
||||
import org.saturnclient.ui.components.PropertyList;
|
||||
import org.saturnclient.ui.components.SectionNav;
|
||||
import org.saturnclient.ui.components.Sidebar;
|
||||
import org.saturnclient.ui.components.ThemePresetCard;
|
||||
import org.saturnclient.ui.elements.ActionButton;
|
||||
import org.saturnclient.ui.elements.Divider;
|
||||
import org.saturnclient.ui.elements.Label;
|
||||
import org.saturnclient.ui.elements.Scroll;
|
||||
import org.saturnclient.ui.resources.Textures;
|
||||
|
||||
/**
|
||||
* The client's own settings, split into sections picked from a list on the left.
|
||||
*/
|
||||
public class ClientSettings extends PanelScreen {
|
||||
private enum Section {
|
||||
GENERAL("General", "Title screen, emotes and cosmetics", Textures.ICON_SLIDERS),
|
||||
UI_STYLE("UI Style", "Colors, corners and font for every Saturn screen", Textures.ICON_PALETTE),
|
||||
ANIMATIONS("Animations", "How long menu animations take, and their easing", Textures.ICON_ANIMATIONS);
|
||||
|
||||
final String title;
|
||||
final String description;
|
||||
final IdentifierRef icon;
|
||||
|
||||
Section(String title, String description, IdentifierRef icon) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NAV_WIDTH = 170;
|
||||
private static final int NAV_GAP = 16;
|
||||
private static final int LIST_Y = 58;
|
||||
private static final int SECTION_GAP = 22;
|
||||
private static final int PRESET_GAP = 10;
|
||||
private static final int SCROLLBAR_SPACE = 14;
|
||||
|
||||
private Section section = Section.GENERAL;
|
||||
|
||||
public ClientSettings() {
|
||||
super("Settings", Sidebar.SETTINGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void panel() {
|
||||
List<SectionNav.Item> items = Stream.of(Section.values())
|
||||
.map(s -> new SectionNav.Item(s.icon, s.title))
|
||||
.toList();
|
||||
|
||||
draw(new SectionNav("SATURN CLIENT", items, section.ordinal(), NAV_WIDTH, i -> {
|
||||
section = Section.values()[i];
|
||||
init();
|
||||
}).position(contentX, contentY + 4));
|
||||
|
||||
int dividerX = contentX + NAV_WIDTH + NAV_GAP;
|
||||
draw(new Divider(1).dimensions(1, panelHeight).position(dividerX, panelY));
|
||||
|
||||
int x = dividerX + 1 + NAV_GAP + 4;
|
||||
int width = contentX + contentWidth - x;
|
||||
|
||||
// Header
|
||||
draw(new Label(() -> section.title, 1.15f, () -> Theme.FONT.value, () -> Theme.FOREGROUND.value)
|
||||
.position(x, contentY + 2));
|
||||
draw(new Label(() -> section.description, 0.66f, Theme::getBodyFont, Theme::getMutedFg)
|
||||
.position(x, contentY + 28));
|
||||
|
||||
ActionButton reset = new ActionButton(Textures.ICON_RESET, "Reset", true, this::reset);
|
||||
draw(reset.position(x + width - reset.width, contentY + 4));
|
||||
|
||||
// The section's settings
|
||||
Scroll scroll = new Scroll(0).noBackground();
|
||||
|
||||
switch (section) {
|
||||
case GENERAL -> PropertyList.draw(scroll, getGeneralProperties(), Set.of(), width, 0);
|
||||
case UI_STYLE -> drawUiStyle(scroll, width);
|
||||
case ANIMATIONS -> PropertyList.draw(scroll, AnimationConfig.config.getProperties(), Set.of(), width, 0);
|
||||
}
|
||||
|
||||
draw(scroll.dimensions(width + SCROLLBAR_SPACE, contentHeight - LIST_Y).position(x, contentY + LIST_Y));
|
||||
}
|
||||
|
||||
private void drawUiStyle(Scroll scroll, int width) {
|
||||
Map<String, Property> properties = Theme.config.getProperties();
|
||||
|
||||
int y = PropertyList.drawSection(scroll, "Presets", 0) + 10;
|
||||
int cardWidth = (width - PRESET_GAP * (Theme.PRESETS.size() - 1)) / Theme.PRESETS.size();
|
||||
|
||||
for (int i = 0; i < Theme.PRESETS.size(); i++) {
|
||||
// Rebuild so the color inputs show the preset's colors
|
||||
scroll.draw(new ThemePresetCard(Theme.PRESETS.get(i), cardWidth, this::init)
|
||||
.position(i * (cardWidth + PRESET_GAP), y));
|
||||
}
|
||||
|
||||
y += ThemePresetCard.HEIGHT + SECTION_GAP;
|
||||
y = PropertyList.drawSection(scroll, "Colors", y) + 10;
|
||||
y = ColorGrid.draw(scroll, properties, width, y) + SECTION_GAP;
|
||||
|
||||
y = PropertyList.drawSection(scroll, "Shape & type", y) + 4;
|
||||
PropertyList.draw(scroll, properties, getNames(properties, p -> p instanceof ColorProperty), width, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* The top-level settings. The namespaces have sections of their own.
|
||||
*/
|
||||
private static Map<String, Property> getGeneralProperties() {
|
||||
return Config.config.getProperties().entrySet().stream()
|
||||
.filter(e -> !(e.getValue() instanceof NamespaceProperty))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a,
|
||||
LinkedHashMap::new));
|
||||
}
|
||||
|
||||
private static Set<String> getNames(Map<String, Property> properties, Predicate<Property> filter) {
|
||||
return properties.entrySet().stream()
|
||||
.filter(e -> filter.test(e.getValue()))
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the current section's settings back to their defaults.
|
||||
*/
|
||||
private void reset() {
|
||||
Map<String, Property> properties = switch (section) {
|
||||
case GENERAL -> getGeneralProperties();
|
||||
case UI_STYLE -> Theme.config.getProperties();
|
||||
case ANIMATIONS -> AnimationConfig.config.getProperties();
|
||||
};
|
||||
|
||||
properties.values().forEach(Property::reset);
|
||||
init();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user