mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04: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:
parent
67065d766b
commit
317e8c74df
@ -3,62 +3,77 @@ package com.unciv.ui.cityscreen
|
|||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
|
import com.unciv.Constants
|
||||||
import com.unciv.logic.city.CityFocus
|
import com.unciv.logic.city.CityFocus
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
|
|
||||||
class CitizenManagementTable(val cityScreen: CityScreen) : Table() {
|
class CitizenManagementTable(val cityScreen: CityScreen) : Table(BaseScreen.skin) {
|
||||||
private val innerTable = Table()
|
|
||||||
val city = cityScreen.city
|
val city = cityScreen.city
|
||||||
|
|
||||||
init {
|
fun update() {
|
||||||
innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().darken(0.5f))
|
clear()
|
||||||
add(innerTable).pad(2f).fill()
|
|
||||||
background = ImageGetter.getBackground(Color.WHITE)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(visible: Boolean = false) {
|
|
||||||
innerTable.clear()
|
|
||||||
|
|
||||||
if (!visible) {
|
|
||||||
isVisible = false
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isVisible = true
|
|
||||||
|
|
||||||
val colorSelected = BaseScreen.skin.get("selection", Color::class.java)
|
val colorSelected = BaseScreen.skin.get("selection", Color::class.java)
|
||||||
val colorButton = BaseScreen.skin.get("color", Color::class.java)
|
val colorButton = BaseScreen.skin.get("color", Color::class.java)
|
||||||
// effectively a button, but didn't want to rewrite TextButton style
|
// effectively a button, but didn't want to rewrite TextButton style
|
||||||
// and much more compact and can control backgrounds easily based on settings
|
// 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 avoidLabel = "Avoid Growth".toLabel()
|
||||||
val avoidCell = Table()
|
val avoidCell = Table()
|
||||||
avoidCell.touchable = Touchable.enabled
|
|
||||||
avoidCell.add(avoidLabel).pad(5f)
|
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.onClick { city.avoidGrowth = !city.avoidGrowth; city.reassignPopulation(); cityScreen.update() }
|
||||||
|
}
|
||||||
avoidCell.background = ImageGetter.getBackground(if (city.avoidGrowth) colorSelected else colorButton)
|
avoidCell.background = ImageGetter.getBackground(if (city.avoidGrowth) colorSelected else colorButton)
|
||||||
innerTable.add(avoidCell).colspan(2).growX().pad(3f)
|
add(avoidCell).colspan(2).growX().pad(3f)
|
||||||
innerTable.row()
|
row()
|
||||||
|
|
||||||
|
var newRow = false
|
||||||
for (focus in CityFocus.values()) {
|
for (focus in CityFocus.values()) {
|
||||||
if (!focus.tableEnabled) continue
|
if (!focus.tableEnabled) continue
|
||||||
if (focus == CityFocus.FaithFocus && !city.civInfo.gameInfo.isReligionEnabled()) continue
|
if (focus == CityFocus.FaithFocus && !city.civInfo.gameInfo.isReligionEnabled()) continue
|
||||||
val label = focus.label.toLabel()
|
val label = focus.label.toLabel()
|
||||||
val cell = Table()
|
val cell = Table()
|
||||||
cell.touchable = Touchable.enabled
|
|
||||||
cell.add(label).pad(5f)
|
cell.add(label).pad(5f)
|
||||||
if (cityScreen.canChangeState)
|
if (cityScreen.canChangeState) {
|
||||||
cell.onClick { city.cityAIFocus = focus; city.reassignPopulation(); cityScreen.update() }
|
cell.touchable = Touchable.enabled
|
||||||
|
cell.onClick {
|
||||||
|
city.cityAIFocus = focus; city.reassignPopulation(); cityScreen.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
cell.background = ImageGetter.getBackground(if (city.cityAIFocus == focus) colorSelected else colorButton)
|
cell.background = ImageGetter.getBackground(if (city.cityAIFocus == focus) colorSelected else colorButton)
|
||||||
innerTable.add(cell).growX().pad(3f)
|
add(cell).growX().pad(3f)
|
||||||
if (focus.stat != null)
|
if (newRow) // every 2 make new row
|
||||||
innerTable.add(ImageGetter.getStatIcon(focus.stat.name)).size(20f).padRight(5f)
|
row()
|
||||||
innerTable.row()
|
newRow = !newRow
|
||||||
}
|
}
|
||||||
|
|
||||||
pack()
|
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 */
|
/** Displays raze city button - sits on TOP CENTER */
|
||||||
private var razeCityButtonHolder = Table()
|
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 */
|
/** Displays city stats info */
|
||||||
private var cityStatsTable = CityStatsTable(this)
|
private var cityStatsTable = CityStatsTable(this)
|
||||||
|
|
||||||
@ -70,10 +64,6 @@ class CityScreen(
|
|||||||
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
|
/** Displays selected construction info, alternate with tileTable - sits on BOTTOM RIGHT */
|
||||||
private var selectedConstructionTable = ConstructionInfoTable(this)
|
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 */
|
/** Displays city name, allows switching between cities - sits on BOTTOM CENTER */
|
||||||
private var cityPickerTable = CityScreenCityPickerTable(this)
|
private var cityPickerTable = CityScreenCityPickerTable(this)
|
||||||
|
|
||||||
@ -118,29 +108,10 @@ class CityScreen(
|
|||||||
|
|
||||||
//stage.setDebugTableUnderMouse(true)
|
//stage.setDebugTableUnderMouse(true)
|
||||||
stage.addActor(cityStatsTable)
|
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()
|
constructionsTable.addActorsToStage()
|
||||||
stage.addActor(cityInfoTable)
|
stage.addActor(cityInfoTable)
|
||||||
stage.addActor(selectedConstructionTable)
|
stage.addActor(selectedConstructionTable)
|
||||||
stage.addActor(tileTable)
|
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(cityPickerTable) // add late so it's top in Z-order and doesn't get covered in cramped portrait
|
||||||
stage.addActor(exitCityButton)
|
stage.addActor(exitCityButton)
|
||||||
update()
|
update()
|
||||||
@ -178,23 +149,6 @@ class CityScreen(
|
|||||||
tileTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
tileTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
||||||
selectedConstructionTable.update(selectedConstruction)
|
selectedConstructionTable.update(selectedConstruction)
|
||||||
selectedConstructionTable.setPosition(stage.width - posFromEdge, posFromEdge, Align.bottomRight)
|
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
|
// In portrait mode only: calculate already occupied horizontal space
|
||||||
val rightMargin = when {
|
val rightMargin = when {
|
||||||
@ -413,13 +367,11 @@ class CityScreen(
|
|||||||
pickTileData = null
|
pickTileData = null
|
||||||
}
|
}
|
||||||
selectedTile = null
|
selectedTile = null
|
||||||
citizenManagementVisible = false
|
|
||||||
}
|
}
|
||||||
private fun selectTile(newTile: TileInfo?) {
|
private fun selectTile(newTile: TileInfo?) {
|
||||||
selectedConstruction = null
|
selectedConstruction = null
|
||||||
selectedQueueEntryTargetTile = null
|
selectedQueueEntryTargetTile = null
|
||||||
pickTileData = null
|
pickTileData = null
|
||||||
citizenManagementVisible = false
|
|
||||||
selectedTile = newTile
|
selectedTile = newTile
|
||||||
}
|
}
|
||||||
fun clearSelection() = selectTile(null)
|
fun clearSelection() = selectTile(null)
|
||||||
|
@ -16,9 +16,11 @@ import com.unciv.ui.images.ImageGetter
|
|||||||
import com.unciv.ui.utils.*
|
import com.unciv.ui.utils.*
|
||||||
import kotlin.math.ceil
|
import kotlin.math.ceil
|
||||||
import kotlin.math.round
|
import kotlin.math.round
|
||||||
|
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||||
|
|
||||||
class CityStatsTable(val cityScreen: CityScreen): Table() {
|
class CityStatsTable(val cityScreen: CityScreen): Table() {
|
||||||
private val innerTable = Table()
|
private val innerTable = Table()
|
||||||
|
private val outerPane: ScrollPane
|
||||||
private val cityInfo = cityScreen.city
|
private val cityInfo = cityScreen.city
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@ -29,7 +31,10 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
innerTable.defaults().pad(2f)
|
innerTable.defaults().pad(2f)
|
||||||
innerTable.background = ImageGetter.getBackground(Color.BLACK.cpy().apply { a = 0.8f })
|
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() {
|
fun update() {
|
||||||
@ -42,19 +47,21 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
val icon = Table()
|
val icon = Table()
|
||||||
if (cityInfo.cityAIFocus.stat == stat) {
|
if (cityInfo.cityAIFocus.stat == stat) {
|
||||||
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = selected))
|
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = selected))
|
||||||
if (cityScreen.canChangeState)
|
if (cityScreen.canChangeState) {
|
||||||
icon.onClick {
|
icon.onClick {
|
||||||
cityInfo.cityAIFocus = CityFocus.NoFocus
|
cityInfo.cityAIFocus = CityFocus.NoFocus
|
||||||
cityInfo.reassignPopulation(); cityScreen.update()
|
cityInfo.reassignPopulation(); cityScreen.update()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = Color.CLEAR))
|
icon.add(ImageGetter.getStatIcon(stat.name).surroundWithCircle(27f, false, color = Color.CLEAR))
|
||||||
if (cityScreen.canChangeState)
|
if (cityScreen.canChangeState) {
|
||||||
icon.onClick {
|
icon.onClick {
|
||||||
cityInfo.cityAIFocus = cityInfo.cityAIFocus.safeValueOf(stat)
|
cityInfo.cityAIFocus = cityInfo.cityAIFocus.safeValueOf(stat)
|
||||||
cityInfo.reassignPopulation(); cityScreen.update()
|
cityInfo.reassignPopulation(); cityScreen.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
miniStatsTable.add(icon).size(27f).padRight(5f)
|
miniStatsTable.add(icon).size(27f).padRight(5f)
|
||||||
val valueToDisplay = if (stat == Stat.Happiness) cityInfo.cityStats.happinessList.values.sum() else amount
|
val valueToDisplay = if (stat == Stat.Happiness) cityInfo.cityStats.happinessList.values.sum() else amount
|
||||||
miniStatsTable.add(round(valueToDisplay).toInt().toLabel()).padRight(10f)
|
miniStatsTable.add(round(valueToDisplay).toInt().toLabel()).padRight(10f)
|
||||||
@ -63,12 +70,16 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
|
|
||||||
innerTable.addSeparator()
|
innerTable.addSeparator()
|
||||||
addText()
|
addText()
|
||||||
|
addCitizenManagement()
|
||||||
if (!cityInfo.population.getMaxSpecialists().isEmpty()) {
|
if (!cityInfo.population.getMaxSpecialists().isEmpty()) {
|
||||||
addSpecialistInfo()
|
addSpecialistInfo()
|
||||||
}
|
}
|
||||||
if (cityInfo.religion.getNumberOfFollowers().isNotEmpty() && cityInfo.civInfo.gameInfo.isReligionEnabled())
|
if (cityInfo.religion.getNumberOfFollowers().isNotEmpty() && cityInfo.civInfo.gameInfo.isReligionEnabled())
|
||||||
addReligionInfo()
|
addReligionInfo()
|
||||||
|
|
||||||
|
innerTable.pack()
|
||||||
|
outerPane.layout()
|
||||||
|
outerPane.updateVisualScroll()
|
||||||
pack()
|
pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +143,18 @@ class CityStatsTable(val cityScreen: CityScreen): Table() {
|
|||||||
innerTable.add(tableWithIcons).row()
|
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() {
|
private fun addSpecialistInfo() {
|
||||||
val expanderTab = SpecialistAllocationTable(cityScreen).asExpander {
|
val expanderTab = SpecialistAllocationTable(cityScreen).asExpander {
|
||||||
pack()
|
pack()
|
||||||
|
@ -18,7 +18,7 @@ class SpecialistAllocationTable(val cityScreen: CityScreen) : Table(BaseScreen.s
|
|||||||
// Auto/Manual Specialists Toggle
|
// Auto/Manual Specialists Toggle
|
||||||
// Color of "color" coming from Skin.json that's loaded into BaseScreen
|
// Color of "color" coming from Skin.json that's loaded into BaseScreen
|
||||||
// 5 columns: unassignButton, AllocationTable, assignButton, SeparatorVertical, SpecialistsStatsTabe
|
// 5 columns: unassignButton, AllocationTable, assignButton, SeparatorVertical, SpecialistsStatsTabe
|
||||||
if (cityScreen.canChangeState)
|
if (cityScreen.canChangeState) {
|
||||||
if (cityInfo.manualSpecialists) {
|
if (cityInfo.manualSpecialists) {
|
||||||
val manualSpecialists = "Manual Specialists".toLabel()
|
val manualSpecialists = "Manual Specialists".toLabel()
|
||||||
.addBorder(5f, BaseScreen.skin.get("color", Color::class.java))
|
.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() }
|
autoSpecialists.onClick { cityInfo.manualSpecialists = true; update() }
|
||||||
add(autoSpecialists).colspan(5).row()
|
add(autoSpecialists).colspan(5).row()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for ((specialistName, maxSpecialists) in cityInfo.population.getMaxSpecialists()) {
|
for ((specialistName, maxSpecialists) in cityInfo.population.getMaxSpecialists()) {
|
||||||
if (!cityInfo.getRuleset().specialists.containsKey(specialistName)) // specialist doesn't exist in this ruleset, probably a mod
|
if (!cityInfo.getRuleset().specialists.containsKey(specialistName)) // specialist doesn't exist in this ruleset, probably a mod
|
||||||
continue
|
continue
|
||||||
|
Loading…
x
Reference in New Issue
Block a user