diff --git a/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt b/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt index 661b579fc0..7ac47d54e4 100644 --- a/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt @@ -1,7 +1,9 @@ package com.unciv.ui.cityscreen import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.Touchable +import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.Constants @@ -24,6 +26,10 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) private val scrollPane: ScrollPane private val innerTable = Table(skin) + private val allExpanders = mutableListOf() + private val hideShowAllCell: Cell + private var hideShowAllShouldClose = false + init { align(Align.topLeft) @@ -37,13 +43,17 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) scrollPane = ScrollPane(innerTable.addBorder(2f, Color.WHITE)) scrollPane.setOverscroll(false, false) - add(showConstructionsTableButton).left().padLeft(pad).padBottom(pad).row() - add(scrollPane).left().row() + val hideShowAllButton = Group() + add(showConstructionsTableButton).left().padLeft(pad).padBottom(pad) + hideShowAllCell = add(hideShowAllButton).size(30f) // size as the cell won't be resized when the actor is replaced + hideShowAllCell.left().padLeft(pad).padBottom(pad).expandX().row() + add(scrollPane).colspan(2).left().row() } internal fun update() { val cityInfo = cityScreen.city + allExpanders.clear() innerTable.clear() innerTable.apply { @@ -52,24 +62,56 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) addGreatPersonPointInfo(cityInfo) } + updateHideShowAllButton() + getCell(scrollPane).maxHeight(stage.height - showConstructionsTableButton.height - pad - 10f) + onContentResize() + } + + private fun updateHideShowAllButton() { + val anyExpanderOpen = allExpanders.map { it.isOpen }.maxOrNull() ?: false + if (anyExpanderOpen == hideShowAllShouldClose) return + hideShowAllShouldClose = anyExpanderOpen + val hideShowAllButton = getToggleButton(hideShowAllShouldClose) + hideShowAllButton.touchable = Touchable.enabled + hideShowAllButton.onClick { + for (expander in allExpanders) { + if (expander.isOpen == hideShowAllShouldClose) expander.toggle() + } + updateHideShowAllButton() + } + hideShowAllCell.setActor(hideShowAllButton) + } + + private fun onContentResize() { pack() + setPosition(CityScreen.posFromEdge, stage.height - CityScreen.posFromEdge, Align.topLeft) } private fun Table.addCategory(category: String, showHideTable: Table) { val categoryWidth = cityScreen.stage.width / 4 - val expander = ExpanderTab(category, persistenceID = "CityInfo") { + val expander = ExpanderTab(category, persistenceID = "CityInfo.$category" + , onChange = { + onContentResize() + updateHideShowAllButton() + } + ) { it.add(showHideTable).minWidth(categoryWidth) } addSeparator() add(expander).minWidth(categoryWidth).expandX().fillX().row() + allExpanders += expander } private fun addBuildingInfo(building: Building, destinationTable: Table) { val icon = ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f) val isFree = building.name in cityScreen.city.civInfo.civConstructions.getFreeBuildings(cityScreen.city.id) val displayName = if (isFree) "{${building.name}} ({Free})" else building.name - val buildingNameAndIconTable = ExpanderTab(displayName, Constants.defaultFontSize, icon, false, 5f) { + val buildingNameAndIconTable = ExpanderTab( + displayName, Constants.defaultFontSize, icon, + startsOutOpened = false, defaultPad = 5f, + onChange = { onContentResize() } + ) { val detailsString = building.getDescription(cityScreen.city, false) it.add(detailsString.toLabel().apply { wrap = true }) .width(cityScreen.stage.width / 4 - 2 * pad).row() // when you set wrap, then you need to manually set the size of the label @@ -146,8 +188,13 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) } } - private fun addStatsToHashmap(statTreeNode: StatTreeNode, hashMap: HashMap, stat:Stat, - showDetails:Boolean, indentation:Int=0) { + private fun addStatsToHashmap( + statTreeNode: StatTreeNode, + hashMap: HashMap, + stat: Stat, + showDetails: Boolean, + indentation: Int = 0 + ) { for ((name, child) in statTreeNode.children) { val statAmount = child.totalStats[stat] if (statAmount == 0f) continue @@ -185,6 +232,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) statValuesTable, !showDetails ) + onContentResize() } val relevantBaseStats = LinkedHashMap() @@ -245,10 +293,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) statValuesTable.pack() if (stat != Stat.Happiness) { - val toggleButtonChar = if (showDetails) "-" else "+" - val toggleButton = toggleButtonChar.toLabel().apply { setAlignment(Align.center) } - .surroundWithCircle(25f, color = ImageGetter.getBlue()) - .surroundWithCircle(27f, false) + val toggleButton = getToggleButton(showDetails) statValuesTable.addActor(toggleButton) toggleButton.setPosition(0f, statValuesTable.height, Align.topLeft) } @@ -256,6 +301,14 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) statValuesTable.padBottom(4f) } + private fun getToggleButton(showDetails: Boolean): IconCircleGroup { + val label = (if (showDetails) "-" else "+").toLabel() + label.setAlignment(Align.center) + return label + .surroundWithCircle(25f, color = ImageGetter.getBlue()) + .surroundWithCircle(27f, false) + } + private fun Table.addGreatPersonPointInfo(cityInfo: CityInfo) { val greatPersonPoints = cityInfo.getGreatPersonPointsForNextTurn() val allGreatPersonNames = greatPersonPoints.asSequence().flatMap { it.value.keys }.distinct() @@ -274,7 +327,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(BaseScreen.skin) companion object { private const val FONT_SIZE_STAT_INFO_HEADER = 22 - + private fun Float.toPercentLabel() = "${if (this>0f) "+" else ""}${DecimalFormat("0.#").format(this)}%".toLabel() private fun Float.toOneDecimalLabel() = diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index 4618be8173..f49ca1e9e5 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -113,7 +113,7 @@ class CityScreen( constructionsTable.isVisible = false cityInfoTable.isVisible = true cityInfoTable.update() - cityInfoTable.setPosition(posFromEdge, stage.height - posFromEdge, Align.topLeft) + // CityInfoTable sets its relative position itself } // Bottom right: Tile or selected construction info