mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-01 02:14:51 +07:00
ExpanderTab revisited - move and apply to city screen (#4401)
This commit is contained in:
parent
9e37cc8f16
commit
1d080ac54d
@ -18,6 +18,7 @@ import com.unciv.models.stats.Stat
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.utils.*
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.math.max
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
|
||||
class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBaseScreen.skin) {
|
||||
@ -53,6 +54,7 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
|
||||
add(showCityInfoTableButton).left().padLeft(pad).padBottom(pad).row()
|
||||
add(constructionsQueueScrollPane).left().padBottom(pad).row()
|
||||
add().expandY().row() // allow the bottom() below to open up the unneeded space
|
||||
add(buttons).left().bottom().padBottom(pad).row()
|
||||
add(availableConstructionsScrollPane).left().bottom().row()
|
||||
}
|
||||
@ -81,7 +83,7 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
val queue = cityConstructions.constructionQueue
|
||||
|
||||
constructionsQueueTable.defaults().pad(0f)
|
||||
constructionsQueueTable.add(getHeader("Current construction".tr())).fillX()
|
||||
constructionsQueueTable.add(getHeader("Current construction")).fillX()
|
||||
|
||||
constructionsQueueTable.addSeparator()
|
||||
|
||||
@ -92,21 +94,20 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
constructionsQueueTable.add("Pick a construction".toLabel()).pad(2f).row()
|
||||
|
||||
constructionsQueueTable.addSeparator()
|
||||
constructionsQueueTable.add(getHeader("Construction queue".tr())).fillX()
|
||||
constructionsQueueTable.addSeparator()
|
||||
|
||||
|
||||
if (queue.isNotEmpty()) {
|
||||
if (queue.size > 1) {
|
||||
constructionsQueueTable.add(getHeader("Construction queue")).fillX()
|
||||
constructionsQueueTable.addSeparator()
|
||||
queue.forEachIndexed { i, constructionName ->
|
||||
if (i != 0) // This is already displayed as "Current construction"
|
||||
// The first entry is already displayed as "Current construction"
|
||||
if (i != 0) {
|
||||
constructionsQueueTable.add(getQueueEntry(i, constructionName))
|
||||
.expandX().fillX().row()
|
||||
if (i != queue.size - 1)
|
||||
constructionsQueueTable.addSeparator()
|
||||
.expandX().fillX().row()
|
||||
if (i != queue.size - 1)
|
||||
constructionsQueueTable.addSeparator()
|
||||
}
|
||||
}
|
||||
} else
|
||||
constructionsQueueTable.add("Queue empty".toLabel()).pad(2f).row()
|
||||
|
||||
}
|
||||
|
||||
constructionsQueueScrollPane.layout()
|
||||
constructionsQueueScrollPane.scrollY = queueScrollY
|
||||
@ -171,6 +172,7 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
val constructionButtonDTOList = getConstructionButtonDTOs()
|
||||
Gdx.app.postRunnable {
|
||||
availableConstructionsTable.clear()
|
||||
var maxWidth = constructionsQueueTable.width
|
||||
for (dto in constructionButtonDTOList) {
|
||||
val constructionButton = getConstructionButton(dto)
|
||||
when (dto.construction) {
|
||||
@ -184,14 +186,15 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
}
|
||||
is PerpetualConstruction -> specialConstructions.add(constructionButton)
|
||||
}
|
||||
if (constructionButton.needsLayout()) constructionButton.pack()
|
||||
maxWidth = max(maxWidth, constructionButton.width)
|
||||
}
|
||||
|
||||
availableConstructionsTable.addCategory("Units", units, constructionsQueueTable.width)
|
||||
availableConstructionsTable.addCategory("Wonders", buildableWonders, constructionsQueueTable.width)
|
||||
availableConstructionsTable.addCategory("National Wonders", buildableNationalWonders, constructionsQueueTable.width)
|
||||
availableConstructionsTable.addCategory("Buildings", buildableBuildings, constructionsQueueTable.width)
|
||||
availableConstructionsTable.addCategory("Other", specialConstructions, constructionsQueueTable.width)
|
||||
|
||||
availableConstructionsTable.addCategory("Units", units, maxWidth)
|
||||
availableConstructionsTable.addCategory("Wonders", buildableWonders, maxWidth)
|
||||
availableConstructionsTable.addCategory("National Wonders", buildableNationalWonders, maxWidth)
|
||||
availableConstructionsTable.addCategory("Buildings", buildableBuildings, maxWidth)
|
||||
availableConstructionsTable.addCategory("Other", specialConstructions, maxWidth)
|
||||
|
||||
availableConstructionsScrollPane.layout()
|
||||
availableConstructionsScrollPane.scrollY = constrScrollY
|
||||
@ -489,13 +492,13 @@ class CityConstructionsTable(val cityScreen: CityScreen) : Table(CameraStageBase
|
||||
private fun Table.addCategory(title: String, list: ArrayList<Table>, prefWidth: Float) {
|
||||
if (list.isEmpty()) return
|
||||
|
||||
addSeparator()
|
||||
add(getHeader(title)).prefWidth(prefWidth).fill().row()
|
||||
addSeparator()
|
||||
|
||||
for (table in list) {
|
||||
add(table).fill().left().row()
|
||||
if (table != list.last()) addSeparator()
|
||||
if (rows > 0) addSeparator()
|
||||
val expander = ExpanderTab(title, defaultPad = 0f, expanderWidth = prefWidth) {
|
||||
for (table in list) {
|
||||
it.addSeparator(colSpan = 1)
|
||||
it.add(table).left().row()
|
||||
}
|
||||
}
|
||||
add(expander).prefWidth(prefWidth).growX().row()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,74 +54,49 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
}
|
||||
|
||||
private fun Table.addCategory(str: String, showHideTable: Table) {
|
||||
val width = cityScreen.stage.width / 4
|
||||
val showHideTableWrapper = Table()
|
||||
.add(showHideTable)
|
||||
.minWidth(width)
|
||||
.table
|
||||
|
||||
val titleTable = Table()
|
||||
.background(ImageGetter.getBackground(ImageGetter.getBlue()))
|
||||
.pad(4f)
|
||||
.addCell(str.toLabel(fontSize = 24))
|
||||
.onClick {
|
||||
if (showHideTableWrapper.hasChildren()) {
|
||||
showHideTableWrapper.clear()
|
||||
} else {
|
||||
showHideTableWrapper.add(showHideTable).minWidth(width)
|
||||
}
|
||||
}
|
||||
val categoryWidth = cityScreen.stage.width / 4
|
||||
val expander = ExpanderTab(str) {
|
||||
it.add(showHideTable).minWidth(categoryWidth)
|
||||
}
|
||||
addSeparator()
|
||||
|
||||
add(titleTable).minWidth(width).row()
|
||||
add(showHideTableWrapper).row()
|
||||
add(expander).minWidth(categoryWidth).expandX().fillX().row()
|
||||
}
|
||||
|
||||
private fun addBuildingInfo(building: Building, wondersTable: Table) {
|
||||
val wonderNameAndIconTable = Table()
|
||||
wonderNameAndIconTable.touchable = Touchable.enabled
|
||||
wonderNameAndIconTable.add(ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f))
|
||||
wonderNameAndIconTable.add(building.name.toLabel()).pad(5f)
|
||||
wondersTable.add(wonderNameAndIconTable).pad(5f).fillX().row()
|
||||
private fun addBuildingInfo(building: Building, destinationTable: Table) {
|
||||
val icon = ImageGetter.getConstructionImage(building.name).surroundWithCircle(30f)
|
||||
val buildingNameAndIconTable = ExpanderTab(building.name, 18, icon, false, 5f) {
|
||||
//todo: getDescription signature changes with civilopedia phase 5
|
||||
val detailsString = building.getDescription(true,
|
||||
cityScreen.city, cityScreen.city.civInfo.gameInfo.ruleSet)
|
||||
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
|
||||
if (building.isSellable()) {
|
||||
val sellAmount = cityScreen.city.getGoldForSellingBuilding(building.name)
|
||||
val sellBuildingButton = "Sell for [$sellAmount] gold".toTextButton()
|
||||
it.add(sellBuildingButton).pad(5f).row()
|
||||
|
||||
val wonderDetailsTable = Table()
|
||||
wondersTable.add(wonderDetailsTable).pad(5f).align(Align.left).row()
|
||||
sellBuildingButton.onClick {
|
||||
sellBuildingButton.disable()
|
||||
cityScreen.closeAllPopups()
|
||||
|
||||
wonderNameAndIconTable.onClick {
|
||||
if (wonderDetailsTable.hasChildren())
|
||||
wonderDetailsTable.clear()
|
||||
else {
|
||||
val detailsString = building.getDescription(true,
|
||||
cityScreen.city, cityScreen.city.civInfo.gameInfo.ruleSet)
|
||||
wonderDetailsTable.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
|
||||
if (building.isSellable()) {
|
||||
val sellAmount = cityScreen.city.getGoldForSellingBuilding(building.name)
|
||||
val sellBuildingButton = "Sell for [$sellAmount] gold".toTextButton()
|
||||
wonderDetailsTable.add(sellBuildingButton).pad(5f).row()
|
||||
|
||||
sellBuildingButton.onClick {
|
||||
sellBuildingButton.disable()
|
||||
cityScreen.closeAllPopups()
|
||||
|
||||
YesNoPopup("Are you sure you want to sell this [${building.name}]?".tr(),
|
||||
{
|
||||
cityScreen.city.sellBuilding(building.name)
|
||||
cityScreen.city.cityStats.update()
|
||||
cityScreen.update()
|
||||
}, cityScreen,
|
||||
{
|
||||
cityScreen.update()
|
||||
}).open()
|
||||
}
|
||||
if (cityScreen.city.hasSoldBuildingThisTurn && !cityScreen.city.civInfo.gameInfo.gameParameters.godMode
|
||||
|| cityScreen.city.isPuppet
|
||||
|| !UncivGame.Current.worldScreen.isPlayersTurn || !cityScreen.canChangeState)
|
||||
sellBuildingButton.disable()
|
||||
YesNoPopup("Are you sure you want to sell this [${building.name}]?".tr(),
|
||||
{
|
||||
cityScreen.city.sellBuilding(building.name)
|
||||
cityScreen.city.cityStats.update()
|
||||
cityScreen.update()
|
||||
}, cityScreen,
|
||||
{
|
||||
cityScreen.update()
|
||||
}).open()
|
||||
}
|
||||
wonderDetailsTable.addSeparator()
|
||||
if (cityScreen.city.hasSoldBuildingThisTurn && !cityScreen.city.civInfo.gameInfo.gameParameters.godMode
|
||||
|| cityScreen.city.isPuppet
|
||||
|| !UncivGame.Current.worldScreen.isPlayersTurn || !cityScreen.canChangeState)
|
||||
sellBuildingButton.disable()
|
||||
}
|
||||
it.addSeparator()
|
||||
}
|
||||
destinationTable.add(buildingNameAndIconTable).pad(5f).fillX().row()
|
||||
}
|
||||
|
||||
private fun Table.addBuildingsInfo(cityInfo: CityInfo) {
|
||||
@ -153,7 +128,7 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
specialistIcons.row().size(20f).pad(5f)
|
||||
for ((specialistName, amount) in building.newSpecialists()) {
|
||||
val specialist = cityInfo.getRuleset().specialists[specialistName]
|
||||
if (specialist == null) continue // probably a mod that doesn't have the specialist defined yet
|
||||
?: continue // probably a mod that doesn't have the specialist defined yet
|
||||
for (i in 0 until amount)
|
||||
specialistIcons.add(ImageGetter.getSpecialistIcon(specialist.colorObject)).size(20f)
|
||||
}
|
||||
@ -194,11 +169,11 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
val specificStatValue = entry.value
|
||||
sumOfAllBaseValues += specificStatValue
|
||||
statValuesTable.add(entry.key.toLabel())
|
||||
statValuesTable.add(DecimalFormat("0.#").format(specificStatValue).toLabel()).row()
|
||||
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
||||
}
|
||||
statValuesTable.addSeparator()
|
||||
statValuesTable.add("Total".toLabel())
|
||||
statValuesTable.add(DecimalFormat("0.#").format(sumOfAllBaseValues).toLabel()).row()
|
||||
statValuesTable.add(sumOfAllBaseValues.toOneDecimalLabel()).row()
|
||||
|
||||
val relevantBonuses = cityStats.statPercentBonusList.filter { it.value.get(stat) != 0f }
|
||||
if (relevantBonuses.isNotEmpty()) {
|
||||
@ -208,15 +183,11 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
val specificStatValue = entry.value.get(stat)
|
||||
sumOfBonuses += specificStatValue
|
||||
statValuesTable.add(entry.key.toLabel())
|
||||
val decimal = DecimalFormat("0.#").format(specificStatValue)
|
||||
if (specificStatValue > 0) statValuesTable.add("+$decimal%".toLabel()).row()
|
||||
else statValuesTable.add("$decimal%".toLabel()).row() // negative bonus
|
||||
statValuesTable.add(specificStatValue.toPercentLabel()).row() // negative bonus
|
||||
}
|
||||
statValuesTable.addSeparator()
|
||||
statValuesTable.add("Total".toLabel())
|
||||
val decimal = DecimalFormat("0.#").format(sumOfBonuses)
|
||||
if (sumOfBonuses > 0) statValuesTable.add("+$decimal%".toLabel()).row()
|
||||
else statValuesTable.add("$decimal%".toLabel()).row() // negative bonus
|
||||
statValuesTable.add(sumOfBonuses.toPercentLabel()).row() // negative bonus
|
||||
}
|
||||
|
||||
if (stat != Stat.Happiness) {
|
||||
@ -227,11 +198,11 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
finalTotal += specificStatValue
|
||||
if (specificStatValue == 0f) continue
|
||||
statValuesTable.add(entry.key.toLabel())
|
||||
statValuesTable.add(DecimalFormat("0.#").format(specificStatValue).toLabel()).row()
|
||||
statValuesTable.add(specificStatValue.toOneDecimalLabel()).row()
|
||||
}
|
||||
statValuesTable.addSeparator()
|
||||
statValuesTable.add("Total".toLabel())
|
||||
statValuesTable.add(DecimalFormat("0.#").format(finalTotal).toLabel()).row()
|
||||
statValuesTable.add(finalTotal.toOneDecimalLabel()).row()
|
||||
}
|
||||
|
||||
statValuesTable.padBottom(4f)
|
||||
@ -252,13 +223,18 @@ class CityInfoTable(private val cityScreen: CityScreen) : Table(CameraStageBaseS
|
||||
val value = entry.value.toHashMap()[stat]!!
|
||||
if (value == 0f) continue
|
||||
greatPersonTable.add(entry.key.toLabel()).padRight(10f)
|
||||
greatPersonTable.add(DecimalFormat("0.#").format(value).toLabel()).row()
|
||||
greatPersonTable.add(value.toOneDecimalLabel()).row()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() =
|
||||
DecimalFormat("0.#").format(this).toLabel()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,7 @@ import com.unciv.logic.trade.TradeOffersList
|
||||
import com.unciv.logic.trade.TradeType
|
||||
import com.unciv.logic.trade.TradeType.*
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||
import com.unciv.ui.utils.disable
|
||||
import com.unciv.ui.utils.onClick
|
||||
import com.unciv.ui.utils.toTextButton
|
||||
import com.unciv.ui.utils.*
|
||||
import kotlin.math.min
|
||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||
|
||||
|
@ -1,32 +1,34 @@
|
||||
package com.unciv.ui.trade
|
||||
package com.unciv.ui.utils
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.math.Interpolation
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||
import com.unciv.ui.utils.ImageGetter
|
||||
import com.unciv.ui.utils.onClick
|
||||
import com.unciv.ui.utils.toLabel
|
||||
|
||||
/**
|
||||
* A widget with a header that when clicked shows/hides a sub-Table.
|
||||
*
|
||||
* @param title The header text, automatically translated.
|
||||
* @param fontSize Size applied to header text (only)
|
||||
* @param icon Optional icon - please use [Image][com.badlogic.gdx.scenes.scene2d.ui.Image] or [IconCircleGroup]
|
||||
* @param defaultPad Padding between content and wrapper. Header padding is currently not modifiable.
|
||||
* @param expanderWidth If set initializes header width
|
||||
* @param initContent Optional lambda with [innerTable] as parameter, to help initialize content.
|
||||
*/
|
||||
class ExpanderTab(
|
||||
title: String,
|
||||
fontSize: Int = 24,
|
||||
icon: Actor? = null,
|
||||
startsOutOpened: Boolean = true,
|
||||
defaultPad: Float = 10f,
|
||||
expanderWidth: Float = 0f,
|
||||
initContent: ((Table) -> Unit)? = null
|
||||
): Table(CameraStageBaseScreen.skin) {
|
||||
private companion object {
|
||||
const val fontSize = 24
|
||||
const val arrowSize = 18f
|
||||
const val arrowImage = "OtherIcons/BackArrow"
|
||||
val arrowColor = Color(1f,0.96f,0.75f,1f)
|
||||
@ -56,14 +58,25 @@ class ExpanderTab(
|
||||
headerIcon.rotation = 180f
|
||||
headerIcon.color = arrowColor
|
||||
header.background(ImageGetter.getBackground(ImageGetter.getBlue()))
|
||||
if (icon != null) header.add(icon)
|
||||
header.add(headerLabel)
|
||||
header.add(headerIcon).size(arrowSize).align(Align.center)
|
||||
header.touchable= Touchable.enabled
|
||||
header.onClick { toggle() }
|
||||
add(header).expandX().fill().row()
|
||||
contentWrapper.defaults().pad(defaultPad)
|
||||
add(contentWrapper).expandX()
|
||||
if (expanderWidth != 0f)
|
||||
defaults().minWidth(expanderWidth)
|
||||
defaults().growX()
|
||||
contentWrapper.defaults().growX().pad(defaultPad)
|
||||
innerTable.defaults().growX()
|
||||
add(header).fillY().row()
|
||||
add(contentWrapper)
|
||||
contentWrapper.add(innerTable) // update will revert this
|
||||
initContent?.invoke(innerTable)
|
||||
if (expanderWidth == 0f) {
|
||||
// Measure content width incl. pad, set header to same width
|
||||
if (innerTable.needsLayout()) contentWrapper.pack()
|
||||
getCell(header).minWidth(contentWrapper.width)
|
||||
}
|
||||
update(noAnimation = true)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user