From 7475c4e48a4c6389461f4724ef145b0fd6b4d026 Mon Sep 17 00:00:00 2001 From: yairm210 Date: Thu, 11 Jul 2024 22:49:14 +0300 Subject: [PATCH] Added unique builder screen, accessible from mod checker --- .../unciv/ui/popups/options/AdvancedTab.kt | 12 +- .../unciv/ui/popups/options/ModCheckTab.kt | 14 +- .../unciv/ui/screens/UniqueBuilderScreen.kt | 126 ++++++++++++++++++ 3 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 core/src/com/unciv/ui/screens/UniqueBuilderScreen.kt diff --git a/core/src/com/unciv/ui/popups/options/AdvancedTab.kt b/core/src/com/unciv/ui/popups/options/AdvancedTab.kt index c0c4bd7f04..b61873c810 100644 --- a/core/src/com/unciv/ui/popups/options/AdvancedTab.kt +++ b/core/src/com/unciv/ui/popups/options/AdvancedTab.kt @@ -22,13 +22,7 @@ import com.unciv.models.metadata.ModCategories import com.unciv.models.translations.TranslationFileWriter import com.unciv.models.translations.tr import com.unciv.ui.components.UncivTooltip.Companion.addTooltip -import com.unciv.ui.components.extensions.addSeparator -import com.unciv.ui.components.extensions.disable -import com.unciv.ui.components.extensions.setFontColor -import com.unciv.ui.components.extensions.toCheckBox -import com.unciv.ui.components.extensions.toLabel -import com.unciv.ui.components.extensions.toTextButton -import com.unciv.ui.components.extensions.withoutItem +import com.unciv.ui.components.extensions.* import com.unciv.ui.components.fonts.FontFamilyData import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.keyShortcuts @@ -45,7 +39,7 @@ import com.unciv.utils.launchOnGLThread import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.UUID +import java.util.* import java.util.zip.Deflater class AdvancedTab( @@ -106,7 +100,7 @@ class AdvancedTab( add("Screen orientation".toLabel()).left().fillX() val selectBox = SelectBox(skin) - selectBox.items = Array(ScreenOrientation.values()) + selectBox.items = Array(ScreenOrientation.entries.toTypedArray()) selectBox.selected = settings.displayOrientation selectBox.onChange { val orientation = selectBox.selected diff --git a/core/src/com/unciv/ui/popups/options/ModCheckTab.kt b/core/src/com/unciv/ui/popups/options/ModCheckTab.kt index ce5493bd25..c558b68ab3 100644 --- a/core/src/com/unciv/ui/popups/options/ModCheckTab.kt +++ b/core/src/com/unciv/ui/popups/options/ModCheckTab.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align +import com.unciv.UncivGame import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.unique.Unique @@ -21,6 +22,7 @@ import com.unciv.ui.components.widgets.TabbedPager import com.unciv.ui.components.widgets.TranslatedSelectBox import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.ToastPopup +import com.unciv.ui.screens.UniqueBuilderScreen import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.utils.Concurrency import com.unciv.utils.Log @@ -126,17 +128,25 @@ class ModCheckTab( val expanderTab = ExpanderTab(mod.name, icon = icon, startsOutOpened = mod.name in openedExpanderTitles) { it.defaults().align(Align.left) + it.defaults().pad(10f) + + val openUniqueBuilderButton = "Open unique builder".toTextButton() + val ruleset = if (base == MOD_CHECK_WITHOUT_BASE) mod + else RulesetCache.getComplexRuleset(linkedSetOf(mod.name), base) + openUniqueBuilderButton.onClick { UncivGame.Current.pushScreen(UniqueBuilderScreen(ruleset)) } + it.add(openUniqueBuilderButton).row() + if (!noProblem && mod.folderLocation != null) { val replaceableUniques = getDeprecatedReplaceableUniques(mod) if (replaceableUniques.isNotEmpty()) it.add("Autoupdate mod uniques".toTextButton() - .onClick { autoUpdateUniques(screen, mod, replaceableUniques) }).pad(10f).row() + .onClick { autoUpdateUniques(screen, mod, replaceableUniques) }).row() } for (line in modLinks) { val label = Label(line.text, BaseScreen.skin) .apply { color = line.errorSeverityToReport.color } label.wrap = true - it.add(label).width(stage.width / 2).pad(10f).row() + it.add(label).width(stage.width / 2).row() } if (!noProblem) it.add("Copy to clipboard".toTextButton().onClick { diff --git a/core/src/com/unciv/ui/screens/UniqueBuilderScreen.kt b/core/src/com/unciv/ui/screens/UniqueBuilderScreen.kt new file mode 100644 index 0000000000..d665111c5e --- /dev/null +++ b/core/src/com/unciv/ui/screens/UniqueBuilderScreen.kt @@ -0,0 +1,126 @@ +package com.unciv.ui.screens + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.scenes.scene2d.ui.TextField +import com.unciv.models.ruleset.Ruleset +import com.unciv.models.ruleset.unique.Unique +import com.unciv.models.ruleset.unique.UniqueTarget +import com.unciv.models.ruleset.unique.UniqueType +import com.unciv.models.ruleset.validation.UniqueValidator +import com.unciv.models.translations.fillPlaceholders +import com.unciv.models.translations.getPlaceholderParameters +import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.input.onChange +import com.unciv.ui.components.widgets.LanguageTable +import com.unciv.ui.components.widgets.LanguageTable.Companion.addLanguageTables +import com.unciv.ui.components.widgets.TranslatedSelectBox +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.popups.options.OptionsPopup +import com.unciv.ui.screens.pickerscreens.PickerScreen + +/** A [PickerScreen] to select a language, used once on the initial run after a fresh install. + * After that, [OptionsPopup] provides the functionality. + * Reusable code is in [LanguageTable] and [addLanguageTables]. + */ +class UniqueBuilderScreen(ruleset: Ruleset) : PickerScreen() { + + private val parameterSelectBoxTable = Table().apply { defaults().pad(5f) } + private val uniqueSelectBoxTable = Table() + + private val uniqueErrorTable = Table().apply { defaults().pad(5f) } + private val uniqueText = TextField("Unique", skin) + + init { + setDefaultCloseAction() + rightSideButton.isVisible = false + topTable.defaults().pad(5f) + val uniqueTargets = UniqueTarget.entries.map { it.name } + + val uniqueTargetSelectBoxTable = Table().apply { defaults().pad(5f) } + val uniqueTargetsSelectBox = TranslatedSelectBox(uniqueTargets, UniqueTarget.Global.name) + uniqueTargetSelectBoxTable.add(uniqueTargetsSelectBox) + + uniqueTargetSelectBoxTable.add(uniqueSelectBoxTable).row() + topTable.add(uniqueTargetSelectBoxTable).row() + + uniqueTargetsSelectBox.onChange { + onUniqueTargetChange(uniqueTargetsSelectBox, ruleset, parameterSelectBoxTable) + } + onUniqueTargetChange(uniqueTargetsSelectBox, ruleset, parameterSelectBoxTable) + + topTable.row() + topTable.add(uniqueText).width(stage.width * 0.9f).row() + topTable.add(parameterSelectBoxTable).row() + + + uniqueText.onChange { + updateUniqueErrors(ruleset) + } + + uniqueErrorTable.defaults().pad(5f) + uniqueErrorTable.background = ImageGetter.getWhiteDotDrawable().tint(Color.DARK_GRAY) + topTable.add(uniqueErrorTable).row() + } + + private fun onUniqueTargetChange( + uniqueTargetsSelectBox: TranslatedSelectBox, + ruleset: Ruleset, + parameterSelectBoxTable: Table, + ) { + val selected = UniqueTarget.entries.first { it.name == uniqueTargetsSelectBox.selected.value } + val uniquesForTarget = UniqueType.entries.filter { it.canAcceptUniqueTarget(selected) } + val uniqueSelectBox = TranslatedSelectBox(uniquesForTarget.map { it.name }, uniquesForTarget.first().name) + uniqueSelectBox.onChange { + onUniqueSelected(uniqueSelectBox, ruleset, parameterSelectBoxTable) + } + onUniqueSelected(uniqueSelectBox, ruleset, parameterSelectBoxTable) + uniqueSelectBoxTable.clear() + uniqueSelectBoxTable.add(uniqueSelectBox) + } + + private fun onUniqueSelected( + uniqueSelectBox: TranslatedSelectBox, + ruleset: Ruleset, + parameterSelectBoxTable: Table + ) { + val uniqueType = UniqueType.entries.first { it.name == uniqueSelectBox.selected.value } + uniqueText.text = uniqueType.text + updateUniqueErrors(ruleset) + + parameterSelectBoxTable.clear() + for ((index, parameter) in uniqueType.text.getPlaceholderParameters().withIndex()) { + val paramTable = Table().apply { defaults().pad(10f) } + paramTable.background = ImageGetter.getWhiteDotDrawable().tint(Color.DARK_GRAY) + paramTable.add("Parameter ${index+1}: $parameter".toLabel()).row() + val knownParamValues = uniqueType.parameterTypeMap[index] + .flatMap { it.getKnownValuesForAutocomplete(ruleset) }.toSet() + + if (knownParamValues.isNotEmpty()) { + val paramSelectBox = TranslatedSelectBox(knownParamValues.toList(), knownParamValues.first()) + paramSelectBox.onChange { + val currentParams = uniqueText.text.getPlaceholderParameters().toMutableList() + currentParams[index] = paramSelectBox.selected.value + val newText = uniqueType.text.fillPlaceholders(*currentParams.toTypedArray()) + uniqueText.text = newText + updateUniqueErrors(ruleset) + } + paramTable.add(paramSelectBox) + } else paramTable.add("No known values".toLabel()) + + parameterSelectBoxTable.add(paramTable).fillY() + } + } + + private fun updateUniqueErrors(ruleset: Ruleset) { + uniqueErrorTable.clear() + uniqueErrorTable.add("Errors:".toLabel()).row() + + val uniqueErrors = UniqueValidator(ruleset) + .checkUnique(Unique(uniqueText.text), true, null, true) + for (error in uniqueErrors) + uniqueErrorTable.add(error.text.toLabel().apply { wrap = true }).width(stage.width/2).row() + if (uniqueErrors.isEmpty()) + uniqueErrorTable.add("No errors!".toLabel()) + } +}