mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-31 07:09:26 +07:00
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:
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user