diff --git a/core/src/com/unciv/ui/pickerscreens/DiplomaticVotePickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/DiplomaticVotePickerScreen.kt index b410c7e88d..9b15354aff 100644 --- a/core/src/com/unciv/ui/pickerscreens/DiplomaticVotePickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/DiplomaticVotePickerScreen.kt @@ -19,7 +19,7 @@ class DiplomaticVotePickerScreen(private val votingCiv: CivilizationInfo) : Pick val choosableCivs = votingCiv.gameInfo.civilizations.filter { it.isMajorCiv() && it != votingCiv && !it.isDefeated() } for (civ in choosableCivs) { - val button = getPickerOptionButton(ImageGetter.getNationIndicator(civ.nation, pickerOptionIconSize), civ.civName) + val button = PickerPane.getPickerOptionButton(ImageGetter.getNationIndicator(civ.nation, PickerPane.pickerOptionIconSize), civ.civName) button.pack() button.onClick { chosenCiv = civ.civName diff --git a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt index 5080258fec..109db50b0c 100644 --- a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt @@ -19,7 +19,7 @@ class GreatPersonPickerScreen(val civInfo:CivilizationInfo) : PickerScreen() { val useMayaLongCount = civInfo.greatPeople.mayaLimitedFreeGP > 0 for (unit in greatPersonUnits) { - val button = getPickerOptionButton(ImageGetter.getUnitIcon(unit.name), unit.name) + val button = PickerPane.getPickerOptionButton(ImageGetter.getUnitIcon(unit.name), unit.name) button.pack() button.isEnabled = !useMayaLongCount || unit.name in civInfo.greatPeople.longCountGPPool if (button.isEnabled) button.onClick { diff --git a/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt index 6f757f3862..777db74b75 100644 --- a/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt @@ -131,7 +131,7 @@ class ImprovementPickerScreen( regularImprovements.add(statIcons).align(Align.right) - val improvementButton = getPickerOptionButton(image, labelText) + val improvementButton = PickerPane.getPickerOptionButton(image, labelText) improvementButton.onClick { selectedImprovement = improvement pick(improvement.name.tr()) diff --git a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt index 82d405a019..e52a724e05 100644 --- a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt @@ -375,7 +375,7 @@ class ModManagementScreen( private fun onlineButtonAction(repo: Github.Repo, button: Button) { syncOnlineSelected(repo.name, button) showModDescription(repo.name) - removeRightSideClickListeners() + rightSideButton.clearListeners() rightSideButton.enable() val label = if (installedModInfo[repo.name]?.state?.hasUpdate == true) "Update [${repo.name}]" @@ -519,7 +519,7 @@ class ModManagementScreen( // Don't let the player think he can delete Vanilla and G&K rulesets rightSideButton.isEnabled = mod.ruleset.folderLocation!=null showModDescription(mod.name) - removeRightSideClickListeners() + rightSideButton.clearListeners() rightSideButton.onClick { rightSideButton.isEnabled = false YesNoPopup( diff --git a/core/src/com/unciv/ui/pickerscreens/PickerPane.kt b/core/src/com/unciv/ui/pickerscreens/PickerPane.kt new file mode 100644 index 0000000000..ea17e079ed --- /dev/null +++ b/core/src/com/unciv/ui/pickerscreens/PickerPane.kt @@ -0,0 +1,85 @@ +package com.unciv.ui.pickerscreens + +import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.ui.Button +import com.badlogic.gdx.scenes.scene2d.ui.SplitPane +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup +import com.unciv.Constants +import com.unciv.UncivGame +import com.unciv.ui.images.IconTextButton +import com.unciv.ui.utils.* + +class PickerPane( + disableScroll: Boolean = false, +) : Table() { + /** The close button on the lower left of [bottomTable], see [setDefaultCloseAction] */ + val closeButton = Constants.close.toTextButton() + /** A scrollable wrapped Label you can use to show descriptions in the [bottomTable], starts empty */ + val descriptionLabel = "".toLabel() + /** A wrapper containing [rightSideButton]. You can add buttons, they will be arranged vertically */ + val rightSideGroup = VerticalGroup() + /** A button on the lower right of [bottomTable] you can use for a "OK"-type action, starts disabled */ + val rightSideButton = "".toTextButton() + + private val screenSplit = 0.85f + private val maxBottomTableHeight = 150f // about 7 lines of normal text + + /** + * The table displaying the choices from which to pick (usually). + * Also the element which most of the screen real estate is devoted to displaying. + */ + val topTable = Table() + /** Holds the [Close button][closeButton], a [description label][descriptionLabel] and an [action button][rightSideButton] */ + val bottomTable = Table() + /** A ScrollPane scrolling [topTable], disabled by the disableScroll parameter */ + val scrollPane = AutoScrollPane(topTable) + /** A fixed SplitPane holds [scrollPane] and [bottomTable] */ + val splitPane = SplitPane(scrollPane, bottomTable, true, BaseScreen.skin) + + init { + bottomTable.add(closeButton).pad(10f) + + descriptionLabel.wrap = true + val labelScroll = AutoScrollPane(descriptionLabel, BaseScreen.skin) + bottomTable.add(labelScroll).pad(5f).fill().expand() + + rightSideButton.disable() + rightSideGroup.addActor(rightSideButton) + + bottomTable.add(rightSideGroup).pad(10f).right() + + scrollPane.setScrollingDisabled(disableScroll, disableScroll) // lock scrollPane + if (disableScroll) scrollPane.clearListeners() // remove focus capture of AutoScrollPane too + add(splitPane).expand().fill() + } + + override fun layout() { + super.layout() + bottomTable.height = bottomTable.height.coerceAtMost(maxBottomTableHeight) + splitPane.splitAmount = (scrollPane.height / (scrollPane.height + bottomTable.height)).coerceAtLeast(screenSplit) + } + + /** Enables the [rightSideButton]. See [pick] for a way to set the text. */ + fun setRightSideButtonEnabled(enabled: Boolean) { + rightSideButton.isEnabled = enabled + } + + /** Sets the text of the [rightSideButton] and enables it if it's the player's turn */ + fun pick(rightButtonText: String) { + if (UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable() + rightSideButton.setText(rightButtonText) + } + + companion object { + /** Icon size used in [getPickerOptionButton]. */ + const val pickerOptionIconSize = 30f + /** Return a button for picker screens that display a list of big buttons with icons and labels. */ + fun getPickerOptionButton(icon: Actor, label: String): Button { + return IconTextButton(label, icon).apply { + iconCell!!.size(pickerOptionIconSize).pad(10f) + labelCell.pad(10f) + } + } + } +} diff --git a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt index c7ba66c029..1602ca420a 100644 --- a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt @@ -1,64 +1,38 @@ package com.unciv.ui.pickerscreens -import com.badlogic.gdx.scenes.scene2d.Actor -import com.badlogic.gdx.scenes.scene2d.ui.* -import com.unciv.Constants -import com.unciv.UncivGame -import com.unciv.ui.images.IconTextButton -import com.unciv.ui.utils.* -import com.unciv.ui.utils.AutoScrollPane as ScrollPane +import com.unciv.ui.utils.BaseScreen +import com.unciv.ui.utils.onClick open class PickerScreen(disableScroll: Boolean = false) : BaseScreen() { - /** The close button on the lower left of [bottomTable], see [setDefaultCloseAction] */ - protected var closeButton: TextButton = Constants.close.toTextButton() - /** A scrollable wrapped Label you can use to show descriptions in the [bottomTable], starts empty */ - protected var descriptionLabel: Label - /** A wrapper containing [rightSideButton]. You can add buttons, they will be arranged vertically */ - protected var rightSideGroup = VerticalGroup() - /** A button on the lower right of [bottomTable] you can use for a "OK"-type action, starts disabled */ - protected var rightSideButton: TextButton - private val screenSplit = 0.85f - private val maxBottomTableHeight = 150f // about 7 lines of normal text + val pickerPane = PickerPane(disableScroll = disableScroll) - /** - * The table displaying the choices from which to pick (usually). - * Also the element which most of the screen real estate is devoted to displaying. - */ - protected var topTable: Table - /** Holds the [Close button][closeButton], a [description label][descriptionLabel] and an [action button][rightSideButton] */ - protected var bottomTable:Table = Table() - /** A fixed SplitPane holds [scrollPane] and [bottomTable] */ - protected var splitPane: SplitPane - /** A ScrollPane scrolling [topTable], disabled by the disableScroll parameter */ - protected var scrollPane: ScrollPane + /** @see PickerPane.closeButton */ + val closeButton by pickerPane::closeButton + /** @see PickerPane.descriptionLabel */ + val descriptionLabel by pickerPane::descriptionLabel + /** @see PickerPane.rightSideGroup */ + val rightSideGroup by pickerPane::rightSideGroup + /** @see PickerPane.rightSideButton */ + val rightSideButton by pickerPane::rightSideButton + + /** @see PickerPane.topTable */ + val topTable by pickerPane::topTable + /** @see PickerPane.scrollPane */ + val scrollPane by pickerPane::scrollPane + /** @see PickerPane.splitPane */ + val splitPane by pickerPane::splitPane init { - bottomTable.add(closeButton).pad(10f) + pickerPane.setFillParent(true) + stage.addActor(pickerPane) + ensureLayout() + } - descriptionLabel = "".toLabel() - descriptionLabel.wrap = true - val labelScroll = ScrollPane(descriptionLabel, skin) - bottomTable.add(labelScroll).pad(5f).fill().expand() - - rightSideButton = "".toTextButton() - rightSideButton.disable() - rightSideGroup.addActor(rightSideButton) - - bottomTable.add(rightSideGroup).pad(10f).right() - bottomTable.height = (stage.height * (1 - screenSplit)).coerceAtMost(maxBottomTableHeight) - - topTable = Table() - scrollPane = ScrollPane(topTable) - - scrollPane.setScrollingDisabled(disableScroll, disableScroll) // lock scrollPane - if (disableScroll) scrollPane.clearListeners() // remove focus capture of AutoScrollPane too - scrollPane.setSize(stage.width, stage.height - bottomTable.height) - - splitPane = SplitPane(scrollPane, bottomTable, true, skin) - splitPane.splitAmount = scrollPane.height / stage.height - splitPane.setFillParent(true) - stage.addActor(splitPane) + /** Make sure that anyone relying on sizes of the tables within this class during construction gets correct size readings. + * (see [com.unciv.ui.pickerscreens.PolicyPickerScreen]) */ + private fun ensureLayout() { + pickerPane.validate() } /** @@ -71,35 +45,17 @@ open class PickerScreen(disableScroll: Boolean = false) : BaseScreen() { else game.setWorldScreen() dispose() } - closeButton.onClick(closeAction) + pickerPane.closeButton.onClick(closeAction) onBackButtonClicked(closeAction) } /** Enables the [rightSideButton]. See [pick] for a way to set the text. */ fun setRightSideButtonEnabled(enabled: Boolean) { - rightSideButton.isEnabled = enabled + pickerPane.setRightSideButtonEnabled(enabled) } /** Sets the text of the [rightSideButton] and enables it if it's the player's turn */ - protected fun pick(rightButtonText: String) { - if (UncivGame.Current.worldScreen.isPlayersTurn) rightSideButton.enable() - rightSideButton.setText(rightButtonText) - } - - /** Remove listeners from [rightSideButton] to prepare giving it a new onClick */ - fun removeRightSideClickListeners() { - rightSideButton.clearListeners() - } - - companion object { - /** Icon size used in [getPickerOptionButton]. */ - const val pickerOptionIconSize = 30f - /** Return a button for picker screens that display a list of big buttons with icons and labels. */ - fun getPickerOptionButton(icon: Actor, label: String): Button { - return IconTextButton(label, icon).apply { - iconCell!!.size(pickerOptionIconSize).pad(10f) - labelCell.pad(10f) - } - } + fun pick(rightButtonText: String) { + pickerPane.pick(rightButtonText) } } diff --git a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt index 0b759f415e..24f7b33b19 100644 --- a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt @@ -73,6 +73,7 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo var rowChangeWidth = Float.MAX_VALUE // estimate how many branch boxes fit using average size (including pad) + // TODO If we'd want to use scene2d correctly, this is supposed to happen inside an overridden layout() method val numBranchesX = scrollPane.width / 242f val numBranchesY = scrollPane.height / 305f // plan a nice geometry diff --git a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt index 63c9b549f3..8d55f519ca 100644 --- a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt @@ -77,7 +77,7 @@ class PromotionPickerScreen(val unit: MapUnit) : PickerScreen() { val isPromotionAvailable = promotion in unitAvailablePromotions val unitHasPromotion = unit.promotions.promotions.contains(promotion.name) - val selectPromotionButton = getPickerOptionButton(ImageGetter.getPromotionIcon(promotion.name), promotion.name) + val selectPromotionButton = PickerPane.getPickerOptionButton(ImageGetter.getPromotionIcon(promotion.name), promotion.name) selectPromotionButton.isEnabled = true selectPromotionButton.onClick { val enable = canBePromoted && isPromotionAvailable && !unitHasPromotion && canChangeState