From d9d91a1305e8cfe507af7fce0608f7810dea06b4 Mon Sep 17 00:00:00 2001 From: Bibi Reden Date: Sun, 24 Nov 2024 18:43:53 -0600 Subject: [PATCH] [feat/semver] Stage new beta and add all ui changes --- CHANGELOG.md | 7 +- gradle.properties | 2 +- .../data_attributes/config/ConfigUIState.kt | 3 +- .../config/DataAttributesConfigProviders.kt | 6 +- .../config/AttributeConfigComponent.kt | 2 + .../config/AttributeOverrideComponent.kt | 12 +- .../components/config/ConfigDockComponent.kt | 28 ++ .../config/entities/EntityTypesComponent.kt | 147 +++++++++++ .../entities/EntityTypesHeaderComponent.kt | 126 +++++++++ .../function/AttributeFunctionComponent.kt | 153 ++++++----- .../AttributeFunctionHeaderComponent.kt | 115 +++++---- .../providers/AttributeFunctionProvider.kt | 240 ++---------------- .../providers/AttributeFunctionProviderV2.kt | 37 --- .../config/providers/EntityTypesProviderV2.kt | 33 +++ 14 files changed, 517 insertions(+), 394 deletions(-) create mode 100644 src/main/kotlin/com/bibireden/data_attributes/ui/components/config/ConfigDockComponent.kt create mode 100644 src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesComponent.kt create mode 100644 src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesHeaderComponent.kt delete mode 100644 src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProviderV2.kt create mode 100644 src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/EntityTypesProviderV2.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index f21a85a..647e4eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2 +1,5 @@ -## Fixes 🍋 -- Fixed attribute functions not being able to be edited (and that were default). \ No newline at end of file +## Additions 🍎 +- Added saved state for collapsed entries (session based, saved until game relaunch) +## Changes 🍐 +- Applied a different method to updating UI components. +- Most entries sync, but there is still some work to do, so it will stay as beta until the rest of the issues are figured out. \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 56c5b18..88ee859 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,7 @@ loom_version=1.8-SNAPSHOT minecraft_version=1.20.1 fabric_kotlin_version=1.11.0+kotlin.2.0.0 fabric_api_version=0.92.2+1.20.1 -mod_version=2.0.2+1.20.1 +mod_version=2.0.3+1.20.1-beta.1 loader=fabric # Mappings diff --git a/src/main/kotlin/com/bibireden/data_attributes/config/ConfigUIState.kt b/src/main/kotlin/com/bibireden/data_attributes/config/ConfigUIState.kt index c348f23..9f355b0 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/config/ConfigUIState.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/config/ConfigUIState.kt @@ -5,6 +5,7 @@ data class ConfigUIState(val collapsible: Collapsible = Collapsible()) { val overrides: MutableMap = mutableMapOf(), val functionParents: MutableMap = mutableMapOf(), val functionChildren: MutableMap> = mutableMapOf(), - val entityTypes: MutableMap = mutableMapOf() + val entityTypeHeaders: MutableMap = mutableMapOf(), + val entityTypeEntries: MutableMap> = mutableMapOf() ) } \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/config/DataAttributesConfigProviders.kt b/src/main/kotlin/com/bibireden/data_attributes/config/DataAttributesConfigProviders.kt index 5e58493..a7ab076 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/config/DataAttributesConfigProviders.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/config/DataAttributesConfigProviders.kt @@ -2,9 +2,9 @@ package com.bibireden.data_attributes.config import com.bibireden.data_attributes.ui.colors.ColorCodes import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProvider -import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProviderV2 import com.bibireden.data_attributes.ui.config.providers.AttributeOverrideProvider import com.bibireden.data_attributes.ui.config.providers.EntityTypesProvider +import com.bibireden.data_attributes.ui.config.providers.EntityTypesProviderV2 import com.google.common.base.Predicate import io.wispforest.owo.config.ui.OptionComponentFactory import io.wispforest.owo.ui.component.Components @@ -40,11 +40,11 @@ object DataAttributesConfigProviders { } val ATTRIBUTE_FUNCTIONS_FACTORY = OptionComponentFactory { _, option -> - return@OptionComponentFactory AttributeFunctionProviderV2(option).let { OptionComponentFactory.Result(it, it) } + return@OptionComponentFactory AttributeFunctionProvider(option).let { OptionComponentFactory.Result(it, it) } } val ENTITY_TYPES_FACTORY = OptionComponentFactory { _, option -> - return@OptionComponentFactory EntityTypesProvider(option).let { OptionComponentFactory.Result(it, it) } + return@OptionComponentFactory EntityTypesProviderV2(option).let { OptionComponentFactory.Result(it, it) } } fun textBoxComponent(txt: Text, obj: Any, predicate: Predicate? = null, onChange: ((String) -> Unit)? = null, textBoxID: String? = null): FlowLayout { diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeConfigComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeConfigComponent.kt index 1babbb8..32716c1 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeConfigComponent.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeConfigComponent.kt @@ -15,4 +15,6 @@ interface AttributeConfigComponent { /** If the given entry is currently registered. */ val isRegistered: Boolean get() = registryEntry != null + + fun update() } \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeOverrideComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeOverrideComponent.kt index c9e68d8..8756eba 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeOverrideComponent.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/AttributeOverrideComponent.kt @@ -75,11 +75,13 @@ class AttributeOverrideComponent( titleLayout().tooltip(null) - if (!isRegistered()) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) - } - else if (isDefault()) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + when { + !isRegistered() -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) + } + isDefault() -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + } } } diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/ConfigDockComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/ConfigDockComponent.kt new file mode 100644 index 0000000..9e8a625 --- /dev/null +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/ConfigDockComponent.kt @@ -0,0 +1,28 @@ +package com.bibireden.data_attributes.ui.components.config + +import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents +import com.bibireden.data_attributes.ui.renderers.ButtonRenderers +import io.wispforest.owo.ui.component.ButtonComponent +import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Sizing +import io.wispforest.owo.ui.core.VerticalAlignment +import net.minecraft.text.Text +import org.jetbrains.annotations.ApiStatus + +@ApiStatus.Internal +@Suppress("UnstableApiUsage") +class ConfigDockComponent(private val defaultProperties: ConfigDefaultProperties) : FlowLayout(Sizing.fill(100), Sizing.fixed(15), Algorithm.HORIZONTAL) { + class ConfigDefaultProperties(val onRemoveToggled: (ConfigDockComponent, ButtonComponent) -> Unit, val onEditToggled: (ConfigDockComponent, ButtonComponent) -> Unit) + + init { + verticalAlignment(VerticalAlignment.BOTTOM) + gap(10) + id("dock") + + child(ButtonComponents.remove { defaultProperties.onRemoveToggled(this, it) } + .renderer(ButtonRenderers.STANDARD)) + child(Components.button(Text.translatable("text.config.data_attributes.data_entry.edit")) { defaultProperties.onEditToggled(this, it) } + .renderer(ButtonRenderers.STANDARD)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesComponent.kt new file mode 100644 index 0000000..db3b3eb --- /dev/null +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesComponent.kt @@ -0,0 +1,147 @@ +package com.bibireden.data_attributes.ui.components.config.entities + +import com.bibireden.data_attributes.DataAttributesClient +import com.bibireden.data_attributes.api.DataAttributesAPI +import com.bibireden.data_attributes.config.DataAttributesConfigProviders.registryEntryToText +import com.bibireden.data_attributes.config.DataAttributesConfigProviders.textBoxComponent +import com.bibireden.data_attributes.config.Validators +import com.bibireden.data_attributes.config.entities.EntityTypeData +import com.bibireden.data_attributes.config.entities.EntityTypeEntry +import com.bibireden.data_attributes.ext.round +import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents +import com.bibireden.data_attributes.ui.components.config.AttributeConfigComponent +import com.bibireden.data_attributes.ui.components.config.ConfigDockComponent +import com.bibireden.data_attributes.ui.components.entries.DataEntryComponent +import com.bibireden.data_attributes.ui.components.entries.EntryComponents +import com.bibireden.data_attributes.ui.components.fields.FieldComponents +import com.bibireden.data_attributes.ui.config.providers.EntityTypesProviderV2 +import com.bibireden.data_attributes.ui.renderers.ButtonRenderers +import io.wispforest.owo.config.Option +import io.wispforest.owo.config.ui.component.SearchAnchorComponent +import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.component.LabelComponent +import io.wispforest.owo.ui.component.TextBoxComponent +import io.wispforest.owo.ui.container.CollapsibleContainer +import io.wispforest.owo.ui.container.Containers +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Sizing +import io.wispforest.owo.ui.core.VerticalAlignment +import net.minecraft.entity.EntityType +import net.minecraft.entity.LivingEntity +import net.minecraft.entity.attribute.ClampedEntityAttribute +import net.minecraft.entity.attribute.DefaultAttributeRegistry +import net.minecraft.entity.attribute.EntityAttribute +import net.minecraft.registry.Registries +import net.minecraft.registry.Registry +import net.minecraft.text.Text +import net.minecraft.util.Identifier + +class EntityTypesComponent(override var identifier: Identifier, private var parentId: Identifier, private var entry: EntityTypeEntry, private val provider: EntityTypesProviderV2) + : CollapsibleContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.entityTypeEntries[parentId.toString()]?.get(identifier.toString()) ?: true), AttributeConfigComponent { + + override val registry: Registry = Registries.ATTRIBUTE + + override val isDefault: Boolean + get() = provider.backing[parentId]?.data?.get(identifier) == null + + private fun updateSearchAnchor() { + childById(SearchAnchorComponent::class.java, "search-anchor")?.remove() + child(SearchAnchorComponent(titleLayout(), Option.Key.ROOT, { identifier.toString() }, { Text.translatable(identifier.toTranslationKey()).toString() }).id("search-anchor")) + } + + private fun updateTextLabel() { + titleLayout().children().filterIsInstance().first().text(registryEntryToText(identifier, registry, { it.translationKey }, isDefault)) + } + + override fun update() { + titleLayout().tooltip(null) + when { + !isRegistered -> titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) + isDefault -> titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + } + + // find fallback + try { + entry.fallback = Registries.ENTITY_TYPE.get(parentId) + ?.let { entityType -> registry.get(identifier)?.let(DefaultAttributeRegistry.get(entityType as EntityType)::getBaseValue) } + ?.round(2) + } + catch (_: IllegalArgumentException) { + entry.fallback = 0.0 + } + + val fallback = entry.fallback + if (fallback != null) { + childById(FlowLayout::class.java, "fallback")?.remove() + child(textBoxComponent(Text.translatable("text.config.data_attributes.data_entry.fallback"), fallback, Validators::isNumeric).id("fallback")) + } + + updateTextLabel() + updateSearchAnchor() + } + + + private val valueEntry: DataEntryComponent = EntryComponents.double(Text.translatable("text.config.data_attributes.data_entry.entity_types.value"), DataEntryComponent.Properties({ updateEntryToBacking(entry.copy(value = it)) }), entry.value.toString()).also { + val attribute = registryEntry + if (attribute is ClampedEntityAttribute) { + it.tooltip(Text.translatable("text.config.data_attributes.data_entry.entity_type_value", identifier, attribute.minValue, attribute.maxValue)) + } + } + + private fun updateEntryToBacking(entry: EntityTypeEntry) { + val etd = provider.backing[parentId] ?: return + val mapping = etd.data.toMutableMap() + mapping[identifier] = entry + provider.backing[parentId] = EntityTypeData(mapping) + + update() + } + + fun updateParent(parentId: Identifier) { this.parentId = parentId } + + + init { + onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.entityTypeEntries.computeIfAbsent(parentId.toString()) { mutableMapOf() } [identifier.toString()] = it } + + child(ConfigDockComponent(ConfigDockComponent.ConfigDefaultProperties({ _, _ -> + val entry = provider.backing[parentId]?.data?.toMutableMap() ?: return@ConfigDefaultProperties + if (entry.remove(identifier) != null) { + val defaultEntry = DataAttributesAPI.serverManager.defaults.types.entries[parentId]?.get(identifier) + if (defaultEntry != null) { + valueEntry.textbox.text = defaultEntry.value.toString() + } + else remove() + + provider.backing[parentId] = EntityTypeData(entry) + + update() + } + }, {_, _ -> + if (childById(FlowLayout::class.java, "edit-field") == null) { + val field = FieldComponents.identifier( + { newId, _ -> + val entry = provider.backing[parentId]?.data?.toMutableMap() ?: return@identifier + if (entry.containsKey(newId) || !registry.containsId(newId)) return@identifier + + entry[newId] = entry.remove(identifier) ?: return@identifier + provider.backing[parentId] = EntityTypeData(entry) + + identifier = newId + + update() + }, + autocomplete = Registries.ATTRIBUTE.ids + ) + + field.textBox.predicate = { provider.backing[parentId]?.data?.get(it) == null && registry.containsId(it) } + + child(0, field) + } + } + ))) + + valueEntry.also(::child) + + update() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesHeaderComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesHeaderComponent.kt new file mode 100644 index 0000000..5d16856 --- /dev/null +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/entities/EntityTypesHeaderComponent.kt @@ -0,0 +1,126 @@ +package com.bibireden.data_attributes.ui.components.config.entities + +import com.bibireden.data_attributes.DataAttributesClient +import com.bibireden.data_attributes.api.DataAttributesAPI +import com.bibireden.data_attributes.config.DataAttributesConfigProviders.registryEntryToText +import com.bibireden.data_attributes.config.entities.EntityTypeData +import com.bibireden.data_attributes.config.entities.EntityTypeEntry +import com.bibireden.data_attributes.ui.components.CollapsibleFoldableContainer +import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents +import com.bibireden.data_attributes.ui.components.config.AttributeConfigComponent +import com.bibireden.data_attributes.ui.components.config.ConfigDockComponent +import com.bibireden.data_attributes.ui.components.config.function.AttributeFunctionComponent +import com.bibireden.data_attributes.ui.components.fields.FieldComponents +import com.bibireden.data_attributes.ui.config.providers.EntityTypesProviderV2 +import com.bibireden.data_attributes.ui.renderers.ButtonRenderers +import io.wispforest.owo.config.Option +import io.wispforest.owo.config.ui.component.SearchAnchorComponent +import io.wispforest.owo.ui.component.Components +import io.wispforest.owo.ui.component.LabelComponent +import io.wispforest.owo.ui.container.Containers +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Sizing +import io.wispforest.owo.ui.core.VerticalAlignment +import net.minecraft.entity.EntityType +import net.minecraft.entity.attribute.EntityAttribute +import net.minecraft.registry.Registries +import net.minecraft.registry.Registry +import net.minecraft.text.Text +import net.minecraft.util.Identifier + +class EntityTypesHeaderComponent(override var identifier: Identifier, private val entityTypes: MutableMap, private val provider: EntityTypesProviderV2) + : CollapsibleFoldableContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.entityTypeHeaders[identifier.toString()] ?: true), AttributeConfigComponent> { + + override val registry: Registry> = Registries.ENTITY_TYPE + + override val isDefault: Boolean + get() = !provider.backing.containsKey(identifier) + + private fun updateSearchAnchor() { + childById(SearchAnchorComponent::class.java, "search-anchor")?.remove() + child(SearchAnchorComponent(titleLayout(), Option.Key.ROOT, { identifier.toString() }, { Text.translatable(identifier.toTranslationKey()).toString() }).id("search-anchor")) + } + + private fun updateTextLabel() { + titleLayout().children().filterIsInstance().first().text(registryEntryToText(identifier, registry, { it.translationKey }, isDefault)) + } + + private fun createEntry(entryId: Identifier, entry: EntityTypeEntry): EntityTypesComponent = childById(EntityTypesComponent::class.java, "entry#$entryId") ?: EntityTypesComponent(entryId, identifier, entry, provider).also { it.id("entry#$entryId")}.also(::child) + + override fun update() { + titleLayout().tooltip(null) + when { + !isRegistered -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) + } + isDefault -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + } + } + updateTextLabel() + updateSearchAnchor() + } + + fun addEntityTypes(entityTypes: MutableMap) { + for ((id, types) in entityTypes) createEntry(id, types) + } + + init { + onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.entityTypeHeaders[identifier.toString()] = it } + + child( + ConfigDockComponent(ConfigDockComponent.ConfigDefaultProperties({ _, _ -> + provider.backing.remove(identifier) + + val entries = DataAttributesAPI.serverManager.defaults.types.entries[identifier] + + if (entries != null) { + forEachDescendant { if (it is EntityTypesComponent) { if (entries.containsKey(it.identifier)) it.update() else it.remove() } } + update() + } + else remove() + }) + { _, _ -> + if (childById(FlowLayout::class.java, "edit-field") == null) { + val field = FieldComponents.identifier( + { newId, _ -> + if (provider.backing.containsKey(newId) || !registry.containsId(newId)) return@identifier + + provider.backing.remove(identifier)?.let { provider.backing[newId] = it } + + identifier = newId + + children().filterIsInstance().forEach { it.updateParent(identifier) } + + update() + }, + autocomplete = registry.ids + ) + + field.textBox.predicate = { provider.backing[identifier]?.data?.get(it) == null && registry.containsId(it) } + + child(0, field) + } + }).child( + Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { + val map = provider.backing[identifier]?.data?.toMutableMap() ?: mutableMapOf() + val childId = Identifier("unknown") + val entry = EntityTypeEntry() + map[childId] = entry + provider.backing[identifier] = EntityTypeData(map) + + child(1, EntityTypesComponent(childId, identifier, entry, provider)) + + update() + } + .renderer(ButtonRenderers.STANDARD) + .horizontalSizing(Sizing.content()) + .verticalSizing(Sizing.fixed(20)) + ) + ) + + addEntityTypes(this.entityTypes) + + update() + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionComponent.kt index 36e8115..926e0b7 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionComponent.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionComponent.kt @@ -1,19 +1,25 @@ package com.bibireden.data_attributes.ui.components.config.function import com.bibireden.data_attributes.DataAttributesClient +import com.bibireden.data_attributes.api.DataAttributesAPI import com.bibireden.data_attributes.api.attribute.StackingBehavior import com.bibireden.data_attributes.config.DataAttributesConfigProviders.registryEntryToText import com.bibireden.data_attributes.config.functions.AttributeFunction import com.bibireden.data_attributes.mutable.MutableEntityAttribute import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents +import com.bibireden.data_attributes.ui.components.config.AttributeConfigComponent +import com.bibireden.data_attributes.ui.components.config.AttributeOverrideComponent +import com.bibireden.data_attributes.ui.components.config.ConfigDockComponent +import com.bibireden.data_attributes.ui.components.config.entities.EntityTypesComponent import com.bibireden.data_attributes.ui.components.entries.DataEntryComponent import com.bibireden.data_attributes.ui.components.entries.EntryComponents import com.bibireden.data_attributes.ui.components.fields.FieldComponents -import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProviderV2 +import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProvider import com.bibireden.data_attributes.ui.renderers.ButtonRenderers import io.wispforest.owo.config.Option import io.wispforest.owo.config.ui.component.ConfigToggleButton import io.wispforest.owo.config.ui.component.SearchAnchorComponent +import io.wispforest.owo.ui.component.ButtonComponent import io.wispforest.owo.ui.component.Components import io.wispforest.owo.ui.component.LabelComponent import io.wispforest.owo.ui.container.CollapsibleContainer @@ -24,26 +30,25 @@ import io.wispforest.owo.ui.core.Sizing import io.wispforest.owo.ui.core.VerticalAlignment import net.minecraft.entity.attribute.ClampedEntityAttribute import net.minecraft.registry.Registries +import net.minecraft.registry.Registry import net.minecraft.text.Text import net.minecraft.util.Identifier +import java.util.concurrent.Flow -class AttributeFunctionComponent(private var identifier: Identifier, private var function: AttributeFunction, private var parentId: Identifier, private val provider: AttributeFunctionProviderV2) - : CollapsibleContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.functionChildren[parentId.toString()]?.get(identifier.toString()) ?: true) +class AttributeFunctionComponent(override var identifier: Identifier, private var function: AttributeFunction, private var parentId: Identifier, private val provider: AttributeFunctionProvider) + : CollapsibleContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.functionChildren[parentId.toString()]?.get(identifier.toString()) ?: true), + AttributeConfigComponent { - private val backing = provider.backing - - /** Current registered attribute with this function. */ - private val attribute: MutableEntityAttribute? - get() = Registries.ATTRIBUTE[identifier] - - private val valueEntry: DataEntryComponent + @Suppress("UNCHECKED_CAST") + override val registry: Registry = Registries.ATTRIBUTE as Registry - private fun isRegistered() = attribute != null + private val backing = provider.backing - private fun isDefault() = provider.backing[parentId]?.containsKey(identifier) != true + override val isDefault get() = provider.backing[parentId]?.get(identifier) == null private fun updateEntryToBacking(id: Identifier, function: AttributeFunction) { - backing[parentId]?.set(id, function) + backing.computeIfAbsent(parentId) { mutableMapOf() }[id] = function + update() } private fun updateSearchAnchor() { @@ -52,87 +57,105 @@ class AttributeFunctionComponent(private var identifier: Identifier, private var } private fun updateTextLabel() { - titleLayout().children().filterIsInstance().first().text(registryEntryToText(identifier, Registries.ATTRIBUTE, { it.translationKey }, isDefault())) + titleLayout().children().filterIsInstance().first().text(registryEntryToText(identifier, Registries.ATTRIBUTE, { it.translationKey }, isDefault)) + } + + private val toggleButton = ConfigToggleButton().enabled(function.enabled).also { + it.onPress { updateEntryToBacking(identifier, function.copy(enabled = !function.enabled)) } + it.renderer(ButtonRenderers.STANDARD) } - private fun updateComponent() { + private val valueEntry: DataEntryComponent = EntryComponents.double(Text.translatable("text.config.data_attributes.data_entry.functions.value"), DataEntryComponent.Properties({ updateEntryToBacking(identifier, function.copy(value = it)) }), function.value.toString()).also { + if (registryEntry is ClampedEntityAttribute) { + val clamped = registryEntry as ClampedEntityAttribute + it.tooltip(Text.translatable("text.config.data_attributes.data_entry.function_child", identifier, clamped.minValue, clamped.maxValue)) + } + } + + private val stackingBehaviorButton = Components.button(Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}")) { updateStackingBehavior(StackingBehavior.entries[function.behavior.ordinal xor 1]) } + .apply { + renderer(ButtonRenderers.STANDARD) + positioning(Positioning.relative(100, 0)).horizontalSizing(Sizing.fixed(65)) + } + + override fun update() { titleLayout().tooltip(null) - if (!isRegistered()) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) - } else if (isDefault()) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + when { + !isRegistered -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) + } + isDefault -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + } } updateTextLabel() updateSearchAnchor() } + fun updateParent(parentId: Identifier) { this.parentId = parentId } + + private fun updateStackingBehavior(to: StackingBehavior) { + function.behavior = to + stackingBehaviorButton.message = Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}") + updateEntryToBacking(identifier, function.copy(behavior = function.behavior)) + } + init { onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.functionChildren.computeIfAbsent(parentId.toString()) { mutableMapOf() }[identifier.toString()] = it } - child(Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(15)) - .apply { - verticalAlignment(VerticalAlignment.BOTTOM) - gap(10) - } - .also { fl -> - fl.child(ConfigToggleButton().enabled(function.enabled).onPress { updateEntryToBacking(identifier, function.copy(enabled = !function.enabled)) } - .renderer(ButtonRenderers.STANDARD)) - - if (!isDefault()) { - fl.child(ButtonComponents.remove { backing[parentId]?.remove(identifier); remove() }.renderer(ButtonRenderers.STANDARD)) + child(ConfigDockComponent( + ConfigDockComponent.ConfigDefaultProperties({ _, _ -> + val defaultEntry = DataAttributesAPI.serverManager.defaults.functions.entries[parentId]?.get(identifier) + if (defaultEntry != null) { + toggleButton.enabled(defaultEntry.enabled) + valueEntry.textbox.text = defaultEntry.value.toString() + updateStackingBehavior(defaultEntry.behavior) + } + else remove() - fl.child(Components.button(Text.translatable("text.config.data_attributes.data_entry.edit")) { - if (fl.childById(FlowLayout::class.java, "edit-field") == null) { - val field = FieldComponents.identifier( - { newId, _ -> - val entry = backing[parentId] ?: return@identifier - if (!Registries.ATTRIBUTE.containsId(newId) || entry[newId] != null) return@identifier + backing[parentId]?.remove(identifier) != null - entry[newId] = entry.remove(identifier) ?: return@identifier - backing[parentId] = entry + update() + }) + { dc, _ -> + if (dc.childById(FlowLayout::class.java, "edit-field") == null && backing[parentId]?.get(identifier) != null) { + val field = FieldComponents.identifier( + { newId, _ -> + val entry = backing.computeIfAbsent(parentId) { mutableMapOf() } + if (!registry.containsId(newId) || entry[newId] != null) return@identifier - identifier = newId + entry[newId] = entry.remove(identifier) ?: return@identifier + backing[parentId] = entry - updateComponent() - }, - autocomplete = Registries.ATTRIBUTE.ids - ) + identifier = newId - field.textBox.predicate = { backing[parentId]?.get(it) == null && Registries.ATTRIBUTE.containsId(it) } + for (fc in children().filterIsInstance()) { fc.updateParent(identifier) } - child(0, field) - } - } - .renderer(ButtonRenderers.STANDARD) + update() + }, + autocomplete = Registries.ATTRIBUTE.ids ) + + field.textBox.predicate = { backing[parentId]?.get(it) == null && Registries.ATTRIBUTE.containsId(it) } + + child(0, field) } } - ) + ).apply { + child(0, toggleButton) + }) - valueEntry = EntryComponents.double(Text.translatable("text.config.data_attributes.data_entry.functions.value"), DataEntryComponent.Properties({ updateEntryToBacking(identifier, function.copy(value = it)) }), function.value.toString()).also { - if (attribute is ClampedEntityAttribute) { - val clamped = attribute as ClampedEntityAttribute - it.tooltip(Text.translatable("text.config.data_attributes.data_entry.function_child", identifier, clamped.minValue, clamped.maxValue)) - } - }.also(::child) + valueEntry.also(::child) child( Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(20)).apply { verticalAlignment(VerticalAlignment.CENTER) child(Components.label(Text.translatable("text.config.data_attributes.data_entry.functions.behavior")).sizing(Sizing.content(), Sizing.fixed(20))) - child( - Components.button(Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}")) { - function.behavior = StackingBehavior.entries[function.behavior.ordinal xor 1] - it.message = Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}") - updateEntryToBacking(identifier, function.copy(behavior = function.behavior)) - } - .renderer(ButtonRenderers.STANDARD) - .positioning(Positioning.relative(100, 0)).horizontalSizing(Sizing.fixed(65)) - ) + child(stackingBehaviorButton) } ) - updateComponent() + update() } } \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionHeaderComponent.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionHeaderComponent.kt index 40ed80d..badecd6 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionHeaderComponent.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/components/config/function/AttributeFunctionHeaderComponent.kt @@ -1,13 +1,15 @@ package com.bibireden.data_attributes.ui.components.config.function import com.bibireden.data_attributes.DataAttributesClient +import com.bibireden.data_attributes.api.DataAttributesAPI import com.bibireden.data_attributes.config.DataAttributesConfigProviders.registryEntryToText import com.bibireden.data_attributes.config.functions.AttributeFunction import com.bibireden.data_attributes.ui.components.CollapsibleFoldableContainer import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents import com.bibireden.data_attributes.ui.components.config.AttributeConfigComponent +import com.bibireden.data_attributes.ui.components.config.ConfigDockComponent import com.bibireden.data_attributes.ui.components.fields.FieldComponents -import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProviderV2 +import com.bibireden.data_attributes.ui.config.providers.AttributeFunctionProvider import com.bibireden.data_attributes.ui.renderers.ButtonRenderers import io.wispforest.owo.config.Option import io.wispforest.owo.config.ui.component.SearchAnchorComponent @@ -23,18 +25,14 @@ import net.minecraft.registry.Registry import net.minecraft.text.Text import net.minecraft.util.Identifier -class AttributeFunctionHeaderComponent(override var identifier: Identifier, private val provider: AttributeFunctionProviderV2) : CollapsibleFoldableContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.functionParents[identifier.toString()] ?: true), AttributeConfigComponent { +class AttributeFunctionHeaderComponent(override var identifier: Identifier, private val functions: MutableMap, private val provider: AttributeFunctionProvider) : CollapsibleFoldableContainer(Sizing.content(), Sizing.content(), Text.of(""), DataAttributesClient.UI_STATE.collapsible.functionParents[identifier.toString()] ?: true), AttributeConfigComponent { override val registry: Registry get() = Registries.ATTRIBUTE - /** Current functions of the header obtained from the provider. */ - val functions: MutableMap? - get() = provider.backing[identifier] - override val isDefault: Boolean get() = !provider.backing.containsKey(identifier) - private fun createEntry(childId: Identifier, function: AttributeFunction): AttributeFunctionComponent = AttributeFunctionComponent(childId, function, identifier, provider).also(::child) + private fun createEntry(childId: Identifier, function: AttributeFunction): AttributeFunctionComponent = childById(AttributeFunctionComponent::class.java, "child#$childId") ?: AttributeFunctionComponent(childId, function, identifier, provider).also { it.id("child#$childId") }.also(::child) private fun updateSearchAnchor() { childById(SearchAnchorComponent::class.java, "search-anchor")?.remove() @@ -45,80 +43,85 @@ class AttributeFunctionHeaderComponent(override var identifier: Identifier, priv titleLayout().children().filterIsInstance().first().text(registryEntryToText(identifier, Registries.ATTRIBUTE, { it.translationKey }, isDefault)) } - private fun updateComponent() { + override fun update() { titleLayout().tooltip(null) - if (!isRegistered) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) - } else if (isDefault) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + when { + !isRegistered -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) + } + isDefault -> { + titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) + } } updateTextLabel() updateSearchAnchor() } + fun addFunctions(functions: MutableMap) { + for ((id, function) in functions) createEntry(id, function) + } + init { onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.functionParents[identifier.toString()] = it } - updateComponent() + update() child( - Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(15)) - .apply { - verticalAlignment(VerticalAlignment.CENTER) - gap(10) - id("dock") - } - .also { fl -> - if (!isDefault) { - fl.child(ButtonComponents.remove { provider.backing.remove(identifier); remove() } - .renderer(ButtonRenderers.STANDARD)) + ConfigDockComponent(ConfigDockComponent.ConfigDefaultProperties({ _, _ -> + provider.backing.remove(identifier) - fl.child(Components.button(Text.translatable("text.config.data_attributes.data_entry.edit")) { - if (childById(FlowLayout::class.java, "edit-field") == null) { - val field = FieldComponents.identifier( - { newId, _ -> - if (provider.backing.containsKey(newId) || !Registries.ATTRIBUTE.containsId(newId)) return@identifier + val entries = DataAttributesAPI.serverManager.defaults.functions.entries[identifier] - provider.backing.remove(identifier)?.let { provider.backing[newId] = it } + if (entries != null) { + forEachDescendant { + if (it is AttributeFunctionComponent) { if (entries.containsKey(it.identifier)) it.update() else it.remove() } + } + update() + } + else remove() + }) + { _, _ -> + if (childById(FlowLayout::class.java, "edit-field") == null) { + val field = FieldComponents.identifier( + { newId, _ -> + if (provider.backing.containsKey(newId) || !registry.containsId(newId)) return@identifier - identifier = newId + provider.backing.remove(identifier)?.let { provider.backing[newId] = it } - updateComponent() - }, - autocomplete = Registries.ATTRIBUTE.ids - ) + identifier = newId - field.textBox.predicate = { provider.backing[identifier]?.get(it) == null && Registries.ATTRIBUTE.containsId(it) } + for (afc in children().filterIsInstance()) { afc.updateParent(identifier) } - child(0, field) - } - } - .renderer(ButtonRenderers.STANDARD) + update() + }, + autocomplete = registry.ids ) - } - fl.child( - Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { - val entries = provider.backing[identifier] ?: return@button + field.textBox.predicate = { provider.backing[identifier]?.get(it) == null && registry.containsId(it) } - val childId = Identifier("unknown") - val function = AttributeFunction() + child(0, field) + } + }).child( + Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { + val entries = provider.backing.computeIfAbsent(identifier) { mutableMapOf() } - entries[childId] = function + val childId = Identifier("unknown") + val function = AttributeFunction() - provider.backing.computeIfAbsent(identifier) { mutableMapOf() }[childId] = function + entries[childId] = function - child(1, AttributeFunctionComponent(childId, function, identifier, provider)) + provider.backing[identifier] = entries - updateComponent() - } - .renderer(ButtonRenderers.STANDARD) - .horizontalSizing(Sizing.content()) - .verticalSizing(Sizing.fixed(20)) - ) - } + child(2, AttributeFunctionComponent(childId, function, identifier, provider)) + + update() + } + .renderer(ButtonRenderers.STANDARD) + .horizontalSizing(Sizing.content()) + .verticalSizing(Sizing.fixed(20)) + ) ) - this.functions?.forEach(::createEntry) + addFunctions(this.functions) } } \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProvider.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProvider.kt index 19e8b59..3e5333f 100644 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProvider.kt +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProvider.kt @@ -1,253 +1,45 @@ package com.bibireden.data_attributes.ui.config.providers -import com.bibireden.data_attributes.DataAttributesClient import com.bibireden.data_attributes.api.DataAttributesAPI -import com.bibireden.data_attributes.api.attribute.StackingBehavior -import com.bibireden.data_attributes.config.DataAttributesConfigProviders.registryEntryToText -import com.bibireden.data_attributes.config.DataAttributesConfigProviders.textBoxComponent -import com.bibireden.data_attributes.config.Validators import com.bibireden.data_attributes.config.functions.AttributeFunction import com.bibireden.data_attributes.config.functions.AttributeFunctionConfig -import com.bibireden.data_attributes.ui.components.CollapsibleFoldableContainer -import com.bibireden.data_attributes.ui.components.buttons.ButtonComponents -import com.bibireden.data_attributes.ui.components.fields.FieldComponents +import com.bibireden.data_attributes.ui.components.config.function.AttributeFunctionHeaderComponent import com.bibireden.data_attributes.ui.renderers.ButtonRenderers import io.wispforest.owo.config.Option -import io.wispforest.owo.config.ui.component.ConfigToggleButton import io.wispforest.owo.config.ui.component.OptionValueProvider -import io.wispforest.owo.config.ui.component.SearchAnchorComponent import io.wispforest.owo.ui.component.Components -import io.wispforest.owo.ui.component.LabelComponent -import io.wispforest.owo.ui.container.CollapsibleContainer -import io.wispforest.owo.ui.container.Containers import io.wispforest.owo.ui.container.FlowLayout -import io.wispforest.owo.ui.core.Component -import io.wispforest.owo.ui.core.Positioning import io.wispforest.owo.ui.core.Sizing -import io.wispforest.owo.ui.core.VerticalAlignment -import net.minecraft.entity.attribute.ClampedEntityAttribute -import net.minecraft.entity.attribute.EntityAttribute -import net.minecraft.registry.Registries import net.minecraft.text.Text import net.minecraft.util.Identifier class AttributeFunctionProvider(val option: Option) : FlowLayout(Sizing.fill(100), Sizing.content(), Algorithm.VERTICAL), OptionValueProvider { - private val backing = option.value().data - - private val headerComponents: MutableMap = mutableMapOf() - private val entryComponents: MutableMap = mutableMapOf() - - private fun isFunctionHeaderDefault(id: Identifier) = !backing.containsKey(id) - - private fun isFunctionChildDefault(parentId: Identifier, childId: Identifier) = backing[parentId]?.containsKey(childId) != true - - private fun updateHeader(id: Identifier, component: CollapsibleContainer, isDefault: Boolean) { - component.titleLayout().children().filterIsInstance().first().text(registryEntryToText(id, Registries.ATTRIBUTE, { it.translationKey }, isDefault)) - } - - private fun updateChild(id: Identifier, parentId: Identifier, incomingFunction: AttributeFunction, component: CollapsibleContainer) { - backing[parentId]?.set(id, incomingFunction) - } - - private fun getOrCreateEntryContainer(id: Identifier, isDefault: Boolean): CollapsibleFoldableContainer { - return childById(CollapsibleFoldableContainer::class.java, id.toString()) ?: CollapsibleFoldableContainer(Sizing.content(), Sizing.content(), registryEntryToText(id, Registries.ATTRIBUTE, { it.translationKey }, isDefault), DataAttributesClient.UI_STATE.collapsible.functionParents[id.toString()] ?: true).also { cf -> - headerComponents[id] = cf - cf.id(id.toString()) - cf.onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.functionParents[id.toString()] = it } - - cf.child(Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(15)) - .apply { - verticalAlignment(VerticalAlignment.CENTER) - gap(10) - id("dock") - } - .also { fl -> - if (!isDefault) { - fl.child(ButtonComponents.remove { backing.remove(id); cf.remove() } - .renderer(ButtonRenderers.STANDARD)) - - fl.child(Components.button(Text.translatable("text.config.data_attributes.data_entry.edit")) { - if (cf.childById(FlowLayout::class.java, "edit-field") == null) { - val field = FieldComponents.identifier( - { newId, _ -> - if (backing.containsKey(newId) || !Registries.ATTRIBUTE.containsId(newId)) return@identifier - - backing.remove(id)?.let { backing[newId] = it } - - updateHeader(newId, cf, isFunctionHeaderDefault(newId)) - }, - autocomplete = Registries.ATTRIBUTE.ids - ) - - field.textBox.predicate = { backing[id]?.get(it) == null && Registries.ATTRIBUTE.containsId(it) } - - cf.child(0, field) - } - } - .renderer(ButtonRenderers.STANDARD) - ) - } - - fl.child( - Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { - val map = backing[id] ?: mutableMapOf() - val createdId = Identifier("unknown") - val function = AttributeFunction() - map[createdId] = function - backing[createdId] = map - createEntry(createdId, function, createdId, false, cf) - } - .renderer(ButtonRenderers.STANDARD) - ) - } - ) - - if (id.toString() == "minecraft:unknown" && children.size > 1) child(1, cf) - else child(cf) - } - } - - private fun createEntry(incomingIdentifier: Identifier, function: AttributeFunction, parentId: Identifier, isDefault: Boolean, parent: CollapsibleFoldableContainer): CollapsibleContainer { - var id = incomingIdentifier - // find if it exists already to ignore the default - val located = parent.childById(CollapsibleContainer::class.java, "${id}#child-fn") - if (located != null) return located - - val container = Containers.collapsible(Sizing.content(), Sizing.content(), registryEntryToText(id, Registries.ATTRIBUTE, { it.translationKey }, isDefault), DataAttributesClient.UI_STATE.collapsible.functionChildren[parentId.toString()]?.get(id.toString()) == true).apply { - gap(4) - id("${id}#child-fn") - onToggled().subscribe { DataAttributesClient.UI_STATE.collapsible.functionChildren.computeIfAbsent(parentId.toString()) { mutableMapOf() }[id.toString()] = true } - - val attribute = Registries.ATTRIBUTE[id] - if (attribute !is EntityAttribute) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes.data_entry.invalid")) - } else if (isDefault) { - titleLayout().tooltip(Text.translatable("text.config.data_attributes_data_entry.default")) - } - - child(Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(15)) - .apply { - verticalAlignment(VerticalAlignment.BOTTOM) - gap(10) - } - .also { fl -> - fl.child( - ConfigToggleButton() - .enabled(function.enabled) - .onPress { updateChild(id, parentId, function.copy(enabled = !function.enabled), this) } - .renderer(ButtonRenderers.STANDARD) - ) - - if (!isDefault) { - fl.child( - ButtonComponents.remove { - backing[parentId]?.remove(id) - remove() - } - .renderer(ButtonRenderers.STANDARD) - ) - fl.child(Components.button(Text.translatable("text.config.data_attributes.data_entry.edit")) { - if (fl.childById(FlowLayout::class.java, "edit-field") == null) { - val field = FieldComponents.identifier( - { newId, _ -> - val entry = backing[parentId] ?: return@identifier - if (!Registries.ATTRIBUTE.containsId(newId) || entry[newId] != null) return@identifier - - entry[newId] = entry.remove(id) ?: return@identifier - backing[parentId] = entry - - id = newId - - updateHeader(id, this, isFunctionChildDefault(parentId, newId)) - }, - autocomplete = Registries.ATTRIBUTE.ids - ) - - field.textBox.predicate = { backing[parentId]?.get(it) == null && Registries.ATTRIBUTE.containsId(it) } - - child(0, field) - } - } - .renderer(ButtonRenderers.STANDARD) - ) - } - } - ) - child(textBoxComponent( - Text.translatable("text.config.data_attributes.data_entry.functions.value"), - function.value, - Validators::isNumeric, - onChange = { - it.toDoubleOrNull()?.let { z -> updateChild(id, parentId, function.copy(value = z), this) } - } - ).also { - if (attribute is ClampedEntityAttribute) { - it.tooltip(Text.translatable("text.config.data_attributes.data_entry.function_child", id, attribute.minValue, attribute.maxValue)) - } - }) - - child( - Containers.horizontalFlow(Sizing.fill(100), Sizing.fixed(20)).apply { - verticalAlignment(VerticalAlignment.CENTER) - - child(Components.label(Text.translatable("text.config.data_attributes.data_entry.functions.behavior")).sizing(Sizing.content(), Sizing.fixed(20))) - child( - Components.button(Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}")) { - function.behavior = StackingBehavior.entries[function.behavior.ordinal xor 1] - - it.message = Text.translatable("text.config.data_attributes.enum.functionBehavior.${function.behavior.name.lowercase()}") - - backing[parentId]?.set(id, function.copy(behavior = function.behavior)) - } - .renderer(ButtonRenderers.STANDARD) - .positioning(Positioning.relative(100, 0)).horizontalSizing(Sizing.fixed(65)) - ) - } - ) - - child(SearchAnchorComponent(titleLayout(), Option.Key.ROOT, { id.toString() }, { Text.translatable(id.toTranslationKey()).toString() })) - } - - if (id.toString() == "minecraft:unknown" && parent.children().size > 1) parent.child(1, container) - else parent.child(container) - - entryComponents[id] = container - - // force a rearrangement to bring the dock up top~ - parent.childById(FlowLayout::class.java, "dock")?.let { - parent.removeChild(it) - parent.child(0, it) - } - - return container - } - - private fun createFunctionEntries(functions: Map, parentId: Identifier, parent: CollapsibleFoldableContainer) { - functions.forEach { (id, function) -> - val isDefault = backing[parentId]?.get(id) == null - createEntry(id, function, parentId, isDefault, parent) - } - } + val backing = option.value().data init { child( Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { - backing[Identifier("unknown")] = mutableMapOf() - val component = getOrCreateEntryContainer(Identifier("unknown"), false) - component.remove() - child(1, component) + val id = Identifier("unknown") + val entry = mutableMapOf() + backing[id] = entry + child(1, AttributeFunctionHeaderComponent(id, entry,this)) } .renderer(ButtonRenderers.STANDARD) .horizontalSizing(Sizing.content()) .verticalSizing(Sizing.fixed(20)) ) - for ((id, functions) in backing) { - createFunctionEntries(functions, id, getOrCreateEntryContainer(id, !backing.containsKey(id))) + for ((id, entry) in backing) { + child(AttributeFunctionHeaderComponent(id, entry, this).id(id.toString())) } - - for ((id, functions) in DataAttributesAPI.serverManager.defaults.functions.entries) { - createFunctionEntries(functions, id, getOrCreateEntryContainer(id, !backing.containsKey(id))) + for ((id, entry) in DataAttributesAPI.serverManager.defaults.functions.entries) { + val component = childById(AttributeFunctionHeaderComponent::class.java, id.toString()) + if (component != null) { + component.addFunctions(entry) + } + else { + child(AttributeFunctionHeaderComponent(id, entry, this).id(id.toString())) + } } } diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProviderV2.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProviderV2.kt deleted file mode 100644 index 09c100b..0000000 --- a/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/AttributeFunctionProviderV2.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.bibireden.data_attributes.ui.config.providers - -import com.bibireden.data_attributes.api.DataAttributesAPI -import com.bibireden.data_attributes.config.functions.AttributeFunctionConfig -import com.bibireden.data_attributes.ui.components.config.function.AttributeFunctionComponent -import com.bibireden.data_attributes.ui.components.config.function.AttributeFunctionHeaderComponent -import com.bibireden.data_attributes.ui.renderers.ButtonRenderers -import io.wispforest.owo.config.Option -import io.wispforest.owo.config.ui.component.OptionValueProvider -import io.wispforest.owo.ui.component.Components -import io.wispforest.owo.ui.container.FlowLayout -import io.wispforest.owo.ui.core.Sizing -import net.minecraft.text.Text -import net.minecraft.util.Identifier - -class AttributeFunctionProviderV2(val option: Option) : FlowLayout(Sizing.fill(100), Sizing.content(), Algorithm.VERTICAL), OptionValueProvider { - val backing = option.value().data - - init { - child( - Components.button(Text.translatable("text.config.data_attributes.buttons.add")) { - val id = Identifier("unknown") - backing[id] = mutableMapOf() - child(1, AttributeFunctionHeaderComponent(id, this)) - } - .renderer(ButtonRenderers.STANDARD) - .horizontalSizing(Sizing.content()) - .verticalSizing(Sizing.fixed(20)) - ) - - backing.keys.forEach { id -> child(AttributeFunctionHeaderComponent(id, this)) } - DataAttributesAPI.serverManager.defaults.functions.entries.keys.forEach { id -> child(AttributeFunctionHeaderComponent(id, this)) } - } - - override fun isValid() = !this.option.detached() - override fun parsedValue() = AttributeFunctionConfig(backing) -} \ No newline at end of file diff --git a/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/EntityTypesProviderV2.kt b/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/EntityTypesProviderV2.kt new file mode 100644 index 0000000..961943c --- /dev/null +++ b/src/main/kotlin/com/bibireden/data_attributes/ui/config/providers/EntityTypesProviderV2.kt @@ -0,0 +1,33 @@ +package com.bibireden.data_attributes.ui.config.providers + +import com.bibireden.data_attributes.api.DataAttributesAPI +import com.bibireden.data_attributes.config.entities.EntityTypeData +import com.bibireden.data_attributes.ui.components.config.entities.EntityTypesComponent +import com.bibireden.data_attributes.ui.components.config.entities.EntityTypesHeaderComponent +import io.wispforest.owo.config.Option +import io.wispforest.owo.config.ui.component.OptionValueProvider +import io.wispforest.owo.ui.container.FlowLayout +import io.wispforest.owo.ui.core.Sizing +import net.minecraft.util.Identifier + +class EntityTypesProviderV2(val option: Option>) : FlowLayout(Sizing.fill(100), Sizing.content(), Algorithm.VERTICAL), OptionValueProvider { + val backing = option.value().toMutableMap() + + init { + for ((id, entry) in backing) { + child(EntityTypesHeaderComponent(id, entry.data.toMutableMap(), this).id(id.toString())) + } + for ((id, entry) in DataAttributesAPI.serverManager.defaults.types.entries) { + val component = childById(EntityTypesHeaderComponent::class.java, id.toString()) + if (component != null) { + component.addEntityTypes(entry) + } + else { + child(EntityTypesHeaderComponent(id, entry, this).id(id.toString())) + } + } + } + + override fun isValid() = !this.option.detached() + override fun parsedValue() = backing +} \ No newline at end of file