mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-20 19:56:51 +01:00
UI: various improvements mostly relating to centering and WorldScreenTopBar (#12673)
* (rebase) * centering pt. 1 * (rebase) * centering pt. 2 * world screen top bar fixes: – standardise icon-label order – add ad-hoc spacing to the turn count label – add clean and distinctive new style for 'per turn' stats * centering pt. 3 * –final
This commit is contained in:
parent
997648e174
commit
f9e69fb4f0
|
|
@ -58,6 +58,22 @@ object Fonts {
|
|||
.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.localName })
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for v-centering the text of Icon – Label -type components:
|
||||
*
|
||||
* Normal vertical centering uses the entire font height. In reality,
|
||||
* it is customary to align the centre from the baseline to the ascent
|
||||
* with the centre of the other element. This function estimates the
|
||||
* correct amount to shift the text element.
|
||||
*/
|
||||
fun getDescenderHeight(fontSize: Int): Float {
|
||||
val ratio = fontImplementation.getMetrics().run {
|
||||
descent / height }
|
||||
// For whatever reason, undershooting the adjustment slightly
|
||||
// causes rounding to work better
|
||||
return ratio * fontSize.toFloat() + 2.25f
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a TextureRegion into a Pixmap.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
|||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.ui.components.fonts.Fonts
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import kotlin.math.floor
|
||||
import kotlin.math.ceil
|
||||
|
||||
/**
|
||||
* Translate a [String] and make a [Button] widget from it, with control over font size, font colour, an optional icon, and custom formatting.
|
||||
|
|
@ -32,10 +35,15 @@ open class IconTextButton(
|
|||
val size = fontSize.toFloat()
|
||||
icon.setSize(size, size)
|
||||
icon.setOrigin(Align.center)
|
||||
add(icon).size(size).padRight(size / 3)
|
||||
add(icon).size(size).padRight(size / 3.0f)
|
||||
} else {
|
||||
add()
|
||||
add().padRight(fontSize / 2f)
|
||||
}
|
||||
/** Table cell instance containing the [label]. */
|
||||
val labelCell: Cell<Label> = add(label)
|
||||
|
||||
init {
|
||||
pad(10f)
|
||||
labelCell.padTop(10f - Fonts.getDescenderHeight(fontSize));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ import com.badlogic.gdx.graphics.Color
|
|||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Container
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.extensions.darken
|
||||
|
|
@ -198,20 +200,13 @@ class WorldScreenTopBar(internal val worldScreen: WorldScreen) : Table() {
|
|||
private var selectedCivIcon = Group()
|
||||
private val selectedCivIconCell: Cell<Group>
|
||||
private val selectedCivLabel = "".toLabel()
|
||||
|
||||
private val menuButton = ImageGetter.getImage("OtherIcons/MenuIcon")
|
||||
private val menuButtonWrapper = Container(menuButton)
|
||||
|
||||
init {
|
||||
// vertically align the Nation name by ascender height without descender:
|
||||
// Normal vertical centering uses the entire font height, but that looks off here because there's
|
||||
// few descenders in the typical Nation name. So we calculate an estimate of the descender height
|
||||
// in world coordinates (25 is the Label font size set below), then, since the cells themselves
|
||||
// have no default padding, we remove that much padding from the top of this entire Table, and
|
||||
// give the Label that much top padding in return. Approximated since we're ignoring 'leading'.
|
||||
val descenderHeight = Fonts.fontImplementation.getMetrics().run { descent / height } * 25f
|
||||
|
||||
left()
|
||||
pad(10f)
|
||||
padTop((10f - descenderHeight).coerceAtLeast(0f))
|
||||
|
||||
menuButton.color = Color.WHITE
|
||||
menuButton.onActivation(binding = KeyboardBinding.Menu) { WorldScreenMenuPopup(worldScreen) }
|
||||
|
|
@ -221,13 +216,17 @@ class WorldScreenTopBar(internal val worldScreen: WorldScreen) : Table() {
|
|||
worldScreen.openCivilopedia(worldScreen.selectedCiv.nation.makeLink())
|
||||
}
|
||||
|
||||
selectedCivLabel.setFontSize(25)
|
||||
selectedCivLabel.setFontSize(Constants.headingFontSize)
|
||||
selectedCivLabel.onClick(onNationClick)
|
||||
selectedCivIcon.onClick(onNationClick)
|
||||
|
||||
add(menuButton).size(50f)
|
||||
selectedCivIconCell = add(selectedCivIcon).padLeft(10f)
|
||||
add(selectedCivLabel).padTop(descenderHeight)
|
||||
menuButtonWrapper.size(Constants.headingFontSize * 1.5f);
|
||||
menuButtonWrapper.center()
|
||||
add(menuButtonWrapper)
|
||||
|
||||
selectedCivIconCell = add(selectedCivIcon).padLeft(Constants.defaultFontSize / 1.5f)
|
||||
add(selectedCivLabel).padTop(10f - Fonts.getDescenderHeight(Constants.headingFontSize))
|
||||
.padLeft(Constants.defaultFontSize / 2.0f)
|
||||
pack()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ internal class WorldScreenTopBarResources(topbar: WorldScreenTopBar) : ScalingTa
|
|||
val yearText = YearTextUtil.toYearText(
|
||||
civInfo.gameInfo.getYear(), civInfo.isLongCountDisplay()
|
||||
)
|
||||
turnsLabel.setText(Fonts.turn + "" + civInfo.gameInfo.turns.tr() + " | " + yearText)
|
||||
turnsLabel.setText(Fonts.turn + " " + civInfo.gameInfo.turns.tr() + " | " + yearText)
|
||||
|
||||
resourcesWrapper.clearChildren()
|
||||
val civResources = civInfo.getCivResourcesByName()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package com.unciv.ui.screens.worldscreen.topbar
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.civilization.Civilization
|
||||
import com.unciv.models.stats.Stats
|
||||
import com.unciv.models.translations.tr
|
||||
|
|
@ -22,11 +24,18 @@ import kotlin.math.ceil
|
|||
import kotlin.math.roundToInt
|
||||
|
||||
internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableWrapper() {
|
||||
private val goldLabel = "0".toLabel(colorFromRGB(225, 217, 71))
|
||||
private val scienceLabel = "0".toLabel(colorFromRGB(78, 140, 151))
|
||||
|
||||
private val goldLabel = "0".toLabel(colorFromRGB(225, 217, 71)) // #ed1947
|
||||
private val goldPerTurnLabel = "+0"
|
||||
.toLabel(colorFromRGB(225, 217, 71), 12)
|
||||
|
||||
private val scienceLabel = "0".toLabel(colorFromRGB(78, 140, 151)) // #4e8c97
|
||||
private val happinessLabel = "0".toLabel()
|
||||
private val cultureLabel = "0".toLabel(colorFromRGB(210, 94, 210))
|
||||
private val faithLabel = "0".toLabel(colorFromRGB(168, 196, 241))
|
||||
private val cultureLabel = "0".toLabel(colorFromRGB(210, 94, 210)) // #d25ed2
|
||||
|
||||
private val faithLabel = "0".toLabel(colorFromRGB(168, 196, 241)) // #a8c4f1
|
||||
private val faithPerTurnLabel = "+0"
|
||||
.toLabel(colorFromRGB(168, 196, 241), 12)
|
||||
|
||||
private val happinessContainer = Group()
|
||||
|
||||
|
|
@ -51,8 +60,14 @@ internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableW
|
|||
init {
|
||||
isTransform = false
|
||||
|
||||
|
||||
fun addStat(label: Label, icon: String, isLast: Boolean = false, screenFactory: ()-> BaseScreen?) {
|
||||
defaults().pad(defaultTopPad, defaultHorizontalPad, defaultBottomPad, defaultHorizontalPad)
|
||||
|
||||
fun addStat(
|
||||
icon: String,
|
||||
label: Label,
|
||||
noPad: Boolean = false,
|
||||
screenFactory: () -> BaseScreen?
|
||||
) {
|
||||
val image = ImageGetter.getStatIcon(icon)
|
||||
val action = {
|
||||
val screen = screenFactory()
|
||||
|
|
@ -60,47 +75,59 @@ internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableW
|
|||
}
|
||||
label.onClick(action)
|
||||
image.onClick(action)
|
||||
add(label)
|
||||
add(image).padBottom(defaultImageBottomPad).size(defaultImageSize).apply {
|
||||
if (!isLast) padRight(padRightBetweenStats)
|
||||
}
|
||||
add(image).padBottom(defaultImageBottomPad).size(defaultImageSize)
|
||||
add(label).padRight(if (noPad) 0f else padRightBetweenStats)
|
||||
}
|
||||
|
||||
fun addStat(label: Label, icon: String, overviewPage: EmpireOverviewCategories, isLast: Boolean = false) =
|
||||
addStat(label, icon, isLast) { EmpireOverviewScreen(worldScreen.selectedCiv, overviewPage) }
|
||||
fun addStat(
|
||||
icon: String,
|
||||
label: Label,
|
||||
overviewPage: EmpireOverviewCategories,
|
||||
noPad: Boolean = false
|
||||
) = addStat(icon, label, noPad) {
|
||||
EmpireOverviewScreen(worldScreen.selectedCiv, overviewPage)
|
||||
}
|
||||
|
||||
defaults().pad(defaultTopPad, defaultHorizontalPad, defaultBottomPad, defaultHorizontalPad)
|
||||
addStat(goldLabel, "Gold", EmpireOverviewCategories.Stats)
|
||||
addStat(scienceLabel, "Science") { TechPickerScreen(worldScreen.selectedCiv) }
|
||||
fun addPerTurnLabel(label: Label) {
|
||||
add(label).padRight(padRightBetweenStats)
|
||||
.height(Constants.defaultFontSize.toFloat()).top()
|
||||
}
|
||||
|
||||
|
||||
addStat("Gold", goldLabel, EmpireOverviewCategories.Stats, true)
|
||||
addPerTurnLabel(goldPerTurnLabel);
|
||||
|
||||
addStat("Science", scienceLabel) { TechPickerScreen(worldScreen.selectedCiv) }
|
||||
|
||||
add(happinessContainer).padBottom(defaultImageBottomPad).size(defaultImageSize)
|
||||
add(happinessLabel).padRight(padRightBetweenStats)
|
||||
val invokeResourcesPage = {
|
||||
worldScreen.openEmpireOverview(EmpireOverviewCategories.Resources)
|
||||
}
|
||||
happinessContainer.onClick(invokeResourcesPage)
|
||||
happinessLabel.onClick(invokeResourcesPage)
|
||||
add(happinessContainer).padBottom(defaultImageBottomPad).size(defaultImageSize)
|
||||
add(happinessLabel).padRight(padRightBetweenStats)
|
||||
|
||||
addStat(cultureLabel, "Culture") {
|
||||
addStat("Culture", cultureLabel) {
|
||||
if (worldScreen.gameInfo.ruleset.policyBranches.isEmpty()) null
|
||||
else PolicyPickerScreen(worldScreen.selectedCiv, worldScreen.canChangeState)
|
||||
}
|
||||
|
||||
if (worldScreen.gameInfo.isReligionEnabled()) {
|
||||
addStat(faithLabel, "Faith", EmpireOverviewCategories.Religion, isLast = true)
|
||||
} else {
|
||||
add("Religion: Off".toLabel())
|
||||
}
|
||||
addStat("Faith", faithLabel, EmpireOverviewCategories.Religion, true)
|
||||
addPerTurnLabel(faithPerTurnLabel)
|
||||
} else add("Religion: Off".toLabel())
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private fun rateLabel(value: Float) = value.roundToInt().toStringSigned()
|
||||
|
||||
fun update(civInfo: Civilization) {
|
||||
resetScale()
|
||||
|
||||
val nextTurnStats = civInfo.stats.statsForNextTurn
|
||||
val goldPerTurn = " (" + rateLabel(nextTurnStats.gold) + ")"
|
||||
goldLabel.setText(civInfo.gold.tr() + goldPerTurn)
|
||||
|
||||
goldLabel.setText(civInfo.gold.tr())
|
||||
goldPerTurnLabel.setText(rateLabel(nextTurnStats.gold))
|
||||
|
||||
scienceLabel.setText(rateLabel(nextTurnStats.science))
|
||||
|
||||
|
|
@ -117,9 +144,9 @@ internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableW
|
|||
}
|
||||
|
||||
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
|
||||
faithLabel.setText(
|
||||
civInfo.religionManager.storedFaith.tr() + " (" + rateLabel(nextTurnStats.faith) + ")"
|
||||
)
|
||||
|
||||
faithLabel.setText(civInfo.religionManager.storedFaith.tr())
|
||||
faithPerTurnLabel.setText(rateLabel(nextTurnStats.faith))
|
||||
|
||||
scaleTo(worldScreen.stage.width)
|
||||
}
|
||||
|
|
@ -129,9 +156,9 @@ internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableW
|
|||
// kotlin Float division by Zero produces `Float.POSITIVE_INFINITY`, not an exception
|
||||
val turnsToNextPolicy = (civInfo.policies.getCultureNeededForNextPolicy() - civInfo.policies.storedCulture) / nextTurnStats.culture
|
||||
cultureString += when {
|
||||
turnsToNextPolicy <= 0f -> " (!)" // Can choose policy right now
|
||||
nextTurnStats.culture <= 0 -> " (${Fonts.infinity})" // when you start the game, you're not producing any culture
|
||||
else -> " (" + ceil(turnsToNextPolicy).toInt().tr() + ")"
|
||||
turnsToNextPolicy <= 0f -> " (!)" // Can choose policy right now
|
||||
nextTurnStats.culture <= 0 -> " (${Fonts.infinity})" // when you start the game, you're not producing any culture
|
||||
else -> " (" + Fonts.turn + " " + ceil(turnsToNextPolicy).toInt().tr() + ")"
|
||||
}
|
||||
return cultureString
|
||||
}
|
||||
|
|
@ -146,4 +173,8 @@ internal class WorldScreenTopBarStats(topbar: WorldScreenTopBar) : ScalingTableW
|
|||
" (${goldenAges.storedHappiness.tr()}/${goldenAges.happinessRequiredForNextGoldenAge().tr()})"
|
||||
return happinessText
|
||||
}
|
||||
|
||||
private fun rateLabel(value: Float): String {
|
||||
return if (value.roundToInt() == 0) "±0" else value.roundToInt().toStringSigned()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user