Add YACL config menu

This commit is contained in:
Linnea Gräf
2024-10-13 19:53:10 +02:00
parent e6142bb936
commit 87b8513730
13 changed files with 567 additions and 306 deletions

View File

@@ -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<SavedKeyBinding>,
val managedOption: ManagedOption<SavedKeyBinding>
) : ControllerBuilder<SavedKeyBinding> {
override fun build(): Controller<SavedKeyBinding> {
return KeybindingController(option, managedOption)
}
}

View File

@@ -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<SavedKeyBinding>,
val managedOption: ManagedOption<SavedKeyBinding>,
) : Controller<SavedKeyBinding> {
val handler = managedOption.handler as KeyBindingHandler
override fun option(): Option<SavedKeyBinding> {
return option
}
override fun formatValue(): Text {
return option.pendingValue().format()
}
override fun provideWidget(screen: YACLScreen, widgetDimension: Dimension<Int>): AbstractWidget {
lateinit var button: ControllerWidget<KeybindingController>
val sm = KeyBindingStateManager(
{ option.pendingValue() },
{ option.requestSet(it) },
{ screen.focused = null },
{ screen.focused = button }
)
button = object : ControllerWidget<KeybindingController>(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
}
}

View File

@@ -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<ManagedOption<*>>): Collection<Option<*>> =
options.map { buildOption(it) }
private fun <T : Any> buildOption(managedOption: ManagedOption<T>): Option<*> {
val handler = managedOption.handler
val binding = Binding.generic(managedOption.default(), managedOption::value, managedOption::value.setter)
fun <T> createDefaultBinding(function: (Option<T>) -> ControllerBuilder<T>): Option.Builder<T> {
return Option.createBuilder<T>()
.name(managedOption.labelText)
.binding(binding as Binding<T>)
.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<HudMeta>, 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<Double>()
.name(managedOption.labelText)
.binding((binding as Binding<Duration>).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<SavedKeyBinding>)
}.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)
}
}