Big rework of City plates (#8239)
* Big rework of City plates * New city plates design, new status icons * A little bit of padding for construction icon * Better border for defence counter * Better border for defence counter * Solid colored icons * Solid colored icons * Credits * Credits Co-authored-by: tunerzinc@gmail.com <vfylfhby>
After Width: | Height: | Size: 1.3 KiB |
BIN
android/Images.Skin/Skins/Minimal/roundedEdgeRectangle-mid.9.png
Normal file
After Width: | Height: | Size: 562 B |
After Width: | Height: | Size: 162 B |
After Width: | Height: | Size: 136 B |
BIN
android/Images/OtherIcons/Capital.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 949 B |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 2.8 KiB |
@ -1,12 +1,12 @@
|
||||
|
||||
Skin.png
|
||||
size: 128, 128
|
||||
size: 512, 64
|
||||
format: RGBA8888
|
||||
filter: Linear, Linear
|
||||
repeat: none
|
||||
Skins/Minimal/checkbox
|
||||
rotate: false
|
||||
xy: 52, 16
|
||||
xy: 291, 23
|
||||
size: 31, 31
|
||||
split: 0, 0, 0, 0
|
||||
orig: 31, 31
|
||||
@ -14,7 +14,7 @@ Skins/Minimal/checkbox
|
||||
index: -1
|
||||
Skins/Minimal/checkbox-pressed
|
||||
rotate: false
|
||||
xy: 64, 55
|
||||
xy: 252, 23
|
||||
size: 31, 31
|
||||
split: 0, 0, 0, 0
|
||||
orig: 31, 31
|
||||
@ -22,7 +22,7 @@ Skins/Minimal/checkbox-pressed
|
||||
index: -1
|
||||
Skins/Minimal/rectangleWithOutline
|
||||
rotate: false
|
||||
xy: 112, 121
|
||||
xy: 64, 5
|
||||
size: 3, 3
|
||||
split: 0, 0, 0, 0
|
||||
orig: 3, 3
|
||||
@ -30,25 +30,59 @@ Skins/Minimal/rectangleWithOutline
|
||||
index: -1
|
||||
Skins/Minimal/roundedEdgeRectangle
|
||||
rotate: false
|
||||
xy: 4, 74
|
||||
xy: 4, 4
|
||||
size: 52, 50
|
||||
split: 19, 20, 19, 21
|
||||
pad: 12, 13, 7, 7
|
||||
orig: 52, 50
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/roundedEdgeRectangle-mid
|
||||
rotate: false
|
||||
xy: 110, 16
|
||||
size: 38, 38
|
||||
split: 17, 17, 15, 15
|
||||
pad: 17, 17, -1, -1
|
||||
orig: 38, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/roundedEdgeRectangle-mid-border
|
||||
rotate: false
|
||||
xy: 64, 16
|
||||
size: 38, 38
|
||||
split: 18, 18, 18, 18
|
||||
orig: 38, 38
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/roundedEdgeRectangle-small
|
||||
rotate: false
|
||||
xy: 4, 4
|
||||
xy: 330, 30
|
||||
size: 24, 24
|
||||
split: 10, 10, 10, 10
|
||||
pad: 10, 10, 2, 2
|
||||
orig: 24, 24
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/roundedTopEdgeRectangle-small
|
||||
rotate: false
|
||||
xy: 394, 42
|
||||
size: 24, 12
|
||||
split: 10, 10, 10, 0
|
||||
pad: 10, 10, -1, -1
|
||||
orig: 24, 12
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/roundedTopEdgeRectangle-small-border
|
||||
rotate: false
|
||||
xy: 362, 42
|
||||
size: 24, 12
|
||||
split: 10, 10, 10, 0
|
||||
orig: 24, 12
|
||||
offset: 0, 0
|
||||
index: -1
|
||||
Skins/Minimal/select-box
|
||||
rotate: false
|
||||
xy: 64, 94
|
||||
xy: 204, 24
|
||||
size: 40, 30
|
||||
split: 7, 9, 7, 7
|
||||
orig: 40, 30
|
||||
@ -56,7 +90,7 @@ Skins/Minimal/select-box
|
||||
index: -1
|
||||
Skins/Minimal/select-box-pressed
|
||||
rotate: false
|
||||
xy: 4, 36
|
||||
xy: 156, 24
|
||||
size: 40, 30
|
||||
split: 7, 9, 7, 7
|
||||
orig: 40, 30
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 580 KiB After Width: | Height: | Size: 578 KiB |
@ -11,6 +11,10 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) {
|
||||
|
||||
// Default shapes must always end with "Shape" so the UiElementDocsWriter can identify them
|
||||
val roundedEdgeRectangleSmallShape = skinLocation + "roundedEdgeRectangle-small"
|
||||
val roundedTopEdgeRectangleSmallShape = skinLocation + "roundedTopEdgeRectangle-small"
|
||||
val roundedTopEdgeRectangleSmallBorderShape = skinLocation + "roundedTopEdgeRectangle-small-border"
|
||||
val roundedEdgeRectangleMidShape = skinLocation + "roundedEdgeRectangle-mid"
|
||||
val roundedEdgeRectangleMidBorderShape = skinLocation + "roundedEdgeRectangle-mid-border"
|
||||
val roundedEdgeRectangleShape = skinLocation + "roundedEdgeRectangle"
|
||||
val rectangleWithOutlineShape = skinLocation + "rectangleWithOutline"
|
||||
val selectBoxShape = skinLocation + "select-box"
|
||||
|
@ -37,11 +37,6 @@ class CityScreenCityPickerTable(private val cityScreen: CityScreen) : Table() {
|
||||
cityNameTable.add(fireImage).size(20f).padRight(5f)
|
||||
}
|
||||
|
||||
if (city.isCapital()) {
|
||||
val starImage = ImageGetter.getImage("OtherIcons/Star").apply { color = Color.LIGHT_GRAY }
|
||||
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||
}
|
||||
|
||||
if (city.isPuppet) {
|
||||
val starImage = ImageGetter.getImage("OtherIcons/Puppet").apply { color = Color.LIGHT_GRAY }
|
||||
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||
@ -52,6 +47,11 @@ class CityScreenCityPickerTable(private val cityScreen: CityScreen) : Table() {
|
||||
cityNameTable.add(resistanceImage).size(20f).padRight(5f)
|
||||
}
|
||||
|
||||
if (city.isCapital()) {
|
||||
val starImage = ImageGetter.getImage("OtherIcons/Star").apply { color = Color.LIGHT_GRAY }
|
||||
cityNameTable.add(starImage).size(20f).padRight(5f)
|
||||
}
|
||||
|
||||
val currentCityLabel = city.name.toLabel(fontSize = 30, fontColor = civInfo.nation.getInnerColor())
|
||||
if (cityScreen.canChangeState) currentCityLabel.onClick {
|
||||
AskTextPopup(
|
||||
|
@ -386,16 +386,26 @@ object ImageGetter {
|
||||
.surroundWithThinCircle(techIconColor)
|
||||
}
|
||||
|
||||
fun getProgressBarHorizontal(width: Float, height: Float, percentComplete: Float, progressColor: Color, backgroundColor: Color): Group {
|
||||
fun getProgressBarHorizontal(
|
||||
width: Float, height: Float,
|
||||
percentComplete: Float,
|
||||
progressColor: Color,
|
||||
backgroundColor: Color): Group {
|
||||
return ProgressBar(width, height, false)
|
||||
.setBackground(backgroundColor)
|
||||
.setProgress(progressColor, percentComplete)
|
||||
}
|
||||
|
||||
fun getProgressBarVertical(width: Float, height: Float, percentComplete: Float, progressColor: Color, backgroundColor: Color): Group {
|
||||
fun getProgressBarVertical(
|
||||
width: Float,
|
||||
height: Float,
|
||||
percentComplete: Float,
|
||||
progressColor: Color,
|
||||
backgroundColor: Color,
|
||||
progressPadding: Float = 0f): Group {
|
||||
return ProgressBar(width, height, true)
|
||||
.setBackground(backgroundColor)
|
||||
.setProgress(progressColor, percentComplete)
|
||||
.setProgress(progressColor, percentComplete, padding = progressPadding)
|
||||
}
|
||||
|
||||
class ProgressBar(width: Float, height: Float, val vertical: Boolean = true):Group() {
|
||||
@ -427,7 +437,7 @@ object ImageGetter {
|
||||
|
||||
fun setBackground(color: Color): ProgressBar {
|
||||
background = getWhiteDot()
|
||||
background?.color = color
|
||||
background?.color = color.cpy()
|
||||
background?.setSize(width, height) //clamp between 0 and 1
|
||||
background?.toBack()
|
||||
background?.center(this)
|
||||
@ -436,34 +446,44 @@ object ImageGetter {
|
||||
return this
|
||||
}
|
||||
|
||||
fun setSemiProgress(color: Color, percentage: Float): ProgressBar {
|
||||
fun setSemiProgress(color: Color, percentage: Float, padding: Float = 0f): ProgressBar {
|
||||
secondaryPercentage = percentage
|
||||
secondaryProgress = getWhiteDot()
|
||||
secondaryProgress?.color = color
|
||||
secondaryProgress?.color = color.cpy()
|
||||
if (vertical)
|
||||
secondaryProgress?.setSize(width, height * max(min(percentage, 1f),0f))
|
||||
secondaryProgress?.setSize(width-padding*2, height * max(min(percentage, 1f),0f))
|
||||
else
|
||||
secondaryProgress?.setSize(width * max(min(percentage, 1f),0f), height)
|
||||
if (secondaryProgress != null)
|
||||
secondaryProgress?.setSize(width * max(min(percentage, 1f),0f), height-padding*2)
|
||||
if (secondaryProgress != null) {
|
||||
addActor(secondaryProgress)
|
||||
if (vertical)
|
||||
secondaryProgress?.centerX(this)
|
||||
else
|
||||
secondaryProgress?.centerY(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun setProgress(color: Color, percentage: Float): ProgressBar {
|
||||
fun setProgress(color: Color, percentage: Float, padding: Float = 0f): ProgressBar {
|
||||
primaryPercentage = percentage
|
||||
primaryProgress = getWhiteDot()
|
||||
primaryProgress?.color = color
|
||||
primaryProgress?.color = color.cpy()
|
||||
if (vertical)
|
||||
primaryProgress?.setSize(width, height * max(min(percentage, 1f),0f))
|
||||
primaryProgress?.setSize(width-padding*2, height * max(min(percentage, 1f),0f))
|
||||
else
|
||||
primaryProgress?.setSize(width * max(min(percentage, 1f),0f), height)
|
||||
if (primaryProgress != null)
|
||||
primaryProgress?.setSize(width * max(min(percentage, 1f),0f), height-padding*2)
|
||||
if (primaryProgress != null) {
|
||||
addActor(primaryProgress)
|
||||
if (vertical)
|
||||
primaryProgress?.centerX(this)
|
||||
else
|
||||
primaryProgress?.centerY(this)
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
fun getHealthBar(currentHealth: Float, maxHealth: Float, healthBarSize: Float): Table {
|
||||
fun getHealthBar(currentHealth: Float, maxHealth: Float, healthBarSize: Float, height: Float=5f): Table {
|
||||
val healthPercent = currentHealth / maxHealth
|
||||
val healthBar = Table()
|
||||
|
||||
@ -473,10 +493,10 @@ object ImageGetter {
|
||||
healthPercent > 1 / 3f -> Color.ORANGE
|
||||
else -> Color.RED
|
||||
}
|
||||
healthBar.add(healthPartOfBar).size(healthBarSize * healthPercent, 5f)
|
||||
healthBar.add(healthPartOfBar).size(healthBarSize * healthPercent, height)
|
||||
|
||||
val emptyPartOfBar = getDot(Color.BLACK)
|
||||
healthBar.add(emptyPartOfBar).size(healthBarSize * (1 - healthPercent), 5f)
|
||||
healthBar.add(emptyPartOfBar).size(healthBarSize * (1 - healthPercent), height)
|
||||
|
||||
healthBar.pad(1f)
|
||||
healthBar.pack()
|
||||
|
@ -77,7 +77,9 @@ fun Policy.isPickable() : Boolean {
|
||||
}
|
||||
|
||||
class PolicyButton(val policy: Policy, size: Float = 30f) : BorderedTable(
|
||||
style = BaseScreen.skinStrings.roundedEdgeRectangleSmallShape,
|
||||
path = "PolicyScreen/PolicyButton",
|
||||
defaultBorder = BaseScreen.skinStrings.roundedEdgeRectangleSmallShape,
|
||||
defaultInner = BaseScreen.skinStrings.roundedEdgeRectangleSmallShape,
|
||||
borderSize = 2f
|
||||
) {
|
||||
|
||||
@ -93,10 +95,10 @@ class PolicyButton(val policy: Policy, size: Float = 30f) : BorderedTable(
|
||||
init {
|
||||
|
||||
icon.setSize(size*0.7f, size*0.7f)
|
||||
highlight.setSize(size*1.35f, size*1.35f)
|
||||
highlight.setSize(size*1.38f, size*1.38f)
|
||||
|
||||
addActor(icon)
|
||||
add(highlight).center()
|
||||
addActor(highlight)
|
||||
|
||||
updateState()
|
||||
pack()
|
||||
@ -595,7 +597,10 @@ class PolicyPickerScreen(val worldScreen: WorldScreen, civInfo: CivilizationInfo
|
||||
Colors.policyNotPickable}
|
||||
}
|
||||
|
||||
val table = BorderedTable(style = skinStrings.roundedEdgeRectangleSmallShape, innerColor = color, borderSize = 2f)
|
||||
val table = BorderedTable(
|
||||
defaultInner = skinStrings.roundedEdgeRectangleSmallShape,
|
||||
defaultBorder = skinStrings.roundedEdgeRectangleSmallShape,
|
||||
innerColor = color, borderSize = 2f)
|
||||
|
||||
table.add(label).minHeight(30f).minWidth(150f).growX()
|
||||
table.addActor(lockIcon)
|
||||
|
@ -7,31 +7,57 @@ import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.actions.Actions
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.battle.CityCombatant
|
||||
import com.unciv.logic.city.CityConstructions
|
||||
import com.unciv.logic.city.CityInfo
|
||||
import com.unciv.logic.city.INonPerpetualConstruction
|
||||
import com.unciv.logic.city.PerpetualConstruction
|
||||
import com.unciv.logic.civilization.diplomacy.RelationshipLevel
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.cityscreen.CityReligionInfoTable
|
||||
import com.unciv.ui.cityscreen.CityScreen
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.popup.Popup
|
||||
import com.unciv.ui.trade.DiplomacyScreen
|
||||
import com.unciv.ui.utils.BaseScreen
|
||||
import com.unciv.ui.utils.BorderedTable
|
||||
import com.unciv.ui.utils.Fonts
|
||||
import com.unciv.ui.utils.extensions.brighten
|
||||
import com.unciv.ui.utils.extensions.center
|
||||
import com.unciv.ui.utils.extensions.centerX
|
||||
import com.unciv.ui.utils.extensions.centerY
|
||||
import com.unciv.ui.utils.extensions.colorFromRGB
|
||||
import com.unciv.ui.utils.extensions.onClick
|
||||
import com.unciv.ui.utils.extensions.setFontSize
|
||||
import com.unciv.ui.utils.extensions.setSize
|
||||
import com.unciv.ui.utils.extensions.surroundWithCircle
|
||||
import com.unciv.ui.utils.extensions.surroundWithThinCircle
|
||||
import com.unciv.ui.utils.extensions.toGroup
|
||||
import com.unciv.ui.utils.extensions.toLabel
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
object Colors {
|
||||
|
||||
val construction = colorFromRGB(196,140,62)
|
||||
val growh = colorFromRGB(130,225,78)
|
||||
|
||||
}
|
||||
|
||||
class IconTable(borderColor: Color, innerColor: Color, borderSize: Float, borderOnTop:Boolean=true): BorderedTable(
|
||||
path = "WorldScreen/CityButton/IconTable",
|
||||
defaultInner = BaseScreen.skinStrings.roundedEdgeRectangleMidShape,
|
||||
defaultBorder = BaseScreen.skinStrings.roundedEdgeRectangleMidBorderShape,
|
||||
borderColor = borderColor,
|
||||
innerColor = innerColor,
|
||||
borderSize = borderSize,
|
||||
borderOnTop = borderOnTop
|
||||
) {
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) }
|
||||
}
|
||||
|
||||
class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Table(BaseScreen.skin){
|
||||
val worldScreen = tileGroup.worldScreen
|
||||
val uncivGame = worldScreen.game
|
||||
@ -51,10 +77,8 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
clear()
|
||||
setButtonActions()
|
||||
addAirUnitTable()
|
||||
if (showAdditionalInfoTags && city.health < city.getMaxHealth().toFloat()) {
|
||||
val healthBar = ImageGetter.getHealthBar(city.health.toFloat(), city.getMaxHealth().toFloat(), 100f)
|
||||
add(healthBar).row()
|
||||
}
|
||||
|
||||
add(getDefenceTable()).row()
|
||||
|
||||
iconTable = getIconTable()
|
||||
add(iconTable).row()
|
||||
@ -62,12 +86,21 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
if (city.civInfo.isCityState() && city.civInfo.knows(worldScreen.viewingCiv)) {
|
||||
val diplomacyManager = city.civInfo.getDiplomacyManager(worldScreen.viewingCiv)
|
||||
val influenceBar = getInfluenceBar(diplomacyManager.getInfluence(), diplomacyManager.relationshipLevel())
|
||||
add(influenceBar).row()
|
||||
add(influenceBar).padTop(1f).row()
|
||||
}
|
||||
|
||||
|
||||
add(getStatuses()).padTop(3f)
|
||||
|
||||
pack()
|
||||
|
||||
if (showAdditionalInfoTags && city.health < city.getMaxHealth().toFloat()) {
|
||||
val healthBar = ImageGetter.getHealthBar(city.health.toFloat(),
|
||||
city.getMaxHealth().toFloat(), 100f, 3f)
|
||||
addActor(healthBar)
|
||||
healthBar.center(this)
|
||||
healthBar.y = iconTable.y + iconTable.height-healthBar.height - 1f
|
||||
}
|
||||
|
||||
setOrigin(Align.center)
|
||||
centerX(tileGroup)
|
||||
|
||||
@ -128,9 +161,9 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
setOrigin(Align.center)
|
||||
if (!isButtonMoved) {
|
||||
rotation = 180f
|
||||
setPosition(positionX - width/2, 0f)
|
||||
setPosition(positionX - width/2, -height)
|
||||
} else
|
||||
setPosition(positionX - width/2, -height/4) // height compensation because of asymmetrical icon
|
||||
setPosition(positionX - width/2, -height) // height compensation because of asymmetrical icon
|
||||
}
|
||||
iconTable.addActor(indicator)
|
||||
listOfHiddenUnitMarkers.add(indicator)
|
||||
@ -187,102 +220,127 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIconTable(forPopup: Boolean = false): Table {
|
||||
val secondaryColor = city.civInfo.nation.getInnerColor()
|
||||
class IconTable: Table() {
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) }
|
||||
private fun getDefenceTable(forPopup: Boolean = false): Group {
|
||||
val borderColor = if (city.civInfo == worldScreen.viewingCiv)
|
||||
colorFromRGB(255, 237, 200) else Color.BLACK
|
||||
|
||||
val table = BorderedTable(
|
||||
path="WorldScreen/CityButton/DefenceTable",
|
||||
innerColor = Color.BLACK,
|
||||
borderColor = borderColor,
|
||||
defaultInner = BaseScreen.skinStrings.roundedTopEdgeRectangleSmallShape,
|
||||
defaultBorder = BaseScreen.skinStrings.roundedTopEdgeRectangleSmallBorderShape,
|
||||
borderSize = 5f)
|
||||
table.pad(2f, 3f, 0f, 3f)
|
||||
|
||||
val cityStrength = CityCombatant(city).getDefendingStrength()
|
||||
val cityStrengthLabel = "${Fonts.strength}$cityStrength".toLabel(fontSize = 12)
|
||||
cityStrengthLabel.setAlignment(Align.center)
|
||||
|
||||
if (!forPopup)
|
||||
table.add(cityStrengthLabel).grow().center()
|
||||
return table
|
||||
}
|
||||
|
||||
private fun getStatuses() : Table {
|
||||
|
||||
val table = Table()
|
||||
|
||||
if (belongsToViewingCiv() && city.isConnectedToCapital() && !city.isCapital()) {
|
||||
val connectionImage = ImageGetter.getStatIcon("CityConnection")
|
||||
table.add(connectionImage).size(16f)
|
||||
}
|
||||
val iconTable = IconTable().apply { isTransform = false }
|
||||
iconTable.touchable = Touchable.enabled
|
||||
iconTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/CityButton/IconTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, city.civInfo.nation.getOuterColor())
|
||||
|
||||
if (city.isInResistance()) {
|
||||
val resistanceImage = ImageGetter.getImage("StatIcons/Resistance")
|
||||
iconTable.add(resistanceImage).size(20f).padLeft(5f)
|
||||
table.add(resistanceImage).size(16f).padLeft(2f)
|
||||
}
|
||||
|
||||
if (city.isPuppet) {
|
||||
val puppetImage = ImageGetter.getImage("OtherIcons/Puppet")
|
||||
puppetImage.color = secondaryColor
|
||||
iconTable.add(puppetImage).size(20f).padLeft(5f)
|
||||
table.add(puppetImage).size(16f).padLeft(2f)
|
||||
}
|
||||
|
||||
if (city.isBeingRazed) {
|
||||
val fireImage = ImageGetter.getImage("OtherIcons/Fire")
|
||||
iconTable.add(fireImage).size(20f).padLeft(5f)
|
||||
table.add(fireImage).size(16f).padLeft(2f)
|
||||
}
|
||||
return table
|
||||
|
||||
}
|
||||
|
||||
private fun getIconTable(forPopup: Boolean = false): Table {
|
||||
val secondaryColor = city.civInfo.nation.getInnerColor()
|
||||
val borderColor = if (city.civInfo == worldScreen.viewingCiv)
|
||||
colorFromRGB(233, 233, 172) else Color.BLACK
|
||||
val borderSize = if (city.civInfo == worldScreen.viewingCiv) 4f else 2f /* 7 */
|
||||
|
||||
val iconTable = IconTable(
|
||||
borderColor = borderColor,
|
||||
innerColor = city.civInfo.nation.getOuterColor().cpy().apply { a = 0.9f },
|
||||
borderSize = borderSize
|
||||
).apply {
|
||||
isTransform = false
|
||||
}
|
||||
iconTable.pad(0f).padLeft(5f)
|
||||
iconTable.touchable = Touchable.enabled
|
||||
|
||||
val popGroup = getPopulationGroup(uncivGame.viewEntireMapForDebug
|
||||
|| belongsToViewingCiv()
|
||||
|| worldScreen.viewingCiv.isSpectator())
|
||||
val popGroupCell = iconTable.add(popGroup).minHeight(34f)
|
||||
|
||||
val labelTable = Table()
|
||||
|
||||
if (city.isCapital()) {
|
||||
if (city.civInfo.isCityState()) {
|
||||
val cityStateImage = ImageGetter.getNationIcon("CityState")
|
||||
.apply { color = secondaryColor }
|
||||
iconTable.add(cityStateImage).size(20f).padLeft(5f)
|
||||
.apply { color = secondaryColor }
|
||||
labelTable.add(cityStateImage).size(20f).padRight(5f)
|
||||
} else {
|
||||
val starImage = ImageGetter.getImage("OtherIcons/Star").apply { color = Color.LIGHT_GRAY }
|
||||
iconTable.add(starImage).size(20f).padLeft(5f)
|
||||
val starImage = ImageGetter.getImage("OtherIcons/Capital")
|
||||
labelTable.add(starImage).size(20f).padRight(5f)
|
||||
}
|
||||
} else if (belongsToViewingCiv() && city.isConnectedToCapital()) {
|
||||
val connectionImage = ImageGetter.getStatIcon("CityConnection")
|
||||
connectionImage.color = secondaryColor
|
||||
iconTable.add(connectionImage).size(20f).padLeft(5f)
|
||||
}
|
||||
|
||||
val populationGroup = getPopulationGroup(uncivGame.viewEntireMapForDebug
|
||||
|| belongsToViewingCiv()
|
||||
|| worldScreen.viewingCiv.isSpectator())
|
||||
iconTable.add(populationGroup).padLeft(5f)
|
||||
populationGroup.toBack()
|
||||
val cityButtonText = city.name.tr()
|
||||
val label = cityButtonText.toLabel(secondaryColor).apply { setAlignment(Align.center) }
|
||||
labelTable.add(label).growY().center()
|
||||
|
||||
val cityButtonText = city.name
|
||||
val label = cityButtonText.toLabel(secondaryColor)
|
||||
val rightPadding = if (city.civInfo.isCityState()) 10f else 20f // CS needs less padding here as there will be an icon
|
||||
iconTable.add(label).padRight(rightPadding).padLeft(20f) // sufficient horizontal padding
|
||||
.fillY() // provide full-height clicking area
|
||||
label.toBack() // this is so the label is rendered right before the population group,
|
||||
// so we save the font texture and avoid another texture switch
|
||||
|
||||
val cityStrength = CityCombatant(city).getDefendingStrength()
|
||||
val cityStrengthLabel =
|
||||
"${Fonts.strength}$cityStrength".toLabel(city.civInfo.nation.getInnerColor(), 10)
|
||||
if (!forPopup) {
|
||||
// City strength is added NOT inside the table, but rather - top-center to it
|
||||
iconTable.addActor(cityStrengthLabel) // We create this here to we can .toBack() it as well.
|
||||
cityStrengthLabel.toBack()
|
||||
val cityReligion = city.religion.getMajorityReligion()
|
||||
if (cityReligion != null) {
|
||||
val religionImage = ImageGetter.getReligionImage(cityReligion.getIconName()).apply {
|
||||
color = secondaryColor }.toGroup(20f)
|
||||
labelTable.add(religionImage).size(20f).padLeft(5f)
|
||||
}
|
||||
}
|
||||
|
||||
labelTable.pack()
|
||||
iconTable.add(labelTable).padLeft(10f).padRight(10f).expandY().minHeight(32f).center()
|
||||
label.toFront()
|
||||
|
||||
if (city.civInfo.isCityState()) {
|
||||
val cityStateImage = ImageGetter.getImage("CityStateIcons/" +city.civInfo.cityStateType.name).apply { color = secondaryColor }
|
||||
iconTable.add(cityStateImage).size(20f).fillY()
|
||||
iconTable.padLeft(10f)
|
||||
iconTable.add(cityStateImage).size(20f).fillY().padRight(5f)
|
||||
}
|
||||
|
||||
if (uncivGame.viewEntireMapForDebug || belongsToViewingCiv() || worldScreen.viewingCiv.isSpectator()) {
|
||||
val constructionGroup = getConstructionGroup(city.cityConstructions)
|
||||
iconTable.add(constructionGroup)
|
||||
constructionGroup.toBack() // We do this so the construction group is right before the label.
|
||||
// What we end up with is construction group > label > population group.
|
||||
// Since the label in the construction group is rendered *last* (toFront()),
|
||||
// and the two labels in the the population group are rendered *first* (toBack()),
|
||||
// What we get is that ALL 4 LABELS are rendered one after the other,
|
||||
// and so the glyph texture only needs to be swapped in once rather than 4 times! :)
|
||||
} else if (city.civInfo.isMajorCiv()) {
|
||||
val nationIcon = ImageGetter.getNationIcon(city.civInfo.nation.name)
|
||||
nationIcon.color = secondaryColor
|
||||
iconTable.add(nationIcon).size(20f)
|
||||
}
|
||||
|
||||
if (!forPopup) {
|
||||
val cityReligion = city.religion.getMajorityReligion()
|
||||
if (cityReligion != null) {
|
||||
val religionImage = ImageGetter.getReligionImage(cityReligion.getIconName()).apply { color = city.civInfo.nation.getInnerColor() }
|
||||
iconTable.add(religionImage).size(20f).padLeft(5f).fillY()
|
||||
}
|
||||
iconTable.add(nationIcon).size(20f).padRight(7f)
|
||||
popGroupCell.padLeft(5f)
|
||||
}
|
||||
|
||||
if (city.civInfo == worldScreen.viewingCiv)
|
||||
iconTable.bgBorder.toFront()
|
||||
else
|
||||
iconTable.bgBorder.toBack()
|
||||
iconTable.pack()
|
||||
if (!forPopup) {
|
||||
cityStrengthLabel.x = label.x // so it'll be aligned right above the city name
|
||||
cityStrengthLabel.setY(iconTable.height, Align.top)
|
||||
}
|
||||
return iconTable
|
||||
}
|
||||
|
||||
@ -309,23 +367,20 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
}
|
||||
|
||||
private fun getPopulationGroup(showGrowth: Boolean): Group {
|
||||
val growthGreen = Color(0.0f, 0.5f, 0.0f, 1.0f)
|
||||
|
||||
|
||||
class PopulationGroup:Group() { // for recognition in the profiler
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) }
|
||||
val secondaryColor = city.civInfo.nation.getInnerColor()
|
||||
val table = Table().apply { isTransform = false }
|
||||
val popLabel = city.population.population.toString()
|
||||
.toLabel(fontColor = secondaryColor, fontSize = 18).apply {
|
||||
setAlignment(Align.center)
|
||||
}
|
||||
val group = PopulationGroup().apply { isTransform=false }
|
||||
table.add(popLabel).minHeight(30f).apply {
|
||||
if (showGrowth)
|
||||
minWidth(26f)
|
||||
else
|
||||
minWidth(17f)
|
||||
}.pad(0f)
|
||||
|
||||
val populationLabel = city.population.population.toLabel()
|
||||
populationLabel.color = city.civInfo.nation.getInnerColor()
|
||||
|
||||
group.addActor(populationLabel)
|
||||
|
||||
val groupHeight = 25f
|
||||
var groupWidth = populationLabel.width
|
||||
if (showGrowth) groupWidth += 12f
|
||||
group.setSize(groupWidth, groupHeight)
|
||||
table.pack()
|
||||
|
||||
if (showGrowth) {
|
||||
var growthPercentage = city.population.foodStored / city.population.getFoodToNextPopulation().toFloat()
|
||||
@ -335,83 +390,64 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab
|
||||
// Without it, it caused the growth bar's height to exceed that of the group's.
|
||||
if (growthPercentage > 1) growthPercentage = 1.0f
|
||||
|
||||
val growthBar = ImageGetter.getProgressBarVertical(2f, groupHeight,
|
||||
if (city.isStarving()) 1.0f else growthPercentage,
|
||||
if (city.isStarving()) Color.RED else growthGreen, Color.BLACK)
|
||||
growthBar.x = populationLabel.width + 3
|
||||
growthBar.centerY(group)
|
||||
val growthBar = ImageGetter.getProgressBarVertical(4f, 30f,
|
||||
if (city.isStarving()) 1.0f else growthPercentage,
|
||||
if (city.isStarving()) Color.RED else Colors.growh, Color.BLACK, 1f)
|
||||
growthBar.color.a = 0.8f
|
||||
table.add(growthBar).padTop(1f).padBottom(1f)
|
||||
|
||||
group.addActor(growthBar)
|
||||
|
||||
val turnLabel: Label = when {
|
||||
val turnLabelText = when {
|
||||
city.isGrowing() -> {
|
||||
val turnsToGrowth = city.getNumTurnsToNewPopulation()
|
||||
if (turnsToGrowth != null && turnsToGrowth < 100) turnsToGrowth.toString().toLabel() else "∞".toLabel()
|
||||
if (turnsToGrowth != null && turnsToGrowth < 100) turnsToGrowth.toString() else "∞"
|
||||
}
|
||||
city.isStarving() -> {
|
||||
val turnsToStarvation = city.getNumTurnsToStarvation()
|
||||
if (turnsToStarvation != null && turnsToStarvation < 100) turnsToStarvation.toString().toLabel() else "∞".toLabel()
|
||||
if (turnsToStarvation != null && turnsToStarvation < 100) turnsToStarvation.toString() else "∞"
|
||||
}
|
||||
else -> "∞".toLabel()
|
||||
else -> "∞"
|
||||
}
|
||||
turnLabel.color = city.civInfo.nation.getInnerColor()
|
||||
turnLabel.setFontSize(14)
|
||||
turnLabel.pack()
|
||||
|
||||
group.addActor(turnLabel)
|
||||
turnLabel.toBack() // this is so both labels are rendered next to each other -
|
||||
// this is important because when switching to a label, we switch out the texture we're using to use the font texture,
|
||||
// so this has a direct impact on framerate!
|
||||
turnLabel.x = growthBar.x + growthBar.width + 1
|
||||
val turnLabel = turnLabelText.toLabel(fontColor = secondaryColor, fontSize = 13)
|
||||
table.add(turnLabel).expandY().bottom().padLeft(3f)
|
||||
turnLabel.toBack()
|
||||
}
|
||||
|
||||
populationLabel.centerY(group)
|
||||
|
||||
return group
|
||||
return table
|
||||
}
|
||||
|
||||
private fun getConstructionGroup(cityConstructions: CityConstructions): Group {
|
||||
val secondaryColor = city.civInfo.nation.getInnerColor()
|
||||
val cityCurrentConstruction = cityConstructions.getCurrentConstruction()
|
||||
|
||||
class ConstructionGroup : Group() { // for recognition in the profiler
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) {
|
||||
super.draw(batch, parentAlpha)
|
||||
}
|
||||
}
|
||||
val table = Table().apply { isTransform = false }
|
||||
val tableHeight = 30f
|
||||
|
||||
val group = ConstructionGroup().apply { isTransform = false }
|
||||
val groupHeight = 25f
|
||||
val groupWidth = if (cityCurrentConstruction is PerpetualConstruction) 15f else 40f
|
||||
group.setSize(groupWidth, groupHeight)
|
||||
if (cityConstructions.currentConstructionFromQueue.isNotEmpty()) {
|
||||
val constructionImage = ImageGetter.getPortraitImage(cityCurrentConstruction.name, 25f)
|
||||
constructionImage.centerY(group)
|
||||
constructionImage.x = group.width - constructionImage.width
|
||||
group.addActor(constructionImage)
|
||||
|
||||
if (cityCurrentConstruction !is PerpetualConstruction) {
|
||||
val turnsToConstruction = cityConstructions.turnsToConstruction(cityCurrentConstruction.name)
|
||||
val label = (if (turnsToConstruction < 100) turnsToConstruction.toString() else "∞").toLabel(secondaryColor, 13)
|
||||
|
||||
table.add(label).expandY().bottom().padRight(3f)
|
||||
|
||||
val constructionPercentage = cityConstructions.getWorkDone(cityCurrentConstruction.name) /
|
||||
(cityCurrentConstruction as INonPerpetualConstruction).getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
val productionBar = ImageGetter.getProgressBarVertical(4f, tableHeight, constructionPercentage,
|
||||
Colors.construction, Color.BLACK, 1f)
|
||||
productionBar.color.a = 0.8f
|
||||
|
||||
table.add(productionBar).padTop(1f).padBottom(1f)
|
||||
}
|
||||
|
||||
val constructionImage = ImageGetter.getPortraitImage(cityCurrentConstruction.name, 24f)
|
||||
table.add(constructionImage).minHeight(32f).minWidth(26f)
|
||||
.expand().center().right().pad(0f).padRight(4f).padLeft(3f)
|
||||
table.pack()
|
||||
}
|
||||
|
||||
val secondaryColor = cityConstructions.cityInfo.civInfo.nation.getInnerColor()
|
||||
if (cityCurrentConstruction !is PerpetualConstruction) {
|
||||
val turnsToConstruction = cityConstructions.turnsToConstruction(cityCurrentConstruction.name)
|
||||
val label = (if (turnsToConstruction < 100) turnsToConstruction.toString() else "∞").toLabel(secondaryColor, 14)
|
||||
label.pack()
|
||||
group.addActor(label)
|
||||
|
||||
val constructionPercentage = cityConstructions.getWorkDone(cityCurrentConstruction.name) /
|
||||
(cityCurrentConstruction as INonPerpetualConstruction).getProductionCost(cityConstructions.cityInfo.civInfo).toFloat()
|
||||
val productionBar = ImageGetter.getProgressBarVertical(2f, groupHeight, constructionPercentage,
|
||||
Color.BROWN.brighten(0.5f), Color.BLACK)
|
||||
productionBar.x = 10f
|
||||
label.x = productionBar.x - label.width - 3
|
||||
group.addActor(productionBar)
|
||||
productionBar.toBack() // Since the production bar is based on whiteDot.png in the MAIN texture,
|
||||
// and the constructionImage may be a building or unit which have their own textures,
|
||||
// we move the production bar's rendering to be next to the circle's rendering,
|
||||
// so we have circle - bar - constructionImage - label (2 texture switches and ending with label)
|
||||
// which is the minimal amount of switches we can have here
|
||||
label.toFront()
|
||||
}
|
||||
return group
|
||||
return table
|
||||
}
|
||||
|
||||
private fun foreignCityInfoPopup() {
|
||||
|
@ -1,44 +1,64 @@
|
||||
package com.unciv.ui.utils
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Image
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.ui.utils.extensions.center
|
||||
|
||||
open class BorderedTable(
|
||||
val style: String = BaseScreen.skinStrings.rectangleWithOutlineShape,
|
||||
val path: String = "",
|
||||
val defaultInner: String = BaseScreen.skinStrings.rectangleWithOutlineShape,
|
||||
val defaultBorder: String = BaseScreen.skinStrings.rectangleWithOutlineShape,
|
||||
val borderColor: Color = Color.WHITE,
|
||||
val innerColor: Color = Color.BLACK,
|
||||
val borderSize: Float = 5f
|
||||
val borderSize: Float = 5f,
|
||||
val borderOnTop: Boolean = false
|
||||
) : Table() {
|
||||
|
||||
private var bgBorder: Image = Image(BaseScreen.skinStrings.getUiBackground("", style, Color.WHITE))
|
||||
private var bgInner: Image = Image(BaseScreen.skinStrings.getUiBackground("", style, innerColor))
|
||||
var bgBorder: Image = Image(BaseScreen.skinStrings.getUiBackground(path, defaultBorder, borderColor))
|
||||
var bgInner: Image = Image(BaseScreen.skinStrings.getUiBackground(path, defaultInner, innerColor))
|
||||
|
||||
init {
|
||||
this.addActor(bgBorder)
|
||||
if (borderSize != 0f)
|
||||
this.addActor(bgBorder)
|
||||
this.addActor(bgInner)
|
||||
|
||||
bgInner.toBack()
|
||||
bgBorder.toBack()
|
||||
|
||||
if (borderOnTop) {
|
||||
if (borderSize != 0f)
|
||||
bgBorder.toBack()
|
||||
bgInner.toBack()
|
||||
} else {
|
||||
bgInner.toBack()
|
||||
if (borderSize != 0f)
|
||||
bgBorder.toBack()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setBackgroundColor(color: Color) {
|
||||
bgInner.remove()
|
||||
bgInner = Image(BaseScreen.skinStrings.getUiBackground("", style, color))
|
||||
bgInner = Image(BaseScreen.skinStrings.getUiBackground(path, defaultInner, color))
|
||||
addActor(bgInner)
|
||||
bgInner.zIndex = bgBorder.zIndex + 1
|
||||
if (borderSize != 0f) {
|
||||
if (borderOnTop)
|
||||
bgBorder.zIndex = bgInner.zIndex + 1
|
||||
else
|
||||
bgInner.zIndex = bgBorder.zIndex + 1
|
||||
}
|
||||
sizeChanged()
|
||||
|
||||
}
|
||||
|
||||
override fun sizeChanged() {
|
||||
super.sizeChanged()
|
||||
bgBorder.setSize(width + borderSize, height + borderSize)
|
||||
if (borderSize != 0f)
|
||||
bgBorder.setSize(width + borderSize, height + borderSize)
|
||||
bgInner.setSize(width, height)
|
||||
|
||||
bgBorder.center(this)
|
||||
if (borderSize != 0f)
|
||||
bgBorder.center(this)
|
||||
bgInner.center(this)
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ fun Actor.surroundWithCircle(size: Float, resizeActor: Boolean = true, color: Co
|
||||
return IconCircleGroup(size, this, resizeActor, color)
|
||||
}
|
||||
|
||||
fun Actor.surroundWithThinCircle(color: Color=Color.BLACK): IconCircleGroup = surroundWithCircle(width*1.05f, false, color)
|
||||
fun Actor.surroundWithThinCircle(color: Color=Color.BLACK): IconCircleGroup = surroundWithCircle(width+2f, false, color)
|
||||
|
||||
|
||||
fun Actor.addBorder(size:Float, color: Color, expandCell:Boolean = false): Table {
|
||||
|
@ -676,7 +676,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
||||
- [Aircraft](https://thenounproject.com/search/?q=aircraft&i=1629000) By Tom Fricker for aircraft icon in city button
|
||||
- [radar scan](https://thenounproject.com/search/?q=range&i=1500234) By icon 54 for Range
|
||||
- [short range radar](https://thenounproject.com/search/?q=air%20range&i=2612731) by Vectors Point for Intercept range
|
||||
- [Puppet](https://thenounproject.com/search/?q=puppet&i=285735) By Ben Davis for puppeted cities
|
||||
- Puppet by [vegeta1k95](https://github.com/veget1k95) based on [Puppet](https://thenounproject.com/search/?q=puppet&i=285735) by Ben Davis, for puppeted cities
|
||||
- [City](https://thenounproject.com/search/?q=city&i=1765370) By Muhajir ila Robbi in the Icon center
|
||||
- [Lock](https://thenounproject.com/search/?q=lock&i=3217613) by Vadim Solomakhin for locked tiles
|
||||
- [Hourglass](https://thenounproject.com/search/?q=hourglass&i=142268) by I Create Stuff for the 'Turn' icon
|
||||
|
@ -104,7 +104,6 @@ These shapes are used all over Unciv and can be replaced to make a lot of UI ele
|
||||
| WorldScreen/ | TutorialTaskTable | null | |
|
||||
| WorldScreen/ | UnitTable | null | |
|
||||
| WorldScreen/CityButton/ | AirUnitTable | roundedEdgeRectangle | |
|
||||
| WorldScreen/CityButton/ | IconTable | roundedEdgeRectangle | |
|
||||
| WorldScreen/CityButton/ | InfluenceBar | null | |
|
||||
| WorldScreen/Minimap/ | Background | null | |
|
||||
| WorldScreen/Minimap/ | Border | null | |
|
||||
|