diff --git a/core/src/com/unciv/ui/screens/overviewscreen/CityOverviewTable.kt b/core/src/com/unciv/ui/screens/overviewscreen/CityOverviewTable.kt index 3178debdb9..aeba428841 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/CityOverviewTable.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/CityOverviewTable.kt @@ -9,13 +9,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.UncivGame -import com.unciv.logic.city.CityFlags import com.unciv.logic.city.City +import com.unciv.logic.city.CityFlags import com.unciv.logic.civilization.Civilization import com.unciv.models.stats.Stat import com.unciv.models.translations.tr -import com.unciv.ui.screens.cityscreen.CityScreen -import com.unciv.ui.images.ImageGetter import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.center @@ -24,6 +22,8 @@ import com.unciv.ui.components.extensions.pad import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.screens.cityscreen.CityScreen import kotlin.math.roundToInt class CityOverviewTab( @@ -48,7 +48,8 @@ class CityOverviewTab( private const val CITY = "City" private const val WLTK = "WLTK" private const val CONSTRUCTION = "Construction" - private val alphabeticColumns = listOf(CITY, CONSTRUCTION, WLTK) + private const val GARRISON = "Garrison" + private val alphabeticColumns = listOf(CITY, CONSTRUCTION, WLTK, GARRISON) private val citySortIcon = ImageGetter.getUnitIcon("Settler") .surroundWithCircle(iconSize) @@ -61,6 +62,10 @@ class CityOverviewTab( .apply { color = Color.BLACK } .surroundWithCircle(iconSize, color = Color.LIGHT_GRAY) .apply { addTooltip("Current construction", 18f, tipAlign = Align.center) } + private val garrisonSortIcon = ImageGetter.getImage("OtherIcons/Shield") + .apply { color = Color.BLACK } + .surroundWithCircle(iconSize, color = Color.LIGHT_GRAY) + .apply { addTooltip("Garrisoned by unit", 18f, tipAlign = Align.center) } // Readability helpers private fun String.isStat() = Stat.isStat(this) @@ -103,7 +108,7 @@ class CityOverviewTab( add(cityInfoTableTotal) } - fun toggleSort(sortBy: String) { + private fun toggleSort(sortBy: String) { if (sortBy == persistableData.sortedBy) { persistableData.descending = !persistableData.descending } else { @@ -112,7 +117,7 @@ class CityOverviewTab( } } - fun getComparator() = Comparator { city2: City, city1: City -> + private fun getComparator() = Comparator { city2: City, city1: City -> when(persistableData.sortedBy) { CITY -> collator.compare(city2.name.tr(), city1.name.tr()) CONSTRUCTION -> collator.compare( @@ -120,6 +125,10 @@ class CityOverviewTab( city1.cityConstructions.currentConstructionFromQueue.tr()) "Population" -> city2.population.population - city1.population.population WLTK -> city2.isWeLoveTheKingDayActive().compareTo(city1.isWeLoveTheKingDayActive()) + GARRISON -> collator.compare( + city2.getCenterTile().militaryUnit?.name?.tr() ?: "", + city1.getCenterTile().militaryUnit?.name?.tr() ?: "", + ) else -> { val stat = Stat.safeValueOf(persistableData.sortedBy)!! city2.getStat(stat) - city1.getStat(stat) @@ -172,6 +181,7 @@ class CityOverviewTab( addSortIcon(name) } addSortIcon(WLTK, wltkSortIcon) + addSortIcon(GARRISON, garrisonSortIcon) cityInfoTableHeader.pack() } @@ -221,11 +231,23 @@ class CityOverviewTab( city.demandedResource.isNotEmpty() -> { val image = ImageGetter.getResourcePortrait(city.demandedResource, iconSize *0.7f) image.addTooltip("Demanding [${city.demandedResource}]", 18f, tipAlign = Align.topLeft) - cityInfoTableDetails.add(image).padLeft(iconSize *0.3f) + cityInfoTableDetails.add(image) } else -> cityInfoTableDetails.add() } + val garrisonUnit = city.getCenterTile().militaryUnit + if (garrisonUnit == null) { + cityInfoTableDetails.add() + } else { + val garrisonUnitName = garrisonUnit.displayName() + val garrisonUnitIcon = ImageGetter.getConstructionPortrait(garrisonUnit.baseUnit.getIconName(), iconSize * 0.7f) + garrisonUnitIcon.addTooltip(garrisonUnitName, 18f, tipAlign = Align.topLeft) + garrisonUnitIcon.onClick { + overviewScreen.select(EmpireOverviewCategories.Units, UnitOverviewTab.getUnitIdentifier(garrisonUnit) ) + } + cityInfoTableDetails.add(garrisonUnitIcon) + } cityInfoTableDetails.row() } @@ -248,6 +270,7 @@ class CityOverviewTab( else cityInfoTableTotal.add(viewingPlayer.cities.sumOf { it.getStat(stat) }.toCenteredLabel()) } cityInfoTableTotal.add(viewingPlayer.cities.count { it.isWeLoveTheKingDayActive() }.toCenteredLabel()) + cityInfoTableTotal.add(viewingPlayer.cities.count { it.getCenterTile().militaryUnit != null }.toCenteredLabel()) cityInfoTableTotal.pack() } } diff --git a/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewScreen.kt index b78e5b4deb..95465802f3 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewScreen.kt @@ -73,7 +73,7 @@ class EmpireOverviewScreen( ) if (category.name == page) { tabbedPager.selectPage(index) - pageObject.select(selection) + select(pageObject, selection) } } @@ -94,4 +94,14 @@ class EmpireOverviewScreen( val category = (pageObjects.entries.find { it.value == tab } ?: return).key tabbedPager.replacePage(category.name, tab) } + + fun select(category: EmpireOverviewCategories, selection: String) { + tabbedPager.selectPage(category.name) + select(pageObjects[category], selection) + } + private fun select(tab: EmpireOverviewTab?, selection: String) { + if (tab == null) return + val scrollY = tab.select(selection) ?: return + tabbedPager.setPageScrollY(tabbedPager.activePage, scrollY) + } } diff --git a/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewTab.kt b/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewTab.kt index 60bfd3bf0d..b4139d73eb 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewTab.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/EmpireOverviewTab.kt @@ -26,8 +26,10 @@ abstract class EmpireOverviewTab ( settings.lastOverviewPage = caption } - /** Override if the tab can _select_ something specific */ - open fun select(selection: String) {} + /** Override if the tab can _select_ something specific. + * @return non-null to set that tab's ScrollPane.scrollY + */ + open fun select(selection: String): Float? = null val gameInfo = viewingPlayer.gameInfo diff --git a/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt b/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt index 02122e946b..860fef25b2 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/ReligionOverviewTable.kt @@ -125,10 +125,11 @@ class ReligionOverviewTab( } } - override fun select(selection: String) { + override fun select(selection: String): Float? { persistableData.selectedReligion = selection loadReligionButtons() // so the icon is "highlighted" loadReligion(selection) + return null } private fun loadReligion(religionName: String?) { if (religionName == null) return diff --git a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTable.kt b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTable.kt index 495824fbef..4f84a936e7 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTable.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTable.kt @@ -2,7 +2,10 @@ package com.unciv.ui.screens.overviewscreen import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.scenes.scene2d.Action +import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Group +import com.badlogic.gdx.scenes.scene2d.actions.Actions import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.Constants @@ -28,6 +31,7 @@ import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.extensions.toPrettyString import com.unciv.ui.screens.worldscreen.unit.actions.UnitActionsUpgrade import kotlin.math.abs @@ -53,6 +57,7 @@ class UnitOverviewTab( } override fun deactivated(index: Int, caption: String, pager: TabbedPager) { persistableData.scrollY = pager.getPageScrollY(index) + removeBlinkAction() } private val supplyTableWidth = (overviewScreen.stage.width * 0.25f).coerceAtLeast(240f) @@ -60,6 +65,16 @@ class UnitOverviewTab( private val unitHeaderTable = Table() private val fixedContent = Table() + // used for select() + private var blinkAction: Action? = null + private var blinkActor: Actor? = null + private fun removeBlinkAction() { + if (blinkAction == null || blinkActor == null) return + blinkActor!!.removeAction(blinkAction) + blinkAction = null + blinkActor = null + } + override fun getFixedContent() = fixedContent init { @@ -170,6 +185,7 @@ class UnitOverviewTab( UnitGroup(unit, 20f), fontColor = if (unit.due && unit.isIdle()) Color.WHITE else Color.LIGHT_GRAY ) + button.name = getUnitIdentifier(unit) // Marker to find a unit in select() button.onClick { showWorldScreenAt(unit) } @@ -248,4 +264,27 @@ class UnitOverviewTab( } return this } + + companion object { + fun getUnitIdentifier(unit: MapUnit) = unit.run { "$name@${getTile().position.toPrettyString()}" } + } + + override fun select(selection: String): Float? { + val cell = unitListTable.cells.asSequence() + .filter { it.actor is IconTextButton && it.actor.name == selection } + .firstOrNull() ?: return null + val button = cell.actor as IconTextButton + val scrollY = (0 until cell.row) + .map { unitListTable.getRowHeight(it) }.sum() - + (parent.height - unitListTable.getRowHeight(cell.row)) / 2 + + removeBlinkAction() + blinkAction = Actions.repeat(3, Actions.sequence( + Actions.fadeOut(0.17f), + Actions.fadeIn(0.17f) + )) + blinkActor = button + button.addAction(blinkAction) + return scrollY + } }