From 87b851373071490bb371ba1160f85f0341579cb2 Mon Sep 17 00:00:00 2001 From: Linnea Gräf Date: Sun, 13 Oct 2024 19:53:10 +0200 Subject: Add YACL config menu --- src/compat/yacl/java/KeybindingBuilder.kt | 16 ++++ src/compat/yacl/java/KeybindingController.kt | 71 ++++++++++++++++ src/compat/yacl/java/YaclIntegration.kt | 119 +++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 src/compat/yacl/java/KeybindingBuilder.kt create mode 100644 src/compat/yacl/java/KeybindingController.kt create mode 100644 src/compat/yacl/java/YaclIntegration.kt (limited to 'src/compat/yacl/java') diff --git a/src/compat/yacl/java/KeybindingBuilder.kt b/src/compat/yacl/java/KeybindingBuilder.kt new file mode 100644 index 0000000..322ddff --- /dev/null +++ b/src/compat/yacl/java/KeybindingBuilder.kt @@ -0,0 +1,16 @@ +package moe.nea.firmament.compat.yacl + +import dev.isxander.yacl3.api.Controller +import dev.isxander.yacl3.api.Option +import dev.isxander.yacl3.api.controller.ControllerBuilder +import moe.nea.firmament.gui.config.ManagedOption +import moe.nea.firmament.keybindings.SavedKeyBinding + +class KeybindingBuilder( + val option: Option, + val managedOption: ManagedOption +) : ControllerBuilder { + override fun build(): Controller { + return KeybindingController(option, managedOption) + } +} diff --git a/src/compat/yacl/java/KeybindingController.kt b/src/compat/yacl/java/KeybindingController.kt new file mode 100644 index 0000000..6be9dd1 --- /dev/null +++ b/src/compat/yacl/java/KeybindingController.kt @@ -0,0 +1,71 @@ +package moe.nea.firmament.compat.yacl + +import dev.isxander.yacl3.api.Controller +import dev.isxander.yacl3.api.Option +import dev.isxander.yacl3.api.utils.Dimension +import dev.isxander.yacl3.gui.AbstractWidget +import dev.isxander.yacl3.gui.YACLScreen +import dev.isxander.yacl3.gui.controllers.ControllerWidget +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.KeyBindingHandler +import moe.nea.firmament.gui.config.KeyBindingStateManager +import moe.nea.firmament.gui.config.ManagedOption +import moe.nea.firmament.keybindings.SavedKeyBinding + +class KeybindingController( + val option: Option, + val managedOption: ManagedOption, +) : Controller { + val handler = managedOption.handler as KeyBindingHandler + override fun option(): Option { + return option + } + + override fun formatValue(): Text { + return option.pendingValue().format() + } + + override fun provideWidget(screen: YACLScreen, widgetDimension: Dimension): AbstractWidget { + lateinit var button: ControllerWidget + val sm = KeyBindingStateManager( + { option.pendingValue() }, + { option.requestSet(it) }, + { screen.focused = null }, + { screen.focused = button } + ) + button = object : ControllerWidget(this, screen, widgetDimension) { + override fun getHoveredControlWidth(): Int { + return 130 + } + + override fun getValueText(): Text { + return sm.label + } + + override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + return sm.keyboardEvent(keyCode, true) + } + + override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean { + return sm.keyboardEvent(keyCode, false) + } + + override fun unfocus() { + sm.onLostFocus() + } + + override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean { + if (button == 0 && isHovered) { + sm.onClick() + return true + } + return super.mouseClicked(mouseX, mouseY, button) + } + } + option.addListener { t, u -> + sm.updateLabel() + } + sm.updateLabel() + return button + } +} diff --git a/src/compat/yacl/java/YaclIntegration.kt b/src/compat/yacl/java/YaclIntegration.kt new file mode 100644 index 0000000..6c9354a --- /dev/null +++ b/src/compat/yacl/java/YaclIntegration.kt @@ -0,0 +1,119 @@ +package moe.nea.firmament.compat.yacl + +import com.google.auto.service.AutoService +import dev.isxander.yacl3.api.Binding +import dev.isxander.yacl3.api.ButtonOption +import dev.isxander.yacl3.api.ConfigCategory +import dev.isxander.yacl3.api.LabelOption +import dev.isxander.yacl3.api.Option +import dev.isxander.yacl3.api.YetAnotherConfigLib +import dev.isxander.yacl3.api.controller.ControllerBuilder +import dev.isxander.yacl3.api.controller.DoubleSliderControllerBuilder +import dev.isxander.yacl3.api.controller.IntegerSliderControllerBuilder +import dev.isxander.yacl3.api.controller.StringControllerBuilder +import dev.isxander.yacl3.api.controller.TickBoxControllerBuilder +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds +import kotlin.time.DurationUnit +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text +import moe.nea.firmament.gui.config.AllConfigsGui +import moe.nea.firmament.gui.config.BooleanHandler +import moe.nea.firmament.gui.config.ClickHandler +import moe.nea.firmament.gui.config.DurationHandler +import moe.nea.firmament.gui.config.FirmamentConfigScreenProvider +import moe.nea.firmament.gui.config.HudMeta +import moe.nea.firmament.gui.config.HudMetaHandler +import moe.nea.firmament.gui.config.IntegerHandler +import moe.nea.firmament.gui.config.KeyBindingHandler +import moe.nea.firmament.gui.config.ManagedConfig +import moe.nea.firmament.gui.config.ManagedOption +import moe.nea.firmament.gui.config.StringHandler +import moe.nea.firmament.keybindings.SavedKeyBinding +import moe.nea.firmament.util.FirmFormatters + + +@AutoService(FirmamentConfigScreenProvider::class) +class YaclIntegration : FirmamentConfigScreenProvider { + fun buildCategories() = + AllConfigsGui.allConfigs + .map(::buildCategory) + + private fun buildCategory(managedConfig: ManagedConfig): ConfigCategory { + return ConfigCategory.createBuilder() + .name(managedConfig.labelText) + .also { + it.rootGroupBuilder() + .options(buildOptions(managedConfig.sortedOptions)) + } + .build() + } + + fun buildOptions(options: List>): Collection> = + options.map { buildOption(it) } + + private fun buildOption(managedOption: ManagedOption): Option<*> { + val handler = managedOption.handler + val binding = Binding.generic(managedOption.default(), managedOption::value, managedOption::value.setter) + fun createDefaultBinding(function: (Option) -> ControllerBuilder): Option.Builder { + return Option.createBuilder() + .name(managedOption.labelText) + .binding(binding as Binding) + .controller { function(it) } + } + when (handler) { + is ClickHandler -> return ButtonOption.createBuilder() + .name(managedOption.labelText) + .action { t, u -> + handler.runnable() + } + .build() + + is HudMetaHandler -> return ButtonOption.createBuilder() + .name(managedOption.labelText) + .action { t, u -> + handler.openEditor(managedOption as ManagedOption, t) + } + .build() + + is BooleanHandler -> return createDefaultBinding(TickBoxControllerBuilder::create).build() + is StringHandler -> return createDefaultBinding(StringControllerBuilder::create).build() + is IntegerHandler -> return createDefaultBinding { + IntegerSliderControllerBuilder.create(it).range(handler.min, handler.max).step(1) + }.build() + + is DurationHandler -> return Option.createBuilder() + .name(managedOption.labelText) + .binding((binding as Binding).xmap({ it.toDouble(DurationUnit.SECONDS) }, { it.seconds })) + .controller { + DoubleSliderControllerBuilder.create(it) + .formatValue { Text.literal(FirmFormatters.formatTimespan(it.seconds)) } + .step(0.1) + .range(handler.min.toDouble(DurationUnit.SECONDS), handler.max.toDouble(DurationUnit.SECONDS)) + } + .build() + + is KeyBindingHandler -> return createDefaultBinding { + KeybindingBuilder(it, managedOption as ManagedOption) + }.build() + + else -> return LabelOption.create(Text.literal("This option is currently unhandled for this config menu. Please report this as a bug.")) + } + } + + + fun buildConfig(): YetAnotherConfigLib { + return YetAnotherConfigLib.createBuilder() + .title(Text.literal("Firmament")) + .categories(buildCategories()) + .build() + } + + override val key: String + get() = "yacl" + + override fun open(parent: Screen?): Screen { + return buildConfig().generateScreen(parent) + } + +} -- cgit