diff --git a/core/src/com/unciv/ui/components/ColorMarkupLabel.kt b/core/src/com/unciv/ui/components/ColorMarkupLabel.kt new file mode 100644 index 0000000000..ef2fcf0631 --- /dev/null +++ b/core/src/com/unciv/ui/components/ColorMarkupLabel.kt @@ -0,0 +1,107 @@ +@file:Suppress("unused") + +package com.unciv.ui.components + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.scenes.scene2d.ui.Label +import com.unciv.Constants +import com.unciv.models.translations.tr +import com.unciv.ui.screens.basescreen.BaseScreen + +/** A Label allowing Gdx markup + * + * See also [Color Markup Language](https://libgdx.com/wiki/graphics/2d/fonts/color-markup-language) + */ +class ColorMarkupLabel private constructor( + fontSize: Int, // inverted order so it can be differentiated from the translating constructor + text: String, +) : Label(text, BaseScreen.skin) { + + /** A Label allowing Gdx markup, auto-translated. + * + * Since Gdx markup markers are interpreted and removed by translation, use «» instead. + */ + constructor(text: String, fontSize: Int = Constants.defaultFontSize) + : this(fontSize, mapMarkup(text)) + + /** A Label automatically applying Gdx markup colors to symbols and rest of text separately + * - _after_ translating [text]. + */ + constructor(text: String, + textColor: Color, + symbolColor: Color = Color.WHITE, + fontSize: Int = Constants.defaultFontSize) + : this (fontSize, prepareText(text, textColor, symbolColor)) + + private val originalMarkupEnabled: Boolean + + init { + if (fontSize != Constants.defaultFontSize) { + val labelStyle = LabelStyle(style) // clone otherwise all default-styled Labels affected + style = labelStyle + style.font = Fonts.font + setFontScale(fontSize / Fonts.ORIGINAL_FONT_SIZE) + } + originalMarkupEnabled = style.font.data.markupEnabled + } + + override fun layout() { + style.font.data.markupEnabled = true + super.layout() + style.font.data.markupEnabled = originalMarkupEnabled + } + + companion object { + private fun mapMarkup(text: String): String { + val translated = text.tr() + if ('«' !in translated) return translated + return translated.replace('«', '[').replace('»', ']') + } + + private fun Color.toMarkup() = when { + this == Color.CLEAR -> "CLEAR" + this == Color.BLACK -> "BLACK" + this == Color.BLUE -> "BLUE" + this == Color.CYAN -> "CYAN" + this == Color.GOLD -> "GOLD" + this == Color.GRAY -> "GRAY" + this == Color.GREEN -> "GREEN" + this == Color.LIME -> "LIME" + this == Color.NAVY -> "NAVY" + this == Color.PINK -> "PINK" + this == Color.RED -> "RED" + this == Color.SKY -> "SKY" + this == Color.TAN -> "TAN" + this == Color.TEAL -> "TEAL" + this == Color.WHITE -> "WHITE" + a < 1f -> "#" + toString() + else -> "#" + toString().substring(0,6) + } + + private fun prepareText(text: String, textColor: Color, symbolColor: Color): String { + val translated = text.tr() + if (textColor == Color.WHITE && symbolColor == Color.WHITE || translated.isBlank()) + return translated + val tc = textColor.toMarkup() + if (textColor == symbolColor) + return "[$tc]$translated[]" + val sc = symbolColor.toMarkup() + + val sb = StringBuilder(translated.length + 42) + var currentColor = ' ' + for (char in translated) { + val newColor = if (char in Fonts.allSymbols) 'S' else 'T' + if (newColor != currentColor) { + if (currentColor != ' ') sb.append("[]") + sb.append('[') + sb.append((if (newColor == 'S') sc else tc).toString()) + sb.append(']') + currentColor = newColor + } + sb.append(char) + } + if (currentColor != ' ') sb.append("[]") + return sb.toString() + } + } +} diff --git a/core/src/com/unciv/ui/components/Fonts.kt b/core/src/com/unciv/ui/components/Fonts.kt index f5ee5a8812..183c1f2771 100644 --- a/core/src/com/unciv/ui/components/Fonts.kt +++ b/core/src/com/unciv/ui/components/Fonts.kt @@ -249,4 +249,13 @@ object Fonts { const val greatMerchant = '⚖' // U+2696 'scale' const val greatScientist = '⚛' // U+269B 'atom' const val death = '☠' // U+2620 'skull and crossbones' + + val allSymbols = arrayOf( + turn, + strength, rangedStrength, range, movement, + production, gold, food, science, culture, happiness, faith, + greatArtist, greatEngineer, greatGeneral, greatMerchant, greatScientist, + death, + *MayaCalendar.allSymbols + ) } diff --git a/core/src/com/unciv/ui/components/MayaCalendar.kt b/core/src/com/unciv/ui/components/MayaCalendar.kt index d154699823..0150481a83 100644 --- a/core/src/com/unciv/ui/components/MayaCalendar.kt +++ b/core/src/com/unciv/ui/components/MayaCalendar.kt @@ -30,6 +30,15 @@ object MayaCalendar { val digits = zero..nineteen fun digitIcon(ch: Char) = iconFolder + (ch.toCode() - zero.toCode()).toString() + val allSymbols = sequence { + yield(tun) + yield(katun) + yield(baktun) + yieldAll(digits) + }.iterator().run { + Array(23) { next() } + } + // Calculation private const val daysOn30000101BCE = 36000 + 5040 + 240 + 11 diff --git a/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt b/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt index 2b7dd5d211..bb4b25ea2c 100644 --- a/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt @@ -29,6 +29,7 @@ import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags +import com.unciv.ui.components.ColorMarkupLabel import com.unciv.ui.components.Fonts import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.UncivTooltip.Companion.addTooltip @@ -266,12 +267,12 @@ class DiplomacyScreen( } val friendBonusLabelColor = if (relationLevel == RelationshipLevel.Friend) Color.GREEN else Color.GRAY - val friendBonusLabel = friendBonusText.toLabel(friendBonusLabelColor) + val friendBonusLabel = ColorMarkupLabel(friendBonusText, friendBonusLabelColor) .apply { setAlignment(Align.center) } diplomacyTable.add(friendBonusLabel).row() val allyBonusLabelColor = if (relationLevel == RelationshipLevel.Ally) Color.GREEN else Color.GRAY - val allyBonusLabel = allyBonusText.toLabel(allyBonusLabelColor) + val allyBonusLabel = ColorMarkupLabel(allyBonusText, allyBonusLabelColor) .apply { setAlignment(Align.center) } diplomacyTable.add(allyBonusLabel).row() diff --git a/core/src/com/unciv/ui/screens/worldscreen/NotificationsScroll.kt b/core/src/com/unciv/ui/screens/worldscreen/NotificationsScroll.kt index 3ddc8a148d..399f8e1175 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/NotificationsScroll.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/NotificationsScroll.kt @@ -7,6 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.logic.civilization.Notification import com.unciv.logic.civilization.NotificationCategory +import com.unciv.ui.components.ColorMarkupLabel import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.components.WrappableLabel @@ -81,7 +82,7 @@ class NotificationsScroll( add(ImageGetter.getWhiteDot()).minHeight(2f).width(worldScreen.stage.width/8) add(Table().apply { background = backgroundDrawable - add(category.name.toLabel(fontSize = 30, fontColor = Color.BLACK)) + add(ColorMarkupLabel(category.name, Color.BLACK, fontSize = 30)) }).pad(3f) add(ImageGetter.getWhiteDot()).minHeight(2f).width(worldScreen.stage.width/8) }).row()