Citizen Management as Expandable Tab (#6969)

* Add ScrollPane to CityStatsTable, limit to half screen height

* Reformat CitizenManagementTable to not have clashing background. Add Expander functionality
Remove button and Table from CityScreen
CitizenManagement added in CityStatsTable
Other cleanup

* Move Reset Citizens to within ExpanderTab

* Minor code format whitespace
This commit is contained in:
itanasi
2022-05-27 03:59:57 -07:00
committed by GitHub
parent 67065d766b
commit 317e8c74df
4 changed files with 72 additions and 81 deletions

View File

@ -3,62 +3,77 @@ package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants
import com.unciv.logic.city.CityFocus
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
class CitizenManagementTable(val cityScreen: CityScreen) : Table() {
private val innerTable = Table()
class CitizenManagementTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
val city = cityScreen.city
init {
innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().darken(0.5f))
add(innerTable).pad(2f).fill()
background = ImageGetter.getBackground(Color.WHITE)
}
fun update(visible: Boolean = false) {
innerTable.clear()
if (!visible) {
isVisible = false
return
}
isVisible = true
fun update() {
clear()
val colorSelected = BaseScreen.skin.get("selection", Color::class.java)
val colorButton = BaseScreen.skin.get("color", Color::class.java)
// effectively a button, but didn't want to rewrite TextButton style
// and much more compact and can control backgrounds easily based on settings
val resetLabel = "Reset Citizens".toLabel()
val resetCell = Table()
resetCell.add(resetLabel).pad(5f)
if (cityScreen.canChangeState) {
resetCell.touchable = Touchable.enabled
resetCell.onClick { city.reassignPopulation(true); cityScreen.update() }
}
resetCell.background = ImageGetter.getBackground(colorButton)
add(resetCell).colspan(2).growX().pad(3f)
row()
val avoidLabel = "Avoid Growth".toLabel()
val avoidCell = Table()
avoidCell.touchable = Touchable.enabled
avoidCell.add(avoidLabel).pad(5f)
if (cityScreen.canChangeState)
if (cityScreen.canChangeState) {
avoidCell.touchable = Touchable.enabled
avoidCell.onClick { city.avoidGrowth = !city.avoidGrowth; city.reassignPopulation(); cityScreen.update() }
}
avoidCell.background = ImageGetter.getBackground(if (city.avoidGrowth) colorSelected else colorButton)
innerTable.add(avoidCell).colspan(2).growX().pad(3f)
innerTable.row()
add(avoidCell).colspan(2).growX().pad(3f)
row()
var newRow = false
for (focus in CityFocus.values()) {
if (!focus.tableEnabled) continue
if (focus == CityFocus.FaithFocus && !city.civInfo.gameInfo.isReligionEnabled()) continue
val label = focus.label.toLabel()
val cell = Table()
cell.touchable = Touchable.enabled
cell.add(label).pad(5f)
if (cityScreen.canChangeState)
cell.onClick { city.cityAIFocus = focus; city.reassignPopulation(); cityScreen.update() }
if (cityScreen.canChangeState) {
cell.touchable = Touchable.enabled
cell.onClick {
city.cityAIFocus = focus; city.reassignPopulation(); cityScreen.update()
}
}
cell.background = ImageGetter.getBackground(if (city.cityAIFocus == focus) colorSelected else colorButton)
innerTable.add(cell).growX().pad(3f)
if (focus.stat != null)
innerTable.add(ImageGetter.getStatIcon(focus.stat.name)).size(20f).padRight(5f)
innerTable.row()
add(cell).growX().pad(3f)
if (newRow) // every 2 make new row
row()
newRow = !newRow
}
pack()
}
fun asExpander(onChange: (() -> Unit)?): ExpanderTab {
return ExpanderTab(
title = "{Citizen Management}",
fontSize = Constants.defaultFontSize,
persistenceID = "CityStatsTable.CitizenManagement",
startsOutOpened = false,
onChange = onChange
) {
it.add(this)
update()
}
}
}

View File

@ -55,12 +55,6 @@ class CityScreen(
/** Displays raze city button - sits on TOP CENTER */
private var razeCityButtonHolder = Table()
/** Displays reset locks button - sits on BOT RIGHT */
private var resetCitizensButtonHolder = Table()
/** Displays reset locks button - sits on BOT RIGHT */
private var citizenManagementButtonHolder = Table()
/** Displays city stats info */
private var cityStatsTable = CityStatsTable(this)
@ -70,10 +64,6 @@ class CityScreen(
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
private var selectedConstructionTable = ConstructionInfoTable(this)
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
private var citizenManagementTable = CitizenManagementTable(this)
var citizenManagementVisible = false
/** Displays city name, allows switching between cities - sits on BOTTOM CENTER */
private var cityPickerTable = CityScreenCityPickerTable(this)
@ -118,29 +108,10 @@ class CityScreen(
//stage.setDebugTableUnderMouse(true)
stage.addActor(cityStatsTable)
val resetCitizensButton = "Reset Citizens".toTextButton()
resetCitizensButton.labelCell.pad(5f)
resetCitizensButton.onClick { city.reassignPopulation(resetLocked = true); update() }
resetCitizensButtonHolder.add(resetCitizensButton)
resetCitizensButtonHolder.pack()
if (!canChangeState) resetCitizensButton.disable()
stage.addActor(resetCitizensButtonHolder)
val citizenManagementButton = "Citizen Management".toTextButton()
citizenManagementButton.labelCell.pad(5f)
citizenManagementButton.onClick {
clearSelection()
citizenManagementVisible = true
update()
}
if (!canChangeState) citizenManagementButton.disable()
citizenManagementButtonHolder.add(citizenManagementButton)
citizenManagementButtonHolder.pack()
stage.addActor(citizenManagementButtonHolder)
constructionsTable.addActorsToStage()
stage.addActor(cityInfoTable)
stage.addActor(selectedConstructionTable)
stage.addActor(tileTable)
stage.addActor(citizenManagementTable)
stage.addActor(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait
stage.addActor(exitCityButton)
update()
@ -178,23 +149,6 @@ class CityScreen(
tileTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
selectedConstructionTable.update(selectedConstruction)
selectedConstructionTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
citizenManagementTable.update(citizenManagementVisible)
citizenManagementTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
if (selectedTile == null && selectedConstruction == null && !citizenManagementVisible)
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
posFromEdge, Align.bottomRight)
else if (selectedConstruction != null)
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
posFromEdge + selectedConstructionTable.height + 10f, Align.bottomRight)
else if (selectedTile != null)
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
posFromEdge + tileTable.height + 10f, Align.bottomRight)
else
resetCitizensButtonHolder.setPosition(stage.width - posFromEdge,
posFromEdge + citizenManagementTable.height + 10f, Align.bottomRight)
citizenManagementButtonHolder.isVisible = !citizenManagementVisible
citizenManagementButtonHolder.setPosition(stage.width - posFromEdge,
posFromEdge + resetCitizensButtonHolder.y + resetCitizensButtonHolder.height + 10f, Align.bottomRight)
// In portrait mode only: calculate already occupied horizontal space
val rightMargin = when {
@ -413,13 +367,11 @@ class CityScreen(
pickTileData = null
}
selectedTile = null
citizenManagementVisible = false
}
private fun selectTile(newTile: TileInfo?) {
selectedConstruction = null
selectedQueueEntryTargetTile = null
pickTileData = null
citizenManagementVisible = false
selectedTile = newTile
}
fun clearSelection() = selectTile(null)

View File

@ -16,9 +16,11 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.*
import kotlin.math.ceil
import kotlin.math.round
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
class CityStatsTable(val cityScreen: CityScreen): Table() {
private val innerTable = Table()
private val outerPane: ScrollPane
private val cityInfo = cityScreen.city
init {
@ -29,7 +31,10 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
innerTable.defaults().pad(2f)
innerTable.background = ImageGetter.getBackground(Color.BLACK.cpy().apply { a = 0.8f })
add(innerTable).fill()
outerPane = ScrollPane(innerTable)
outerPane.setOverscroll(false, false)
outerPane.setScrollingDisabled(true, false)
add(outerPane).maxHeight(cityScreen.stage.height / 2)
}
fun update() {
@ -42,18 +47,20 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
val icon = Table()
if (cityInfo.cityAIFocus.stat == stat) {
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = selected))
if (cityScreen.canChangeState)
if (cityScreen.canChangeState) {
icon.onClick {
cityInfo.cityAIFocus = CityFocus.NoFocus
cityInfo.reassignPopulation(); cityScreen.update()
}
}
} else {
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = Color.CLEAR))
if (cityScreen.canChangeState)
if (cityScreen.canChangeState) {
icon.onClick {
cityInfo.cityAIFocus = cityInfo.cityAIFocus.safeValueOf(stat)
cityInfo.reassignPopulation(); cityScreen.update()
}
}
}
miniStatsTable.add(icon).size(27f).padRight(5f)
val valueToDisplay = if (stat == Stat.Happiness) cityInfo.cityStats.happinessList.values.sum() else amount
@ -63,12 +70,16 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
innerTable.addSeparator()
addText()
addCitizenManagement()
if (!cityInfo.population.getMaxSpecialists().isEmpty()) {
addSpecialistInfo()
}
if (cityInfo.religion.getNumberOfFollowers().isNotEmpty() && cityInfo.civInfo.gameInfo.isReligionEnabled())
addReligionInfo()
innerTable.pack()
outerPane.layout()
outerPane.updateVisualScroll()
pack()
}
@ -132,6 +143,18 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
innerTable.add(tableWithIcons).row()
}
private fun addCitizenManagement() {
val expanderTab = CitizenManagementTable(cityScreen).asExpander {
pack()
setPosition(
stage.width - CityScreen.posFromEdge,
stage.height - CityScreen.posFromEdge,
Align.topRight
)
}
innerTable.add(expanderTab).growX().row()
}
private fun addSpecialistInfo() {
val expanderTab = SpecialistAllocationTable(cityScreen).asExpander {
pack()

View File

@ -18,7 +18,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
// Auto/Manual Specialists Toggle
// Color of "color" coming from Skin.json that's loaded into BaseScreen
// 5 columns: unassignButton, AllocationTable, assignButton, SeparatorVertical, SpecialistsStatsTabe
if (cityScreen.canChangeState)
if (cityScreen.canChangeState) {
if (cityInfo.manualSpecialists) {
val manualSpecialists = "Manual Specialists".toLabel()
.addBorder(5f, BaseScreen.skin.get("color", Color::class.java))
@ -33,6 +33,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
autoSpecialists.onClick { cityInfo.manualSpecialists = true; update() }
add(autoSpecialists).colspan(5).row()
}
}
for ((specialistName, maxSpecialists) in cityInfo.population.getMaxSpecialists()) {
if (!cityInfo.getRuleset().specialists.containsKey(specialistName)) // specialist doesn't exist in this ruleset, probably a mod
continue