Added Quests and Real Settings (yay)

This commit is contained in:
2026-07-11 10:46:47 +02:00
parent d3fc829dee
commit 652fe728e1
7 changed files with 392 additions and 77 deletions
@@ -18,6 +18,9 @@ public class Config {
public int fpsY = 1; public int fpsY = 1;
public String lastModule = "FPS"; public String lastModule = "FPS";
public int keyX = 1;
public int keyY = 1;
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Path PATH = FabricLoader.getInstance() private static final Path PATH = FabricLoader.getInstance()
.getConfigDir() .getConfigDir()
@@ -0,0 +1,130 @@
package de.fullrisk.citrusDev.UI;
import io.wispforest.owo.ui.component.LabelComponent;
import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers;
import io.wispforest.owo.ui.core.*;
import io.wispforest.owo.ui.hud.Hud;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import de.fullrisk.citrusDev.Config;
public class Module_KeyStrokes {
private static FlowLayout keyContainer;
private static FlowLayout topRow;
private static FlowLayout bottomRow;
private static FlowLayout wBox, aBox, sBox, dBox;
private static LabelComponent wLabel, aLabel, sLabel, dLabel;
static boolean toggle = true;
private static boolean shown = false;
public static boolean isEnabled() {
return toggle;
}
public static void setEnabled(boolean value) {
toggle = value;
}
private static final Config CONFIG = Config.get();
private static final Surface GLASS_PANEL = Surface.blur(5f, 15f)
.and(Surface.flat(0x40FFFFFF));
private static final int KEY_SIZE = 16;
private static final int PRESSED_COLOR = 0xFF64de4b;
private static final int IDLE_COLOR = 0x40FFFFFF;
public static void setPosition(int x, int y) {
if (keyContainer != null) {
keyContainer.positioning(Positioning.relative(x, y));
}
CONFIG.keyX = x;
CONFIG.keyY = y;
CONFIG.save();
}
public static void register() {
Hud.add(Identifier.fromNamespaceAndPath("citrus-dev", "keystrokes_display"), () -> {
if (keyContainer == null) {
wLabel = UIComponents.label(Component.literal("W"));
aLabel = UIComponents.label(Component.literal("A"));
sLabel = UIComponents.label(Component.literal("S"));
dLabel = UIComponents.label(Component.literal("D"));
wBox = makeKeyBox(wLabel);
aBox = makeKeyBox(aLabel);
sBox = makeKeyBox(sLabel);
dBox = makeKeyBox(dLabel);
topRow = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
topRow.gap(2);
topRow.horizontalAlignment(HorizontalAlignment.CENTER);
topRow.child(UIContainers.horizontalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE))); // spacer
topRow.child(wBox);
topRow.child(UIContainers.horizontalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE))); // spacer
bottomRow = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
bottomRow.gap(2);
bottomRow.horizontalAlignment(HorizontalAlignment.CENTER);
bottomRow.child(aBox);
bottomRow.child(sBox);
bottomRow.child(dBox);
keyContainer = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
keyContainer.gap(2);
keyContainer.verticalAlignment(VerticalAlignment.CENTER);
keyContainer.horizontalAlignment(HorizontalAlignment.CENTER);
keyContainer.padding(Insets.of(0));
keyContainer.positioning(Positioning.relative(CONFIG.keyX, CONFIG.keyY));
}
return keyContainer;
});
}
private static FlowLayout makeKeyBox(LabelComponent label) {
FlowLayout box = UIContainers.verticalFlow(Sizing.fixed(KEY_SIZE), Sizing.fixed(KEY_SIZE));
box.horizontalAlignment(HorizontalAlignment.CENTER);
box.verticalAlignment(VerticalAlignment.CENTER);
box.surface(Surface.flat(IDLE_COLOR));
box.child(label);
return box;
}
public static void tick() {
if (keyContainer == null) return;
if (toggle && !shown) {
keyContainer.clearChildren(); // <-- safety net against duplicate adds
keyContainer.surface(GLASS_PANEL);
keyContainer.padding(Insets.of(Config.get().fpsP));
keyContainer.child(topRow);
keyContainer.child(bottomRow);
shown = true;
} else if (!toggle && shown) {
keyContainer.clearChildren();
keyContainer.surface(Surface.flat(0));
keyContainer.padding(Insets.of(0));
shown = false;
}
if (!toggle) return;
Minecraft client = Minecraft.getInstance();
KeyMapping up = client.options.keyUp;
KeyMapping left = client.options.keyLeft;
KeyMapping down = client.options.keyDown;
KeyMapping right = client.options.keyRight;
wBox.surface(Surface.flat(up.isDown() ? PRESSED_COLOR : IDLE_COLOR));
aBox.surface(Surface.flat(left.isDown() ? PRESSED_COLOR : IDLE_COLOR));
sBox.surface(Surface.flat(down.isDown() ? PRESSED_COLOR : IDLE_COLOR));
dBox.surface(Surface.flat(right.isDown() ? PRESSED_COLOR : IDLE_COLOR));
}
}
@@ -56,6 +56,7 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
private FlowLayout content; private FlowLayout content;
private final String initialModule; private final String initialModule;
public MyScreen() { public MyScreen() {
this(null); this(null);
} }
@@ -130,8 +131,8 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
rootComponent.child(panel); rootComponent.child(panel);
if ("FPS".equals(initialModule)) { if (initialModule != null) {
openModuleSettings("FPS", fpsModuleSettings()); openModuleByKey(initialModule);
} else { } else {
buildGeneralPanel(content); buildGeneralPanel(content);
} }
@@ -249,72 +250,51 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
} }
private void buildGeneralPanel(FlowLayout content) { private void buildGeneralPanel(FlowLayout content) {
FlowLayout iconButton = UIContainers.horizontalFlow(Sizing.content(), Sizing.content()); FlowLayout fpsRow = ModuleRow.build(
iconButton.gap(8); GLASS_PANEL, DISABLED, FLAT,
iconButton.verticalAlignment(VerticalAlignment.TOP);
iconButton.horizontalAlignment(HorizontalAlignment.CENTER);
iconButton.padding(Insets.of(6));
iconButton.horizontalSizing(Sizing.fixed(0));
iconButton.verticalSizing(Sizing.fixed(0));
iconButton.surface(toggle ? GLASS_PANEL : DISABLED);
iconButton.child(UIComponents.texture(
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/block_culling_file.png"), Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/block_culling_file.png"),
0, 0, 18, 12, 18, 12 18, 12,
)).horizontalAlignment(HorizontalAlignment.LEFT) MC_FIVE,
.verticalAlignment(VerticalAlignment.CENTER); "FPS",
"Displays your FPS",
FlowLayout textStack = UIContainers.verticalFlow(Sizing.content(), Sizing.content()); new ModuleRow.ToggleState() {
textStack.gap(2); public boolean get() { return toggle; }
textStack.horizontalAlignment(HorizontalAlignment.LEFT); public void set(boolean value) { toggle = value; }
textStack.verticalAlignment(VerticalAlignment.CENTER); },
var fpsLabel = UIComponents.label(
Component.literal("FPS")
.withStyle(style -> style.withFont(new FontDescription.Resource(MC_FIVE)))
).color(Color.ofRgb(toggle ? 0xffffff : 0x797b86));
textStack.child(fpsLabel);
textStack.child(UIComponents.label(
Component.literal("Displays your FPS"))
.color(Color.ofRgb(0xa3a3ac))
.maxWidth(130)
);
iconButton.child(textStack);
iconButton.child(UIComponents.spacer());
FlowLayout settingsButton = SettingsControls.makeSmallButton(
FLAT,
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/settings.png"), Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/settings.png"),
() -> { () -> {
Config.get().lastModule = "FPS"; Config.get().lastModule = "FPS";
Config.get().save(); Config.get().save();
openModuleSettings("FPS", fpsModuleSettings()); openModuleSettings("FPS", fpsModuleSettings());
} },
"Module Enabled", "FPS counter is now active",
"Module Disabled", "FPS counter is now inactive"
); );
iconButton.child(settingsButton);
iconButton.mouseEnter().subscribe(() -> iconButton.surface(toggle ? GLASS_PANEL : DISABLED)); FlowLayout keyStrokesRow = ModuleRow.build(
iconButton.mouseLeave().subscribe(() -> iconButton.surface(toggle ? GLASS_PANEL : DISABLED)); GLASS_PANEL, DISABLED, FLAT,
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/block_culling_file.png"),
iconButton.mouseDown().subscribe((click, doubled) -> { 18, 12,
toggle = !toggle; MC_FIVE,
fpsLabel.color(Color.ofRgb(toggle ? 0xffffff : 0x797b86)); "Keystrokes",
iconButton.surface(toggle ? GLASS_PANEL : DISABLED); "Current Key Presses",
CitrusToast.show("Module Enabled", "FPS counter is now active"); new ModuleRow.ToggleState() {
public boolean get() { return Module_KeyStrokes.isEnabled(); }
Minecraft.getInstance().getSoundManager().play( public void set(boolean value) { Module_KeyStrokes.setEnabled(value); }
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2) },
Identifier.fromNamespaceAndPath("citrus-dev", "textures/icons/settings.png"),
() -> {
Config.get().lastModule = "Key";
Config.get().save();
openModuleSettings("Key", keyStrokesSettings());
},
"Module Enabled", "Keystrokes is now active",
"Module Disabled", "KeyStrokes is now inactive"
); );
return true; content.child(keyStrokesRow);
}); content.child(fpsRow);
iconButton.horizontalSizing().animate(150, Easing.CUBIC, Sizing.fixed(200)).forwards();
iconButton.verticalSizing().animate(150, Easing.CUBIC, Sizing.fixed(35)).forwards();
content.child(iconButton);
} }
@@ -366,6 +346,14 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
content.child(scrollArea); content.child(scrollArea);
} }
private void openModuleByKey(String key) {
switch (key) {
case "FPS" -> openModuleSettings("FPS", fpsModuleSettings());
case "Key" -> openModuleSettings("Keystrokes", keyStrokesSettings());
default -> buildGeneralPanel(content);
}
}
private FlowLayout makeSettingRow(SettingRow setting) { private FlowLayout makeSettingRow(SettingRow setting) {
FlowLayout row = UIContainers.horizontalFlow(Sizing.fixed(CONTENT_WIDTH - 8), Sizing.fixed(16)); FlowLayout row = UIContainers.horizontalFlow(Sizing.fixed(CONTENT_WIDTH - 8), Sizing.fixed(16));
row.verticalAlignment(VerticalAlignment.CENTER); row.verticalAlignment(VerticalAlignment.CENTER);
@@ -398,12 +386,48 @@ public class MyScreen extends BaseOwoScreen<FlowLayout> {
value -> Module_FPS.fpsContainer.gap((int) value) value -> Module_FPS.fpsContainer.gap((int) value)
); );
int currentIndex = positionIndex(Config.get().fpsX, Config.get().fpsY);
return List.of( return List.of(
new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates)), new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates, currentIndex)),
new SettingRow("Size", sizeSlider) new SettingRow("Size", sizeSlider)
); );
} }
private List<SettingRow> keyStrokesSettings() {
List<SettingsControls.ButtonState> positionStates = List.of(
new SettingsControls.ButtonState("L-TOP", () -> Module_KeyStrokes.setPosition(1, 1)),
new SettingsControls.ButtonState("R-TOP", () -> Module_KeyStrokes.setPosition(99, 1)),
new SettingsControls.ButtonState("R-BOTTOM", () -> Module_KeyStrokes.setPosition(99, 99)),
new SettingsControls.ButtonState("L-BOTTOM", () -> Module_KeyStrokes.setPosition(1, 99))
);
FlowLayout sizeSlider = SettingsControls.makeSlider(
FLAT,
80,
0.0, 20.0,
4.0,
value -> (int) value + "px",
value -> {} // fixed: was Module_FPS.fpsContainer.gap(...)
);
int currentIndex = positionIndex(Config.get().keyX, Config.get().keyY);
return List.of(
new SettingRow("Position", SettingsControls.makeCyclingButton(GLASS_PANEL, positionStates, currentIndex)),
new SettingRow("Size", sizeSlider)
);
}
private int positionIndex(int x, int y) {
boolean right = x > 50;
boolean bottom = y > 50;
if (!right && !bottom) return 0; // L-TOP
if (right && !bottom) return 1; // R-TOP
if (right && bottom) return 2; // R-BOTTOM
return 3; // L-BOTTOM
}
@Override @Override
public boolean isPauseScreen() { public boolean isPauseScreen() {
return false; return false;
@@ -1,5 +1,6 @@
package de.fullrisk.citrusDev.UI; package de.fullrisk.citrusDev.UI;
import io.wispforest.owo.ui.component.LabelComponent;
import io.wispforest.owo.ui.component.UIComponents; import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout; import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers; import io.wispforest.owo.ui.container.UIContainers;
@@ -7,12 +8,15 @@ import io.wispforest.owo.ui.core.*;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription; import net.minecraft.network.chat.FontDescription;
import de.fullrisk.citrusDev.client.PlaytimeTracker; import de.fullrisk.citrusDev.client.PlaytimeTracker;
import de.fullrisk.citrusDev.UIHelper.CitrusToast;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class QuestsPanel { public class QuestsPanel {
private static final int ACCENT = 0xbaff86; private static final int ACCENT = 0x64de4b;
private record QuestData(String title, String description, int requiredPlaytime) { private record QuestData(String title, String description, int requiredPlaytime) {
boolean isUnlocked() { boolean isUnlocked() {
@@ -20,7 +24,50 @@ public class QuestsPanel {
} }
} }
public static void build(FlowLayout content, int contentWidth, int contentHeight) { public static class Handle {
private final LabelComponent playtimeLabel;
private final LabelComponent percentLabel;
private final FlowLayout barFill;
private final int barWidth;
private final List<QuestData> quests;
private final Set<String> notifiedTitles = new HashSet<>();
private Handle(LabelComponent playtimeLabel, LabelComponent percentLabel, FlowLayout barFill, int barWidth, List<QuestData> quests) {
this.playtimeLabel = playtimeLabel;
this.percentLabel = percentLabel;
this.barFill = barFill;
this.barWidth = barWidth;
this.quests = quests;
// seed with whatever's already unlocked on open, so we don't spam
// toasts for quests the player unlocked before opening this screen
for (QuestData quest : quests) {
if (quest.isUnlocked()) {
notifiedTitles.add(quest.title());
}
}
}
public void refresh() {
int playtime = PlaytimeTracker.getCurrentPlaytimeSeconds();
int maxPlaytime = 360;
int progress = Math.min(playtime * 100 / maxPlaytime, 100);
playtimeLabel.text(Component.literal(formatPlaytime(playtime)));
percentLabel.text(Component.literal(progress + "%"));
int fillWidth = Math.max(barWidth * progress / 100, progress > 0 ? 2 : 0);
barFill.horizontalSizing(Sizing.fixed(fillWidth));
for (QuestData quest : quests) {
if (quest.isUnlocked() && notifiedTitles.add(quest.title())) {
CitrusToast.show("Quest Unlocked", quest.title());
}
}
}
}
public static Handle build(FlowLayout content, int contentWidth, int contentHeight) {
List<QuestData> quests = quests(); List<QuestData> quests = quests();
int playtime = PlaytimeTracker.getCurrentPlaytimeSeconds(); int playtime = PlaytimeTracker.getCurrentPlaytimeSeconds();
int maxPlaytime = 360; int maxPlaytime = 360;
@@ -28,7 +75,6 @@ public class QuestsPanel {
int barWidth = contentWidth - 8; int barWidth = contentWidth - 8;
long unlockedCount = quests.stream().filter(QuestData::isUnlocked).count(); long unlockedCount = quests.stream().filter(QuestData::isUnlocked).count();
// --- status row: playtime + percentage ---
FlowLayout statusBar = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(20)); FlowLayout statusBar = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(20));
statusBar.gap(4); statusBar.gap(4);
statusBar.padding(Insets.of(4)); statusBar.padding(Insets.of(4));
@@ -36,15 +82,17 @@ public class QuestsPanel {
statusBar.horizontalAlignment(HorizontalAlignment.LEFT); statusBar.horizontalAlignment(HorizontalAlignment.LEFT);
statusBar.surface(MyScreen.GLASS_PANEL); statusBar.surface(MyScreen.GLASS_PANEL);
statusBar.child(UIComponents.label(Component.literal("Playtime: " + formatPlaytime(playtime))) LabelComponent playtimeLabel = UIComponents.label(Component.literal(formatPlaytime(playtime)));
.color(Color.ofRgb(0xFFFFFF))); playtimeLabel.color(Color.ofRgb(0xFFFFFF));
statusBar.child(playtimeLabel);
statusBar.child(UIComponents.spacer()); statusBar.child(UIComponents.spacer());
statusBar.child(UIComponents.label(Component.literal(progress + "%"))
.color(Color.ofRgb(ACCENT))); LabelComponent percentLabel = UIComponents.label(Component.literal(progress + "%"));
percentLabel.color(Color.ofRgb(ACCENT));
statusBar.child(percentLabel);
content.child(statusBar); content.child(statusBar);
// --- progress bar ---
FlowLayout barBg = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(6)); FlowLayout barBg = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.fixed(6));
barBg.surface(Surface.flat(0x30FFFFFF).and(Surface.outline(0x30FFFFFF))); barBg.surface(Surface.flat(0x30FFFFFF).and(Surface.outline(0x30FFFFFF)));
barBg.horizontalAlignment(HorizontalAlignment.LEFT); barBg.horizontalAlignment(HorizontalAlignment.LEFT);
@@ -58,7 +106,6 @@ public class QuestsPanel {
content.child(barBg); content.child(barBg);
// --- unlocked count summary ---
FlowLayout summaryRow = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.content()); FlowLayout summaryRow = UIContainers.horizontalFlow(Sizing.fixed(barWidth), Sizing.content());
summaryRow.padding(Insets.of(3, 0, 2, 2)); summaryRow.padding(Insets.of(3, 0, 2, 2));
@@ -69,7 +116,6 @@ public class QuestsPanel {
content.child(summaryRow); content.child(summaryRow);
// --- quest list (scrollable) ---
FlowLayout questList = UIContainers.verticalFlow(Sizing.fixed(barWidth), Sizing.content()); FlowLayout questList = UIContainers.verticalFlow(Sizing.fixed(barWidth), Sizing.content());
questList.gap(3); questList.gap(3);
questList.padding(Insets.of(2, 0, 2, 2)); questList.padding(Insets.of(2, 0, 2, 2));
@@ -78,7 +124,7 @@ public class QuestsPanel {
questList.child(buildQuestEntry(quest, contentWidth)); questList.child(buildQuestEntry(quest, contentWidth));
} }
int usedHeight = 20 + 6 + 18 + 6; // statusBar + barBg + summaryRow + gaps int usedHeight = 20 + 6 + 18 + 6;
int scrollHeight = contentHeight - usedHeight; int scrollHeight = contentHeight - usedHeight;
var scrollArea = UIContainers.verticalScroll( var scrollArea = UIContainers.verticalScroll(
@@ -87,6 +133,8 @@ public class QuestsPanel {
questList questList
); );
content.child(scrollArea); content.child(scrollArea);
return new Handle(playtimeLabel, percentLabel, barFill, barWidth, quests);
} }
private static String formatPlaytime(int seconds) { private static String formatPlaytime(int seconds) {
@@ -130,7 +178,7 @@ public class QuestsPanel {
: Surface.flat(0x40FFFFFF)); : Surface.flat(0x40FFFFFF));
iconBox.horizontalAlignment(HorizontalAlignment.CENTER); iconBox.horizontalAlignment(HorizontalAlignment.CENTER);
iconBox.verticalAlignment(VerticalAlignment.CENTER); iconBox.verticalAlignment(VerticalAlignment.CENTER);
iconBox.child(UIComponents.label(Component.literal(unlocked ? "" : "")) iconBox.child(UIComponents.label(Component.literal(""))
.color(Color.ofRgb(0x1c1c1c))); .color(Color.ofRgb(0x1c1c1c)));
row.child(iconBox); row.child(iconBox);
@@ -0,0 +1,102 @@
package de.fullrisk.citrusDev.UIHelper;
import io.wispforest.owo.ui.component.UIComponents;
import io.wispforest.owo.ui.container.FlowLayout;
import io.wispforest.owo.ui.container.UIContainers;
import io.wispforest.owo.ui.core.*;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
import net.minecraft.resources.Identifier;
import net.minecraft.sounds.SoundEvents;
public class ModuleRow {
/** Bridge to whatever boolean field actually holds the module's on/off state. */
public interface ToggleState {
boolean get();
void set(boolean value);
}
public static FlowLayout build(
Surface enabledSurface,
Surface disabledSurface,
Surface flatSurface,
Identifier icon,
int iconWidth,
int iconHeight,
Identifier titleFont,
String title,
String description,
ToggleState state,
Identifier settingsIcon,
Runnable onSettingsClick,
String enabledToastTitle,
String enabledToastMessage,
String disabledToastTitle,
String disabledToastMessage
) {
FlowLayout row = UIContainers.horizontalFlow(Sizing.content(), Sizing.content());
row.gap(8);
row.verticalAlignment(VerticalAlignment.TOP);
row.horizontalAlignment(HorizontalAlignment.CENTER);
row.padding(Insets.of(6));
row.horizontalSizing(Sizing.fixed(0));
row.verticalSizing(Sizing.fixed(0));
row.surface(state.get() ? enabledSurface : disabledSurface);
row.child(UIComponents.texture(icon, 0, 0, iconWidth, iconHeight, iconWidth, iconHeight))
.horizontalAlignment(HorizontalAlignment.LEFT)
.verticalAlignment(VerticalAlignment.CENTER);
FlowLayout textStack = UIContainers.verticalFlow(Sizing.content(), Sizing.content());
textStack.gap(2);
textStack.horizontalAlignment(HorizontalAlignment.LEFT);
textStack.verticalAlignment(VerticalAlignment.CENTER);
var titleLabel = UIComponents.label(
Component.literal(title)
.withStyle(style -> style.withFont(new FontDescription.Resource(titleFont)))
);
titleLabel.color(Color.ofRgb(state.get() ? 0xffffff : 0x797b86));
textStack.child(titleLabel);
textStack.child(UIComponents.label(Component.literal(description))
.color(Color.ofRgb(0xa3a3ac))
.maxWidth(130));
row.child(textStack);
row.child(UIComponents.spacer());
FlowLayout settingsButton = SettingsControls.makeSmallButton(flatSurface, settingsIcon, onSettingsClick);
row.child(settingsButton);
row.mouseEnter().subscribe(() -> row.surface(state.get() ? enabledSurface : disabledSurface));
row.mouseLeave().subscribe(() -> row.surface(state.get() ? enabledSurface : disabledSurface));
row.mouseDown().subscribe((click, doubled) -> {
boolean newState = !state.get();
state.set(newState);
titleLabel.color(Color.ofRgb(newState ? 0xffffff : 0x797b86));
row.surface(newState ? enabledSurface : disabledSurface);
if (newState) {
CitrusToast.show(enabledToastTitle, enabledToastMessage);
} else {
CitrusToast.show(disabledToastTitle, disabledToastMessage);
}
Minecraft.getInstance().getSoundManager().play(
SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK.value(), 2.0F, 2)
);
return true;
});
row.horizontalSizing().animate(150, Easing.CUBIC, Sizing.fixed(200)).forwards();
row.verticalSizing().animate(150, Easing.CUBIC, Sizing.fixed(35)).forwards();
return row;
}
}
@@ -73,15 +73,15 @@ public class SettingsControls {
return button; return button;
} }
public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states) { public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states, int initialIndex) {
int[] currentIndex = {0}; int[] currentIndex = { initialIndex };
FlowLayout button = UIContainers.verticalFlow(Sizing.fixed(50), Sizing.fixed(16)); FlowLayout button = UIContainers.verticalFlow(Sizing.fixed(50), Sizing.fixed(16));
button.verticalAlignment(VerticalAlignment.CENTER); button.verticalAlignment(VerticalAlignment.CENTER);
button.horizontalAlignment(HorizontalAlignment.CENTER); button.horizontalAlignment(HorizontalAlignment.CENTER);
button.surface(baseSurface); button.surface(baseSurface);
var label = UIComponents.label(Component.literal(states.get(0).label())) var label = UIComponents.label(Component.literal(states.get(initialIndex).label()))
.color(Color.ofRgb(0xFFFFFF)); .color(Color.ofRgb(0xFFFFFF));
button.child(label); button.child(label);
@@ -104,6 +104,11 @@ public class SettingsControls {
return button; return button;
} }
// keep the old call sites compiling; defaults to index 0
public static FlowLayout makeCyclingButton(Surface baseSurface, List<ButtonState> states) {
return makeCyclingButton(baseSurface, states, 0);
}
public static FlowLayout makeSlider(Surface baseSurface, int width, double min, double max, double initial, public static FlowLayout makeSlider(Surface baseSurface, int width, double min, double max, double initial,
DoubleFunction<String> labelFormatter, DoubleConsumer onChange) { DoubleFunction<String> labelFormatter, DoubleConsumer onChange) {
int labelWidth = 34; int labelWidth = 34;
@@ -3,6 +3,7 @@ package de.fullrisk.citrusDev.client;
import de.fullrisk.citrusDev.Config; import de.fullrisk.citrusDev.Config;
import de.fullrisk.citrusDev.UI.Module_FPS; import de.fullrisk.citrusDev.UI.Module_FPS;
import de.fullrisk.citrusDev.UI.Module_KeyStrokes;
import de.fullrisk.citrusDev.UI.MyScreen; import de.fullrisk.citrusDev.UI.MyScreen;
import de.fullrisk.citrusDev.UI.OverviewScreen; import de.fullrisk.citrusDev.UI.OverviewScreen;
import io.wispforest.owo.ui.hud.Hud; import io.wispforest.owo.ui.hud.Hud;
@@ -21,6 +22,7 @@ public class CitrusDevClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
Module_FPS.register(); Module_FPS.register();
Module_KeyStrokes.register();
KeyMapping.Category category = KeyMapping.Category.register( KeyMapping.Category category = KeyMapping.Category.register(
Identifier.fromNamespaceAndPath("citrus-dev", "general")); Identifier.fromNamespaceAndPath("citrus-dev", "general"));
@@ -41,7 +43,8 @@ public class CitrusDevClient implements ClientModInitializer {
PlaytimeTracker.tick(); PlaytimeTracker.tick();
} }
Module_FPS.tick(); // update every tick, unconditionally Module_FPS.tick();
Module_KeyStrokes.tick();
while (openScreenKey.consumeClick()) { while (openScreenKey.consumeClick()) {
client.setScreen(new MyScreen(null)); // always general tab client.setScreen(new MyScreen(null)); // always general tab
} }