aboutsummaryrefslogtreecommitdiff
path: root/src/compat/yacl/java/YaclIntegration.kt
blob: 239d3a09fce8437207b3771364818d990daa79aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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.OptionGroup
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 dev.isxander.yacl3.gui.YACLScreen
import dev.isxander.yacl3.gui.tab.ListHolderWidget
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
import net.minecraft.client.gui.Element
import net.minecraft.client.gui.screen.Screen
import net.minecraft.text.Text
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() =
		ManagedConfig.Category.entries
			.map(::buildCategory)

	private fun buildCategory(category: ManagedConfig.Category): ConfigCategory {
		return ConfigCategory.createBuilder()
			.name(category.labelText)
			.also { categoryB ->
				category.configs.forEach {
					categoryB.group(
						OptionGroup.createBuilder()
							.name(it.labelText)
							.options(buildOptions(it.sortedOptions))
							.build())
				}
			}
			.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 = it; managedOption.element.save() })

		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 object : YACLScreen(buildConfig(), parent) {
			override fun setFocused(focused: Element?) {
				if (this.focused is KeybindingWidget &&
					focused is ListHolderWidget<*>
				) {
					return
				}
				super.setFocused(focused)
			}

			override fun shouldCloseOnEsc(): Boolean {
				if (focused is KeybindingWidget) {
					return false
				}
				return super.shouldCloseOnEsc()
			}
		}
	}

}