diff --git a/android/src/com/unciv/app/AndroidFont.kt b/android/src/com/unciv/app/AndroidFont.kt index cf1392ec17..6f53457406 100644 --- a/android/src/com/unciv/app/AndroidFont.kt +++ b/android/src/com/unciv/app/AndroidFont.kt @@ -12,10 +12,10 @@ import android.os.Build import androidx.annotation.RequiresApi import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Pixmap -import com.unciv.ui.components.FontFamilyData -import com.unciv.ui.components.FontImplementation -import com.unciv.ui.components.FontMetricsCommon -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.FontFamilyData +import com.unciv.ui.components.fonts.FontImplementation +import com.unciv.ui.components.fonts.FontMetricsCommon +import com.unciv.ui.components.fonts.Fonts import com.unciv.utils.Log import java.util.Locale import kotlin.math.abs diff --git a/android/src/com/unciv/app/AndroidLauncher.kt b/android/src/com/unciv/app/AndroidLauncher.kt index 1a91087a3c..6f944b8e33 100644 --- a/android/src/com/unciv/app/AndroidLauncher.kt +++ b/android/src/com/unciv/app/AndroidLauncher.kt @@ -7,7 +7,7 @@ import androidx.work.WorkManager import com.badlogic.gdx.backends.android.AndroidApplication import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration import com.unciv.logic.files.UncivFiles -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.utils.Display import com.unciv.utils.Log import java.io.File diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index 6786c5adf5..fc154de2f3 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -25,8 +25,8 @@ import com.unciv.ui.audio.MusicController import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags import com.unciv.ui.audio.SoundPlayer -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.center +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.crashhandling.CrashScreen import com.unciv.ui.crashhandling.wrapCrashHandlingUnit import com.unciv.ui.images.ImageGetter @@ -50,10 +50,10 @@ import com.unciv.utils.debug import com.unciv.utils.launchOnGLThread import com.unciv.utils.withGLContext import com.unciv.utils.withThreadPoolContext -import kotlinx.coroutines.CancellationException import java.io.PrintWriter import java.util.EnumSet import java.util.UUID +import kotlinx.coroutines.CancellationException import kotlin.system.exitProcess object GUI { diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index c260297d6c..a6539a0190 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -30,10 +30,9 @@ import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.extensions.addToMapOfSets import com.unciv.ui.components.extensions.withItem import com.unciv.ui.components.extensions.withoutItem +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.CivilopediaCategories import com.unciv.ui.screens.civilopediascreen.FormattedLine import kotlin.math.ceil diff --git a/core/src/com/unciv/logic/map/tile/TileDescription.kt b/core/src/com/unciv/logic/map/tile/TileDescription.kt index c523145ccd..80aa93c424 100644 --- a/core/src/com/unciv/logic/map/tile/TileDescription.kt +++ b/core/src/com/unciv/logic/map/tile/TileDescription.kt @@ -4,8 +4,8 @@ import com.unciv.Constants import com.unciv.logic.civilization.Civilization import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.toStringSigned +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.FormattedLine import com.unciv.utils.DebugUtils diff --git a/core/src/com/unciv/logic/trade/TradeOffer.kt b/core/src/com/unciv/logic/trade/TradeOffer.kt index 8fd043e797..c233e5013b 100644 --- a/core/src/com/unciv/logic/trade/TradeOffer.kt +++ b/core/src/com/unciv/logic/trade/TradeOffer.kt @@ -6,7 +6,7 @@ import com.unciv.logic.IsPartOfGameInfoSerialization import com.unciv.logic.trade.TradeType.TradeTypeNumberType import com.unciv.models.ruleset.Speed import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts data class TradeOffer(val name: String, val type: TradeType, var amount: Int = 1, var duration: Int) : IsPartOfGameInfoSerialization { diff --git a/core/src/com/unciv/models/UnitAction.kt b/core/src/com/unciv/models/UnitAction.kt index 277959a33e..32fbf2317b 100644 --- a/core/src/com/unciv/models/UnitAction.kt +++ b/core/src/com/unciv/models/UnitAction.kt @@ -4,7 +4,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor import com.unciv.Constants import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.translations.getPlaceholderParameters -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index e3b9ab5a99..54149b13ab 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -7,8 +7,8 @@ import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.multiplayer.FriendList import com.unciv.models.UncivSound -import com.unciv.ui.components.FontFamilyData -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.FontFamilyData +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyboardBindings import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories import com.unciv.utils.Display diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index f77d740ff0..a223208e9c 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -17,10 +17,10 @@ import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.getConsumesAmountString import com.unciv.ui.components.extensions.getNeedMoreAmountString import com.unciv.ui.components.extensions.toPercent +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.FormattedLine diff --git a/core/src/com/unciv/models/ruleset/IConstruction.kt b/core/src/com/unciv/models/ruleset/IConstruction.kt index f2f4d78489..82cf6243c0 100644 --- a/core/src/com/unciv/models/ruleset/IConstruction.kt +++ b/core/src/com/unciv/models/ruleset/IConstruction.kt @@ -10,8 +10,8 @@ import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.INamed import com.unciv.models.stats.Stat -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.toPercent +import com.unciv.ui.components.fonts.Fonts import kotlin.math.pow import kotlin.math.roundToInt diff --git a/core/src/com/unciv/models/ruleset/Speed.kt b/core/src/com/unciv/models/ruleset/Speed.kt index 128487ff0c..1e6d026c3a 100644 --- a/core/src/com/unciv/models/ruleset/Speed.kt +++ b/core/src/com/unciv/models/ruleset/Speed.kt @@ -4,8 +4,8 @@ import com.unciv.logic.IsPartOfGameInfoSerialization import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.stats.Stat import com.unciv.models.translations.tr +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.FormattedLine -import com.unciv.ui.components.Fonts import kotlin.math.abs class Speed : RulesetObject(), IsPartOfGameInfoSerialization { diff --git a/core/src/com/unciv/models/ruleset/nation/Difficulty.kt b/core/src/com/unciv/models/ruleset/nation/Difficulty.kt index 564c8a175e..2f862aad2b 100644 --- a/core/src/com/unciv/models/ruleset/nation/Difficulty.kt +++ b/core/src/com/unciv/models/ruleset/nation/Difficulty.kt @@ -3,9 +3,9 @@ package com.unciv.models.ruleset.nation import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.unique.Unique import com.unciv.models.stats.INamed +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.FormattedLine import com.unciv.ui.screens.civilopediascreen.ICivilopediaText -import com.unciv.ui.components.Fonts class Difficulty: INamed, ICivilopediaText { override lateinit var name: String diff --git a/core/src/com/unciv/models/ruleset/tech/Era.kt b/core/src/com/unciv/models/ruleset/tech/Era.kt index 521ed2e4eb..12df54eabb 100644 --- a/core/src/com/unciv/models/ruleset/tech/Era.kt +++ b/core/src/com/unciv/models/ruleset/tech/Era.kt @@ -8,8 +8,8 @@ import com.unciv.models.ruleset.RulesetObject import com.unciv.models.ruleset.unique.StateForConditionals import com.unciv.models.ruleset.unique.UniqueTarget import com.unciv.models.ruleset.unique.UniqueType -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.colorFromRGB +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.civilopediascreen.FormattedLine class Era : RulesetObject() { diff --git a/core/src/com/unciv/models/stats/Stat.kt b/core/src/com/unciv/models/stats/Stat.kt index c10d78b94d..fba2e3e29e 100644 --- a/core/src/com/unciv/models/stats/Stat.kt +++ b/core/src/com/unciv/models/stats/Stat.kt @@ -3,8 +3,8 @@ package com.unciv.models.stats import com.badlogic.gdx.graphics.Color import com.unciv.logic.civilization.NotificationIcon import com.unciv.models.UncivSound -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.colorFromHex +import com.unciv.ui.components.fonts.Fonts enum class Stat( val notificationIcon: String, diff --git a/core/src/com/unciv/models/translations/Translations.kt b/core/src/com/unciv/models/translations/Translations.kt index 46054d9703..c9425f6bdd 100644 --- a/core/src/com/unciv/models/translations/Translations.kt +++ b/core/src/com/unciv/models/translations/Translations.kt @@ -7,7 +7,7 @@ import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.unique.Unique import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.FontRulesetIcons import com.unciv.utils.Log import com.unciv.utils.debug import java.util.Locale @@ -427,8 +427,8 @@ fun String.tr(hideIcons: Boolean = false): String { val stat = Stat.safeValueOf(this) if (stat != null) return stat.character + translation - if (!hideIcons && Fonts.rulesetObjectNameToChar.containsKey(this)) - return Fonts.rulesetObjectNameToChar[this]!! + translation + if (!hideIcons && FontRulesetIcons.rulesetObjectNameToChar.containsKey(this)) + return FontRulesetIcons.rulesetObjectNameToChar[this]!! + translation return translation } diff --git a/core/src/com/unciv/ui/components/Fonts.kt b/core/src/com/unciv/ui/components/Fonts.kt deleted file mode 100644 index e4081565cd..0000000000 --- a/core/src/com/unciv/ui/components/Fonts.kt +++ /dev/null @@ -1,501 +0,0 @@ -package com.unciv.ui.components - -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.graphics.Color -import com.badlogic.gdx.graphics.GL20 -import com.badlogic.gdx.graphics.Pixmap -import com.badlogic.gdx.graphics.Texture -import com.badlogic.gdx.graphics.g2d.BitmapFont -import com.badlogic.gdx.graphics.g2d.BitmapFont.BitmapFontData -import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph -import com.badlogic.gdx.graphics.g2d.GlyphLayout -import com.badlogic.gdx.graphics.g2d.PixmapPacker -import com.badlogic.gdx.graphics.g2d.SpriteBatch -import com.badlogic.gdx.graphics.g2d.TextureRegion -import com.badlogic.gdx.graphics.glutils.FrameBuffer -import com.badlogic.gdx.math.Matrix4 -import com.badlogic.gdx.scenes.scene2d.Actor -import com.badlogic.gdx.scenes.scene2d.Group -import com.badlogic.gdx.utils.Array -import com.badlogic.gdx.utils.Disposable -import com.unciv.Constants -import com.unciv.GUI -import com.unciv.UncivGame -import com.unciv.models.ruleset.Ruleset -import com.unciv.models.translations.tr -import com.unciv.ui.components.extensions.getReadonlyPixmap -import com.unciv.ui.components.extensions.setSize -import com.unciv.ui.images.ImageGetter -import com.unciv.ui.images.Portrait -import kotlin.math.ceil -import kotlin.math.roundToInt - - -// See https://en.wikipedia.org/wiki/Private_Use_Areas -// char encodings 57344 to 63743 (U+E000-U+F8FF) are not assigned -private const val UNUSED_CHARACTER_CODES_START = 57344 -private const val UNUSED_CHARACTER_CODES_END = 63743 - -/** Implementations of FontImplementation will use different FontMetrics - AWT or Android.Paint, - * both have a class of that name, no other common point: thus we create an abstraction. - * - * This is used by [Fonts.getPixmapFromActor] for vertical positioning. - */ -class FontMetricsCommon( - /** (positive) distance from the baseline up to the recommended top of normal text */ - val ascent: Float, - /** (positive) distance from the baseline down to the recommended bottom of normal text */ - val descent: Float, - /** (positive) maximum distance from top to bottom of any text, - * including potentially empty space above ascent or below descent */ - val height: Float, - /** (positive) distance from the bounding box top (as defined by [height]) - * to the highest possible top of any text */ - - // Note: This is NOT what typographical leading actually is, but redefined as extra empty space - // on top, to make it easier to sync desktop and android. AWT has some leading but no measures - // outside ascent+descent+leading, while Android has its leading always 0 but typically top - // above ascent and bottom below descent. - // I chose to map AWT's spacing to the top as I found the calculations easier to visualize. - /** Space from the bounding box top to the top of the ascenders - includes line spacing and - * room for unusually high ascenders, as [ascent] is only a recommendation. */ - val leading: Float -) - -interface FontImplementation { - fun setFontFamily(fontFamilyData: FontFamilyData, size: Int) - fun getFontSize(): Int - fun getCharPixmap(char: Char): Pixmap - fun getSystemFonts(): Sequence - - fun getBitmapFont(): BitmapFont { - val fontData = NativeBitmapFontData(this) - val font = BitmapFont(fontData, fontData.regions, false) - font.setOwnsTexture(true) - return font - } - - fun getMetrics(): FontMetricsCommon -} - -// If save in `GameSettings` need use invariantFamily. -// If show to user need use localName. -// If save localName in `GameSettings` may generate garbled characters by encoding. -class FontFamilyData( - val localName: String, - val invariantName: String = localName, - val filePath: String? = null -) { - - @Suppress("unused") // For serialization - constructor() : this(default.localName, default.invariantName) - - // Implement kotlin equality contract such that _only_ the invariantName field is compared. - override fun equals(other: Any?): Boolean { - return if (other is FontFamilyData) invariantName == other.invariantName - else super.equals(other) - } - - override fun hashCode() = invariantName.hashCode() - - /** For SelectBox usage */ - override fun toString() = localName.tr() - - companion object { - val default = FontFamilyData("Default Font", Fonts.DEFAULT_FONT_FAMILY) - } -} - -// This class is loosely based on libgdx's FreeTypeBitmapFontData -class NativeBitmapFontData( - private val fontImplementation: FontImplementation -) : BitmapFontData(), Disposable { - - val regions: Array - - private var dirty = false - private val packer: PixmapPacker - - private val filter = Texture.TextureFilter.Linear - - private companion object { - /** How to get the alpha channel in a Pixmap.getPixel return value (Int) - it's the LSB */ - const val alphaChannelMask = 255 - /** Where to test circle for transparency */ - // The center of a squared circle's corner wedge would be at (1-PI/4)/2 ≈ 0.1073 - const val nearCornerRelativeOffset = 0.1f - /** Where to test circle for opacity */ - // arbitrary choice just off-center - const val nearCenterRelativeOffset = 0.4f - /** Width multiplier to get extra advance after a ruleset icon, empiric */ - const val relativeAdvanceExtra = 0.039f - /** Multiplier to get default kerning between a ruleset icon and 'open' characters */ - const val relativeKerning = -0.055f - /** Which follower characters receive how much kerning relative to [relativeKerning] */ - val kerningMap = mapOf('A' to 1f, 'T' to 0.6f, 'V' to 1f, 'Y' to 1.2f) - } - - init { - // set general font data - flipped = false - lineHeight = fontImplementation.getFontSize().toFloat() - capHeight = lineHeight - ascent = -lineHeight - down = -lineHeight - - // Create a packer. - val size = 1024 - val packStrategy = PixmapPacker.GuillotineStrategy() - packer = PixmapPacker(size, size, Pixmap.Format.RGBA8888, 1, false, packStrategy) - packer.transparentColor = Color.WHITE - packer.transparentColor.a = 0f - - // Generate texture regions. - regions = Array() - packer.updateTextureRegions(regions, filter, filter, false) - - // Set space glyph. - val spaceGlyph = getGlyph(' ') - spaceXadvance = spaceGlyph.xadvance.toFloat() - - setScale(Constants.defaultFontSize / Fonts.ORIGINAL_FONT_SIZE) - } - - override fun getGlyph(ch: Char): Glyph = super.getGlyph(ch) ?: createAndCacheGlyph(ch) - - private fun createAndCacheGlyph(ch: Char): Glyph { - val charPixmap = getPixmapFromChar(ch) - - val glyph = Glyph() - glyph.id = ch.code - glyph.width = charPixmap.width - glyph.height = charPixmap.height - glyph.xadvance = glyph.width - - // Check alpha to guess whether this is a round icon - // Needs to be done before disposing charPixmap, and we want to do that soon - val assumeRoundIcon = charPixmap.guessIsRoundSurroundedByTransparency() - - val rect = packer.pack(charPixmap) - charPixmap.dispose() - glyph.page = packer.pages.size - 1 // Glyph is always packed into the last page for now. - glyph.srcX = rect.x.toInt() - glyph.srcY = rect.y.toInt() - - if (ch.code >= UNUSED_CHARACTER_CODES_START) - glyph.setRulesetIconGeometry(assumeRoundIcon) - - // If a page was added, create a new texture region for the incrementally added glyph. - if (regions.size <= glyph.page) - packer.updateTextureRegions(regions, filter, filter, false) - - setGlyphRegion(glyph, regions.get(glyph.page)) - setGlyph(ch.code, glyph) - dirty = true - - return glyph - } - - private fun Pixmap.guessIsRoundSurroundedByTransparency(): Boolean { - // If a pixel near the center is opaque... - val nearCenterOffset = (width * nearCenterRelativeOffset).toInt() - if ((getPixel(nearCenterOffset, nearCenterOffset) and alphaChannelMask) == 0) return false - // ... and one near a corner is transparent ... - val nearCornerOffset = (width * nearCornerRelativeOffset).toInt() - return (getPixel(nearCornerOffset, nearCornerOffset) and alphaChannelMask) == 0 - // ... then assume it's a circular icon surrounded by transparency - for kerning - } - - private fun Glyph.setRulesetIconGeometry(assumeRoundIcon: Boolean) { - // This is a Ruleset object icon - first avoid "glue"'ing them to the next char.. - // ends up 2px for default font scale, 1px for min, 3px for max - xadvance += (width * relativeAdvanceExtra).roundToInt() - - if (!assumeRoundIcon) return - - // Now, if we guessed it's round, do some kerning, only for the most conspicuous combos. - // Will look ugly for very unusual Fonts - should we limit this to only default fonts? - - // Kerning is a sparse 2D array of up to 2^16 hints, each stored as byte, so this is - // costly: kerningMap.size * Fonts.charToRulesetImageActor.size * 512 bytes - // Which is 1.76MB for vanilla G&K rules. - - // Ends up -3px for default font scale, -2px for minimum, -4px for max - val defaultKerning = (width * relativeKerning) - for ((char, kerning) in kerningMap) - setKerning(char.code, (defaultKerning * kerning).roundToInt()) - } - - private fun getPixmapForTextureName(regionName: String) = - Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(regionName).region) - - private fun getPixmapFromChar(ch: Char): Pixmap { - return when (ch) { - in Fonts.allSymbols -> getPixmapForTextureName(Fonts.allSymbols[ch]!!) - in Fonts.charToRulesetImageActor -> - try { - // This sometimes fails with a "Frame buffer couldn't be constructed: incomplete attachment" error, unclear why - Fonts.getPixmapFromActor(Fonts.charToRulesetImageActor[ch]!!) - } catch (_: Exception) { - Pixmap(0,0, Pixmap.Format.RGBA8888) // Empty space - } - else -> fontImplementation.getCharPixmap(ch) - } - } - - override fun getGlyphs(run: GlyphLayout.GlyphRun, str: CharSequence, start: Int, end: Int, lastGlyph: Glyph?) { - packer.packToTexture = true // All glyphs added after this are packed directly to the texture. - super.getGlyphs(run, str, start, end, lastGlyph) - if (dirty) { - dirty = false - packer.updateTextureRegions(regions, filter, filter, false) - } - } - - override fun dispose() { - packer.dispose() - } - -} - -object Fonts { - - /** All text is originally rendered in 50px (set in AndroidLauncher and DesktopLauncher), and then scaled to fit the size of the text we need now. - * This has several advantages: It means we only render each character once (good for both runtime and RAM), - * AND it means that our 'custom' emojis only need to be once size (50px) and they'll be rescaled for what's needed. */ - const val ORIGINAL_FONT_SIZE = 50f - const val DEFAULT_FONT_FAMILY = "" - - lateinit var fontImplementation: FontImplementation - lateinit var font: BitmapFont - - /** This resets all cached font data in object Fonts. - * Do not call from normal code - reset the Skin instead: `BaseScreen.setSkin()` - */ - fun resetFont() { - val settings = GUI.getSettings() - fontImplementation.setFontFamily(settings.fontFamilyData, settings.getFontSize()) - font = fontImplementation.getBitmapFont() - font.data.markupEnabled = true - } - - /** Reduce the font list returned by platform-specific code to font families (plain variant if possible) */ - fun getSystemFonts(): Sequence { - return fontImplementation.getSystemFonts() - .sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.localName }) - } - - /** - * Turn a TextureRegion into a Pixmap. - * - * .dispose() must be called on the returned Pixmap when it is no longer needed, or else it will leave a memory leak behind. - * - * @return New Pixmap with all the size and pixel data from this TextureRegion copied into it. - */ - // From https://stackoverflow.com/questions/29451787/libgdx-textureregion-to-pixmap - fun extractPixmapFromTextureRegion(textureRegion: TextureRegion): Pixmap { - val metrics = fontImplementation.getMetrics() - val boxHeight = ceil(metrics.height).toInt() - val boxWidth = ceil(metrics.ascent * textureRegion.regionWidth / textureRegion.regionHeight).toInt() - // In case the region's aspect isn't 1:1, scale the rounded-up width back to a height with unrounded aspect ratio - // (using integer math only, do the equivalent of float math rounded to closest integer) - val drawHeight = (2 * textureRegion.regionHeight * boxWidth + 1) / textureRegion.regionWidth / 2 - // place region from top of bounding box down - // Adding half the descent is empiric - should theoretically be leading only - val drawY = ceil(metrics.leading + metrics.descent * 0.5f).toInt() - - val textureData = textureRegion.texture.textureData - val textureDataPixmap = textureData.getReadonlyPixmap() - - val pixmap = Pixmap(boxWidth, boxHeight, textureData.format) - - // We're using the scaling drawPixmap so pixmap.filter is relevant - it defaults to BiLinear - pixmap.drawPixmap( - textureDataPixmap, // The source Pixmap - textureRegion.regionX, // The source x-coordinate (top left corner) - textureRegion.regionY, // The source y-coordinate (top left corner) - textureRegion.regionWidth, // The width of the area from the other Pixmap in pixels - textureRegion.regionHeight, // The height of the area from the other Pixmap in pixels - 0, // The target x-coordinate (top left corner) - drawY, // The target y-coordinate (top left corner) - boxWidth, // The target width - drawHeight, // The target height - ) - - return pixmap - } - - val rulesetObjectNameToChar =HashMap() - val charToRulesetImageActor = HashMap() - private var nextUnusedCharacterNumber = UNUSED_CHARACTER_CODES_START - - fun addRulesetImages(ruleset: Ruleset) { - rulesetObjectNameToChar.clear() - charToRulesetImageActor.clear() - nextUnusedCharacterNumber = UNUSED_CHARACTER_CODES_START - - fun addChar(objectName: String, objectActor: Actor) { - if (nextUnusedCharacterNumber > UNUSED_CHARACTER_CODES_END) return - val char = Char(nextUnusedCharacterNumber) - nextUnusedCharacterNumber++ - rulesetObjectNameToChar[objectName] = char - charToRulesetImageActor[char] = objectActor - } - - // Note: If an image is missing, these will insert a white square in the font - acceptable in - // most cases as these white squares will be visible elsewhere anyway. "Policy branch Complete" - // is an exception, and therefore gets an existence test. - - for (resourceName in ruleset.tileResources.keys) - addChar(resourceName, ImageGetter.getResourcePortrait(resourceName, ORIGINAL_FONT_SIZE)) - - for (buildingName in ruleset.buildings.keys) - addChar(buildingName, ImageGetter.getConstructionPortrait(buildingName, ORIGINAL_FONT_SIZE)) - - for (unitName in ruleset.units.keys) - addChar(unitName, ImageGetter.getConstructionPortrait(unitName, ORIGINAL_FONT_SIZE)) - - for (promotionName in ruleset.unitPromotions.keys) - addChar(promotionName, ImageGetter.getPromotionPortrait(promotionName, ORIGINAL_FONT_SIZE)) - - for (improvementName in ruleset.tileImprovements.keys) - addChar(improvementName, ImageGetter.getImprovementPortrait(improvementName, ORIGINAL_FONT_SIZE)) - - for (techName in ruleset.technologies.keys) - addChar(techName, ImageGetter.getTechIconPortrait(techName, ORIGINAL_FONT_SIZE)) - - for (nation in ruleset.nations.values) - addChar(nation.name, ImageGetter.getNationPortrait(nation, ORIGINAL_FONT_SIZE)) - - for (policy in ruleset.policies.values) { - val fileLocation = if (policy.name in ruleset.policyBranches) - "PolicyBranchIcons/" + policy.name else "PolicyIcons/" + policy.name - if (!ImageGetter.imageExists(fileLocation)) continue - addChar(policy.name, ImageGetter.getImage(fileLocation).apply { setSize(ORIGINAL_FONT_SIZE) }) - } - } - - private val frameBuffer by lazy { - // Size here is way too big, but it's hard to know in advance how big it needs to be. - // Gdx world coords, not pixels. - FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.width, Gdx.graphics.height, false) - } - private val spriteBatch by lazy { SpriteBatch() } - private val transform = Matrix4() // for repeated reuse without reallocation - - /** Get a Pixmap for a "show ruleset icons as part of text" actor. - * - * Draws onto an offscreen frame buffer and copies the pixels. - * Caller becomes owner of the returned Pixmap and is responsible for disposing it. - * - * Size is such that the actor's height is mapped to the font's ascent (close to - * ORIGINAL_FONT_SIZE * GameSettings.fontSizeMultiplier), the actor is placed like a letter into - * the total height as given by the font's metrics, and width scaled to maintain aspect ratio. - */ - fun getPixmapFromActor(actor: Actor): Pixmap { - val (boxWidth, boxHeight) = scaleAndPositionActor(actor) - - val pixmap = Pixmap(boxWidth, boxHeight, Pixmap.Format.RGBA8888) - - frameBuffer.begin() - - Gdx.gl.glClearColor(0f,0f,0f,0f) - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) - - spriteBatch.begin() - actor.draw(spriteBatch, 1f) - spriteBatch.end() - Gdx.gl.glReadPixels(0, 0, boxWidth, boxHeight, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixmap.pixels) - frameBuffer.end() - - return pixmap - } - - /** Does the Actor scaling and positioning using metrics for [getPixmapFromActor] - * @return boxWidth to boxHeight - */ - private fun scaleAndPositionActor(actor: Actor): Pair { - // We want our - mostly circular - icon to match a typical large uppercase letter in height - // The drawing bounding box should have room, however for the font's leading and descent - val metrics = fontImplementation.getMetrics() - // Empiric slight size reduction - "correctly calculated" they just look a bit too big - val scaledActorHeight = metrics.ascent * 0.93f - val scaledActorWidth = actor.width * (scaledActorHeight / actor.height) - val boxHeight = ceil(metrics.height).toInt() - val boxWidth = ceil(scaledActorWidth).toInt() - - // Nudge down by the border size if it's a Portrait having one, so the "core" sits on the baseline - val border = (actor as? Portrait)?.borderSize ?: 0f - - // Scale to desired font dimensions - modifying the actor this way is OK as the decisions are - // the same each repetition, and size in the Group case or aspect ratio otherwise is preserved - if (actor is Group) { - // We can't just actor.setSize - a Group won't scale its children that way - actor.isTransform = true - val scale = scaledActorWidth / actor.width - actor.setScale(scale, -scale) - // Now the Actor is scaled, we need to position it at the baseline, Y from top of the box - // The +1f is empirical because the result still looked off. - actor.setPosition(0f, metrics.leading + metrics.ascent + border * scale + 1f) - } else { - // Assume it's an Image obeying Actor size, but needing explicit Y flipping - // place actor from top of bounding box down - // (don't think the Gdx (Y is upwards) way - due to the transformMatrix below) - actor.setPosition(0f, metrics.leading + border) - actor.setSize(scaledActorWidth, scaledActorHeight) - transform.idt().scl(1f, -1f, 1f).trn(0f, boxHeight.toFloat(), 0f) - spriteBatch.transformMatrix = transform - // (copies matrix, not a set-by-reference, ignored when actor isTransform is on) - } - - return boxWidth to boxHeight - } - - const val turn = '⏳' // U+23F3 'hourglass' - const val strength = '†' // U+2020 'dagger' - const val rangedStrength = '‡' // U+2021 'double dagger' - const val movement = '➡' // U+27A1 'black rightwards arrow' - const val range = '…' // U+2026 'horizontal ellipsis' - const val production = '⚙' // U+2699 'gear' - const val gold = '¤' // U+00A4 'currency sign' - const val food = '⁂' // U+2042 'asterism' (to avoid 🍏 U+1F34F 'green apple' needing 2 symbols in utf-16 and 4 in utf-8) - const val science = '⍾' // U+237E 'bell symbol' (🧪 U+1F9EA 'test tube', 🔬 U+1F52C 'microscope') - const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note') - const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face') - const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace') - @Suppress("MemberVisibilityCanBePrivate") // offer for mods - const val greatArtist = '♬' // U+266C 'sixteenth note' - @Suppress("MemberVisibilityCanBePrivate") // offer for mods - const val greatEngineer = '⚒' // U+2692 'hammer' - @Suppress("MemberVisibilityCanBePrivate") // offer for mods - const val greatGeneral = '⛤' // U+26E4 'pentagram' - @Suppress("MemberVisibilityCanBePrivate") // offer for mods - const val greatMerchant = '⚖' // U+2696 'scale' - @Suppress("MemberVisibilityCanBePrivate") // offer for mods - const val greatScientist = '⚛' // U+269B 'atom' - const val death = '☠' // U+2620 'skull and crossbones' - const val automate = '⛏' // U+26CF 'pick' - - val allSymbols = mapOf( - turn to "EmojiIcons/Turn", - strength to "StatIcons/Strength", - rangedStrength to "StatIcons/RangedStrength", - range to "StatIcons/Range", - movement to "StatIcons/Movement", - production to "EmojiIcons/Production", - gold to "EmojiIcons/Gold", - food to "EmojiIcons/Food", - science to "EmojiIcons/Science", - culture to "EmojiIcons/Culture", - happiness to "EmojiIcons/Happiness", - faith to "EmojiIcons/Faith", - greatArtist to "EmojiIcons/Great Artist", - greatEngineer to "EmojiIcons/Great Engineer", - greatGeneral to "EmojiIcons/Great General", - greatMerchant to "EmojiIcons/Great Merchant", - greatScientist to "EmojiIcons/Great Scientist", - death to "EmojiIcons/Death", - automate to "EmojiIcons/Automate", - *MayaCalendar.allSymbols - ) -} diff --git a/core/src/com/unciv/ui/components/extensions/FormattingExtensions.kt b/core/src/com/unciv/ui/components/extensions/FormattingExtensions.kt index 9649545532..0c3f8cc20d 100644 --- a/core/src/com/unciv/ui/components/extensions/FormattingExtensions.kt +++ b/core/src/com/unciv/ui/components/extensions/FormattingExtensions.kt @@ -2,7 +2,7 @@ package com.unciv.ui.components.extensions import com.badlogic.gdx.math.Vector2 import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import java.text.SimpleDateFormat import java.time.Duration import java.time.temporal.ChronoUnit diff --git a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt index 4c718851ba..3e5ce865c7 100644 --- a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt +++ b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt @@ -26,10 +26,10 @@ import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.GdxKeyCodeFixes.DEL import com.unciv.ui.components.extensions.GdxKeyCodeFixes.toString import com.unciv.ui.components.extensions.GdxKeyCodeFixes.valueOf +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onChange import com.unciv.ui.images.IconCircleGroup import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/ui/components/fonts/FontFamilyData.kt b/core/src/com/unciv/ui/components/fonts/FontFamilyData.kt new file mode 100644 index 0000000000..1affe82966 --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/FontFamilyData.kt @@ -0,0 +1,31 @@ +package com.unciv.ui.components.fonts + +import com.unciv.models.translations.tr + +// If save in `GameSettings` need use invariantFamily. +// If show to user need use localName. +// If save localName in `GameSettings` may generate garbled characters by encoding. +class FontFamilyData( + val localName: String, + val invariantName: String = localName, + val filePath: String? = null +) { + + @Suppress("unused") // For serialization + constructor() : this(default.localName, default.invariantName) + + // Implement kotlin equality contract such that _only_ the invariantName field is compared. + override fun equals(other: Any?): Boolean { + return if (other is FontFamilyData) invariantName == other.invariantName + else super.equals(other) + } + + override fun hashCode() = invariantName.hashCode() + + /** For SelectBox usage */ + override fun toString() = localName.tr() + + companion object { + val default = FontFamilyData("Default Font", Fonts.DEFAULT_FONT_FAMILY) + } +} diff --git a/core/src/com/unciv/ui/components/fonts/FontImplementation.kt b/core/src/com/unciv/ui/components/fonts/FontImplementation.kt new file mode 100644 index 0000000000..2e7ad0214a --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/FontImplementation.kt @@ -0,0 +1,20 @@ +package com.unciv.ui.components.fonts + +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.g2d.BitmapFont + +interface FontImplementation { + fun setFontFamily(fontFamilyData: FontFamilyData, size: Int) + fun getFontSize(): Int + fun getCharPixmap(char: Char): Pixmap + fun getSystemFonts(): Sequence + + fun getBitmapFont(): BitmapFont { + val fontData = NativeBitmapFontData(this) + val font = BitmapFont(fontData, fontData.regions, false) + font.setOwnsTexture(true) + return font + } + + fun getMetrics(): FontMetricsCommon +} diff --git a/core/src/com/unciv/ui/components/fonts/FontMetricsCommon.kt b/core/src/com/unciv/ui/components/fonts/FontMetricsCommon.kt new file mode 100644 index 0000000000..46d98c3004 --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/FontMetricsCommon.kt @@ -0,0 +1,27 @@ +package com.unciv.ui.components.fonts + +/** Implementations of FontImplementation will use different FontMetrics - AWT or Android.Paint, + * both have a class of that name, no other common point: thus we create an abstraction. + * + * This is used by [Fonts.getPixmapFromActor] for vertical positioning. + */ +class FontMetricsCommon( + /** (positive) distance from the baseline up to the recommended top of normal text */ + val ascent: Float, + /** (positive) distance from the baseline down to the recommended bottom of normal text */ + val descent: Float, + /** (positive) maximum distance from top to bottom of any text, + * including potentially empty space above ascent or below descent */ + val height: Float, + /** (positive) distance from the bounding box top (as defined by [height]) + * to the highest possible top of any text */ + + // Note: This is NOT what typographical leading actually is, but redefined as extra empty space + // on top, to make it easier to sync desktop and android. AWT has some leading but no measures + // outside ascent+descent+leading, while Android has its leading always 0 but typically top + // above ascent and bottom below descent. + // I chose to map AWT's spacing to the top as I found the calculations easier to visualize. + /** Space from the bounding box top to the top of the ascenders - includes line spacing and + * room for unusually high ascenders, as [ascent] is only a recommendation. */ + val leading: Float +) diff --git a/core/src/com/unciv/ui/components/fonts/FontRulesetIcons.kt b/core/src/com/unciv/ui/components/fonts/FontRulesetIcons.kt new file mode 100644 index 0000000000..5586ab2fa3 --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/FontRulesetIcons.kt @@ -0,0 +1,152 @@ +package com.unciv.ui.components.fonts + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.graphics.GL20 +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.g2d.SpriteBatch +import com.badlogic.gdx.graphics.glutils.FrameBuffer +import com.badlogic.gdx.math.Matrix4 +import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.Group +import com.unciv.models.ruleset.Ruleset +import com.unciv.ui.components.extensions.setSize +import com.unciv.ui.components.fonts.FontRulesetIcons.getPixmapFromActor +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.images.Portrait +import kotlin.math.ceil + +/** Map all or most Ruleset icons as Actors to unused Char codepoints, + * [NativeBitmapFontData.getGlyph] can then paint them onto a PixMap, + * on demand, by calling [getPixmapFromActor]. */ +object FontRulesetIcons { + // See https://en.wikipedia.org/wiki/Private_Use_Areas + // char encodings 57344 to 63743 (U+E000-U+F8FF) are not assigned + internal const val UNUSED_CHARACTER_CODES_START = 57344 + private const val UNUSED_CHARACTER_CODES_END = 63743 + + val rulesetObjectNameToChar = HashMap() + val charToRulesetImageActor = HashMap() + private var nextUnusedCharacterNumber = UNUSED_CHARACTER_CODES_START + + fun addRulesetImages(ruleset: Ruleset) { + rulesetObjectNameToChar.clear() + charToRulesetImageActor.clear() + nextUnusedCharacterNumber = UNUSED_CHARACTER_CODES_START + + fun addChar(objectName: String, objectActor: Actor) { + if (nextUnusedCharacterNumber > UNUSED_CHARACTER_CODES_END) return + val char = Char(nextUnusedCharacterNumber) + nextUnusedCharacterNumber++ + rulesetObjectNameToChar[objectName] = char + charToRulesetImageActor[char] = objectActor + } + + // Note: If an image is missing, these will insert a white square in the font - acceptable in + // most cases as these white squares will be visible elsewhere anyway. "Policy branch Complete" + // is an exception, and therefore gets an existence test. + + for (resourceName in ruleset.tileResources.keys) + addChar(resourceName, ImageGetter.getResourcePortrait(resourceName, Fonts.ORIGINAL_FONT_SIZE)) + + for (buildingName in ruleset.buildings.keys) + addChar(buildingName, ImageGetter.getConstructionPortrait(buildingName, Fonts.ORIGINAL_FONT_SIZE)) + + for (unitName in ruleset.units.keys) + addChar(unitName, ImageGetter.getConstructionPortrait(unitName, Fonts.ORIGINAL_FONT_SIZE)) + + for (promotionName in ruleset.unitPromotions.keys) + addChar(promotionName, ImageGetter.getPromotionPortrait(promotionName, Fonts.ORIGINAL_FONT_SIZE)) + + for (improvementName in ruleset.tileImprovements.keys) + addChar(improvementName, ImageGetter.getImprovementPortrait(improvementName, Fonts.ORIGINAL_FONT_SIZE)) + + for (techName in ruleset.technologies.keys) + addChar(techName, ImageGetter.getTechIconPortrait(techName, Fonts.ORIGINAL_FONT_SIZE)) + + for (nation in ruleset.nations.values) + addChar(nation.name, ImageGetter.getNationPortrait(nation, Fonts.ORIGINAL_FONT_SIZE)) + + for (policy in ruleset.policies.values) { + val fileLocation = if (policy.name in ruleset.policyBranches) + "PolicyBranchIcons/" + policy.name else "PolicyIcons/" + policy.name + if (!ImageGetter.imageExists(fileLocation)) continue + addChar(policy.name, ImageGetter.getImage(fileLocation).apply { setSize(Fonts.ORIGINAL_FONT_SIZE) }) + } + } + + private val frameBuffer by lazy { + // Size here is way too big, but it's hard to know in advance how big it needs to be. + // Gdx world coords, not pixels. + FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.width, Gdx.graphics.height, false) + } + private val spriteBatch by lazy { SpriteBatch() } + private val transform = Matrix4() // for repeated reuse without reallocation + + /** Get a Pixmap for a "show ruleset icons as part of text" actor. + * + * Draws onto an offscreen frame buffer and copies the pixels. + * Caller becomes owner of the returned Pixmap and is responsible for disposing it. + * + * Size is such that the actor's height is mapped to the font's ascent (close to + * ORIGINAL_FONT_SIZE * GameSettings.fontSizeMultiplier), the actor is placed like a letter into + * the total height as given by the font's metrics, and width scaled to maintain aspect ratio. + */ + fun getPixmapFromActor(actor: Actor): Pixmap { + val (boxWidth, boxHeight) = scaleAndPositionActor(actor) + + val pixmap = Pixmap(boxWidth, boxHeight, Pixmap.Format.RGBA8888) + + frameBuffer.begin() + + Gdx.gl.glClearColor(0f,0f,0f,0f) + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) + + spriteBatch.begin() + actor.draw(spriteBatch, 1f) + spriteBatch.end() + Gdx.gl.glReadPixels(0, 0, boxWidth, boxHeight, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixmap.pixels) + frameBuffer.end() + + return pixmap + } + + /** Does the Actor scaling and positioning using metrics for [getPixmapFromActor] + * @return boxWidth to boxHeight + */ + private fun scaleAndPositionActor(actor: Actor): Pair { + // We want our - mostly circular - icon to match a typical large uppercase letter in height + // The drawing bounding box should have room, however for the font's leading and descent + val metrics = Fonts.fontImplementation.getMetrics() + // Empiric slight size reduction - "correctly calculated" they just look a bit too big + val scaledActorHeight = metrics.ascent * 0.93f + val scaledActorWidth = actor.width * (scaledActorHeight / actor.height) + val boxHeight = ceil(metrics.height).toInt() + val boxWidth = ceil(scaledActorWidth).toInt() + + // Nudge down by the border size if it's a Portrait having one, so the "core" sits on the baseline + val border = (actor as? Portrait)?.borderSize ?: 0f + + // Scale to desired font dimensions - modifying the actor this way is OK as the decisions are + // the same each repetition, and size in the Group case or aspect ratio otherwise is preserved + if (actor is Group) { + // We can't just actor.setSize - a Group won't scale its children that way + actor.isTransform = true + val scale = scaledActorWidth / actor.width + actor.setScale(scale, -scale) + // Now the Actor is scaled, we need to position it at the baseline, Y from top of the box + // The +1f is empirical because the result still looked off. + actor.setPosition(0f, metrics.leading + metrics.ascent + border * scale + 1f) + } else { + // Assume it's an Image obeying Actor size, but needing explicit Y flipping + // place actor from top of bounding box down + // (don't think the Gdx (Y is upwards) way - due to the transformMatrix below) + actor.setPosition(0f, metrics.leading + border) + actor.setSize(scaledActorWidth, scaledActorHeight) + transform.idt().scl(1f, -1f, 1f).trn(0f, boxHeight.toFloat(), 0f) + spriteBatch.transformMatrix = transform + // (copies matrix, not a set-by-reference, ignored when actor isTransform is on) + } + + return boxWidth to boxHeight + } +} diff --git a/core/src/com/unciv/ui/components/fonts/Fonts.kt b/core/src/com/unciv/ui/components/fonts/Fonts.kt new file mode 100644 index 0000000000..6c91f5b87a --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/Fonts.kt @@ -0,0 +1,148 @@ +package com.unciv.ui.components.fonts + +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.g2d.BitmapFont +import com.badlogic.gdx.graphics.g2d.TextureRegion +import com.unciv.GUI +import com.unciv.UncivGame +import com.unciv.ui.components.MayaCalendar +import com.unciv.ui.components.extensions.getReadonlyPixmap +import com.unciv.ui.components.fonts.Fonts.extractPixmapFromTextureRegion +import com.unciv.ui.components.fonts.Fonts.font +import com.unciv.ui.components.fonts.Fonts.fontImplementation +import kotlin.math.ceil + +/** + * The "Font manager" + * + * * We have one global [font], held by this object. + * * Platform-dependent code is linked through [fontImplementation]. + * * Most of the work happens in [getGlyph][NativeBitmapFontData.getGlyph]. It dispatches to one of three handlers: + * - Normal text goes to the platform specific implemenation to fetch a glyph as pixels from the system. + * - A set of "symbols" (for strength, movement, death, war, gold and some others) + * comes from the texture atlas and is implemented in `extractPixmapFromTextureRegion`. + * They use Unicode code points which normally hold related symbols. + * - Icons for Ruleset objects are pre-build as Actors then drawn as pixels in `FontRulesetIcons`. + * They use code points from the 'Private use' range - see comments over there. + * + * @see NativeBitmapFontData + * @see com.unciv.app.desktop.DesktopFont + * @see com.unciv.app.AndroidFont + * @see extractPixmapFromTextureRegion + * @see FontRulesetIcons + */ +object Fonts { + + /** All text is originally rendered in 50px (set in AndroidLauncher and DesktopLauncher), and then scaled to fit the size of the text we need now. + * This has several advantages: It means we only render each character once (good for both runtime and RAM), + * AND it means that our 'custom' emojis only need to be once size (50px) and they'll be rescaled for what's needed. */ + const val ORIGINAL_FONT_SIZE = 50f + const val DEFAULT_FONT_FAMILY = "" + + lateinit var fontImplementation: FontImplementation + lateinit var font: BitmapFont + + /** This resets all cached font data in object Fonts. + * Do not call from normal code - reset the Skin instead: `BaseScreen.setSkin()` + */ + fun resetFont() { + val settings = GUI.getSettings() + fontImplementation.setFontFamily(settings.fontFamilyData, settings.getFontSize()) + font = fontImplementation.getBitmapFont() + font.data.markupEnabled = true + } + + /** Reduce the font list returned by platform-specific code to font families (plain variant if possible) */ + fun getSystemFonts(): Sequence { + return fontImplementation.getSystemFonts() + .sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.localName }) + } + + /** + * Turn a TextureRegion into a Pixmap. + * + * .dispose() must be called on the returned Pixmap when it is no longer needed, or else it will leave a memory leak behind. + * + * @return New Pixmap with all the size and pixel data from this TextureRegion copied into it. + */ + // From https://stackoverflow.com/questions/29451787/libgdx-textureregion-to-pixmap + fun extractPixmapFromTextureRegion(textureRegion: TextureRegion): Pixmap { + val metrics = fontImplementation.getMetrics() + val boxHeight = ceil(metrics.height).toInt() + val boxWidth = ceil(metrics.ascent * textureRegion.regionWidth / textureRegion.regionHeight).toInt() + // In case the region's aspect isn't 1:1, scale the rounded-up width back to a height with unrounded aspect ratio + // (using integer math only, do the equivalent of float math rounded to closest integer) + val drawHeight = (2 * textureRegion.regionHeight * boxWidth + 1) / textureRegion.regionWidth / 2 + // place region from top of bounding box down + // Adding half the descent is empiric - should theoretically be leading only + val drawY = ceil(metrics.leading + metrics.descent * 0.5f).toInt() + + val textureData = textureRegion.texture.textureData + val textureDataPixmap = textureData.getReadonlyPixmap() + + val pixmap = Pixmap(boxWidth, boxHeight, textureData.format) + + // We're using the scaling drawPixmap so pixmap.filter is relevant - it defaults to BiLinear + pixmap.drawPixmap( + textureDataPixmap, // The source Pixmap + textureRegion.regionX, // The source x-coordinate (top left corner) + textureRegion.regionY, // The source y-coordinate (top left corner) + textureRegion.regionWidth, // The width of the area from the other Pixmap in pixels + textureRegion.regionHeight, // The height of the area from the other Pixmap in pixels + 0, // The target x-coordinate (top left corner) + drawY, // The target y-coordinate (top left corner) + boxWidth, // The target width + drawHeight, // The target height + ) + + return pixmap + } + + const val turn = '⏳' // U+23F3 'hourglass' + const val strength = '†' // U+2020 'dagger' + const val rangedStrength = '‡' // U+2021 'double dagger' + const val movement = '➡' // U+27A1 'black rightwards arrow' + const val range = '…' // U+2026 'horizontal ellipsis' + const val production = '⚙' // U+2699 'gear' + const val gold = '¤' // U+00A4 'currency sign' + const val food = '⁂' // U+2042 'asterism' (to avoid 🍏 U+1F34F 'green apple' needing 2 symbols in utf-16 and 4 in utf-8) + const val science = '⍾' // U+237E 'bell symbol' (🧪 U+1F9EA 'test tube', 🔬 U+1F52C 'microscope') + const val culture = '♪' // U+266A 'eighth note' (🎵 U+1F3B5 'musical note') + const val happiness = '⌣' // U+2323 'smile' (😀 U+1F600 'grinning face') + const val faith = '☮' // U+262E 'peace symbol' (🕊 U+1F54A 'dove of peace') + @Suppress("MemberVisibilityCanBePrivate") // offer for mods + const val greatArtist = '♬' // U+266C 'sixteenth note' + @Suppress("MemberVisibilityCanBePrivate") // offer for mods + const val greatEngineer = '⚒' // U+2692 'hammer' + @Suppress("MemberVisibilityCanBePrivate") // offer for mods + const val greatGeneral = '⛤' // U+26E4 'pentagram' + @Suppress("MemberVisibilityCanBePrivate") // offer for mods + const val greatMerchant = '⚖' // U+2696 'scale' + @Suppress("MemberVisibilityCanBePrivate") // offer for mods + const val greatScientist = '⚛' // U+269B 'atom' + const val death = '☠' // U+2620 'skull and crossbones' + const val automate = '⛏' // U+26CF 'pick' + + val allSymbols = mapOf( + turn to "EmojiIcons/Turn", + strength to "StatIcons/Strength", + rangedStrength to "StatIcons/RangedStrength", + range to "StatIcons/Range", + movement to "StatIcons/Movement", + production to "EmojiIcons/Production", + gold to "EmojiIcons/Gold", + food to "EmojiIcons/Food", + science to "EmojiIcons/Science", + culture to "EmojiIcons/Culture", + happiness to "EmojiIcons/Happiness", + faith to "EmojiIcons/Faith", + greatArtist to "EmojiIcons/Great Artist", + greatEngineer to "EmojiIcons/Great Engineer", + greatGeneral to "EmojiIcons/Great General", + greatMerchant to "EmojiIcons/Great Merchant", + greatScientist to "EmojiIcons/Great Scientist", + death to "EmojiIcons/Death", + automate to "EmojiIcons/Automate", + *MayaCalendar.allSymbols + ) +} diff --git a/core/src/com/unciv/ui/components/fonts/NativeBitmapFontData.kt b/core/src/com/unciv/ui/components/fonts/NativeBitmapFontData.kt new file mode 100644 index 0000000000..2af2a13cd4 --- /dev/null +++ b/core/src/com/unciv/ui/components/fonts/NativeBitmapFontData.kt @@ -0,0 +1,166 @@ +package com.unciv.ui.components.fonts + +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.Pixmap +import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.g2d.BitmapFont +import com.badlogic.gdx.graphics.g2d.GlyphLayout +import com.badlogic.gdx.graphics.g2d.PixmapPacker +import com.badlogic.gdx.graphics.g2d.TextureRegion +import com.badlogic.gdx.utils.Array +import com.badlogic.gdx.utils.Disposable +import com.unciv.Constants +import com.unciv.ui.images.ImageGetter +import kotlin.math.roundToInt + +// This class is loosely based on libgdx's FreeTypeBitmapFontData +class NativeBitmapFontData( + private val fontImplementation: FontImplementation +) : BitmapFont.BitmapFontData(), Disposable { + + val regions: Array + + private var dirty = false + private val packer: PixmapPacker + + private val filter = Texture.TextureFilter.Linear + + private companion object { + /** How to get the alpha channel in a Pixmap.getPixel return value (Int) - it's the LSB */ + const val alphaChannelMask = 255 + /** Where to test circle for transparency */ + // The center of a squared circle's corner wedge would be at (1-PI/4)/2 ≈ 0.1073 + const val nearCornerRelativeOffset = 0.1f + /** Where to test circle for opacity */ + // arbitrary choice just off-center + const val nearCenterRelativeOffset = 0.4f + /** Width multiplier to get extra advance after a ruleset icon, empiric */ + const val relativeAdvanceExtra = 0.039f + /** Multiplier to get default kerning between a ruleset icon and 'open' characters */ + const val relativeKerning = -0.055f + /** Which follower characters receive how much kerning relative to [relativeKerning] */ + val kerningMap = mapOf('A' to 1f, 'T' to 0.6f, 'V' to 1f, 'Y' to 1.2f) + } + + init { + // set general font data + flipped = false + lineHeight = fontImplementation.getFontSize().toFloat() + capHeight = lineHeight + ascent = -lineHeight + down = -lineHeight + + // Create a packer. + val size = 1024 + val packStrategy = PixmapPacker.GuillotineStrategy() + packer = PixmapPacker(size, size, Pixmap.Format.RGBA8888, 1, false, packStrategy) + packer.transparentColor = Color.WHITE + packer.transparentColor.a = 0f + + // Generate texture regions. + regions = Array() + packer.updateTextureRegions(regions, filter, filter, false) + + // Set space glyph. + val spaceGlyph = getGlyph(' ') + spaceXadvance = spaceGlyph.xadvance.toFloat() + + setScale(Constants.defaultFontSize / Fonts.ORIGINAL_FONT_SIZE) + } + + override fun getGlyph(ch: Char): BitmapFont.Glyph = super.getGlyph(ch) ?: createAndCacheGlyph(ch) + + private fun createAndCacheGlyph(ch: Char): BitmapFont.Glyph { + val charPixmap = getPixmapFromChar(ch) + + val glyph = BitmapFont.Glyph() + glyph.id = ch.code + glyph.width = charPixmap.width + glyph.height = charPixmap.height + glyph.xadvance = glyph.width + + // Check alpha to guess whether this is a round icon + // Needs to be done before disposing charPixmap, and we want to do that soon + val assumeRoundIcon = charPixmap.guessIsRoundSurroundedByTransparency() + + val rect = packer.pack(charPixmap) + charPixmap.dispose() + glyph.page = packer.pages.size - 1 // Glyph is always packed into the last page for now. + glyph.srcX = rect.x.toInt() + glyph.srcY = rect.y.toInt() + + if (ch.code >= FontRulesetIcons.UNUSED_CHARACTER_CODES_START) + glyph.setRulesetIconGeometry(assumeRoundIcon) + + // If a page was added, create a new texture region for the incrementally added glyph. + if (regions.size <= glyph.page) + packer.updateTextureRegions(regions, filter, filter, false) + + setGlyphRegion(glyph, regions.get(glyph.page)) + setGlyph(ch.code, glyph) + dirty = true + + return glyph + } + + private fun Pixmap.guessIsRoundSurroundedByTransparency(): Boolean { + // If a pixel near the center is opaque... + val nearCenterOffset = (width * nearCenterRelativeOffset).toInt() + if ((getPixel(nearCenterOffset, nearCenterOffset) and alphaChannelMask) == 0) return false + // ... and one near a corner is transparent ... + val nearCornerOffset = (width * nearCornerRelativeOffset).toInt() + return (getPixel(nearCornerOffset, nearCornerOffset) and alphaChannelMask) == 0 + // ... then assume it's a circular icon surrounded by transparency - for kerning + } + + private fun BitmapFont.Glyph.setRulesetIconGeometry(assumeRoundIcon: Boolean) { + // This is a Ruleset object icon - first avoid "glue"'ing them to the next char.. + // ends up 2px for default font scale, 1px for min, 3px for max + xadvance += (width * relativeAdvanceExtra).roundToInt() + + if (!assumeRoundIcon) return + + // Now, if we guessed it's round, do some kerning, only for the most conspicuous combos. + // Will look ugly for very unusual Fonts - should we limit this to only default fonts? + + // Kerning is a sparse 2D array of up to 2^16 hints, each stored as byte, so this is + // costly: kerningMap.size * Fonts.charToRulesetImageActor.size * 512 bytes + // Which is 1.76MB for vanilla G&K rules. + + // Ends up -3px for default font scale, -2px for minimum, -4px for max + val defaultKerning = (width * relativeKerning) + for ((char, kerning) in kerningMap) + setKerning(char.code, (defaultKerning * kerning).roundToInt()) + } + + private fun getPixmapForTextureName(regionName: String) = + Fonts.extractPixmapFromTextureRegion(ImageGetter.getDrawable(regionName).region) + + private fun getPixmapFromChar(ch: Char): Pixmap { + return when (ch) { + in Fonts.allSymbols -> getPixmapForTextureName(Fonts.allSymbols[ch]!!) + in FontRulesetIcons.charToRulesetImageActor -> + try { + // This sometimes fails with a "Frame buffer couldn't be constructed: incomplete attachment" error, unclear why + FontRulesetIcons.getPixmapFromActor(FontRulesetIcons.charToRulesetImageActor[ch]!!) + } catch (_: Exception) { + Pixmap(0, 0, Pixmap.Format.RGBA8888) // Empty space + } + else -> fontImplementation.getCharPixmap(ch) + } + } + + override fun getGlyphs(run: GlyphLayout.GlyphRun, str: CharSequence, start: Int, end: Int, lastGlyph: BitmapFont.Glyph?) { + packer.packToTexture = true // All glyphs added after this are packed directly to the texture. + super.getGlyphs(run, str, start, end, lastGlyph) + if (dirty) { + dirty = false + packer.updateTextureRegions(regions, filter, filter, false) + } + } + + override fun dispose() { + packer.dispose() + } + +} diff --git a/core/src/com/unciv/ui/components/tilegroups/CityButton.kt b/core/src/com/unciv/ui/components/tilegroups/CityButton.kt index 1387bf1900..a1a688592b 100644 --- a/core/src/com/unciv/ui/components/tilegroups/CityButton.kt +++ b/core/src/com/unciv/ui/components/tilegroups/CityButton.kt @@ -16,15 +16,15 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.models.TutorialTrigger import com.unciv.models.ruleset.INonPerpetualConstruction import com.unciv.models.ruleset.PerpetualConstruction -import com.unciv.ui.components.widgets.BorderedTable -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.centerX import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.toGroup import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.BorderedTable import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.Popup import com.unciv.ui.screens.basescreen.BaseScreen diff --git a/core/src/com/unciv/ui/components/widgets/ColorMarkupLabel.kt b/core/src/com/unciv/ui/components/widgets/ColorMarkupLabel.kt index 2ce74d35e4..f04eb0e21e 100644 --- a/core/src/com/unciv/ui/components/widgets/ColorMarkupLabel.kt +++ b/core/src/com/unciv/ui/components/widgets/ColorMarkupLabel.kt @@ -8,7 +8,8 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout import com.badlogic.gdx.scenes.scene2d.ui.Label import com.unciv.Constants import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.FontRulesetIcons +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.basescreen.BaseScreen /** A Label allowing Gdx markup @@ -41,7 +42,7 @@ class ColorMarkupLabel private constructor( * Use to easily color text without also coloring the icons which translation inserts as * characters for recognized gameplay names. * - * @see Fonts.charToRulesetImageActor + * @see FontRulesetIcons.charToRulesetImageActor */ constructor( text: String, @@ -130,7 +131,7 @@ class ColorMarkupLabel private constructor( val sb = StringBuilder(translated.length + 42) var currentColor = ' ' for (char in translated) { - val newColor = if (char in Fonts.allSymbols || char in Fonts.charToRulesetImageActor) 'S' else 'T' + val newColor = if (char in Fonts.allSymbols || char in FontRulesetIcons.charToRulesetImageActor) 'S' else 'T' if (newColor != currentColor) { if (currentColor != ' ') sb.append("[]") sb.append('[') diff --git a/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt b/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt index a292ca57a3..5c6fb3cf50 100644 --- a/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt +++ b/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt @@ -10,8 +10,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.ImageTextButton import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable import com.badlogic.gdx.utils.Align -import com.unciv.ui.components.Fonts import com.unciv.ui.components.UncivTooltip.Companion.addTooltip +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen diff --git a/core/src/com/unciv/ui/components/widgets/WrappableLabel.kt b/core/src/com/unciv/ui/components/widgets/WrappableLabel.kt index 1d80663e31..b198e7b1f3 100644 --- a/core/src/com/unciv/ui/components/widgets/WrappableLabel.kt +++ b/core/src/com/unciv/ui/components/widgets/WrappableLabel.kt @@ -4,7 +4,7 @@ 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.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.basescreen.BaseScreen import kotlin.math.floor diff --git a/core/src/com/unciv/ui/images/ImageGetter.kt b/core/src/com/unciv/ui/images/ImageGetter.kt index 7a87d8191a..567a94fb8f 100644 --- a/core/src/com/unciv/ui/images/ImageGetter.kt +++ b/core/src/com/unciv/ui/images/ImageGetter.kt @@ -24,7 +24,6 @@ import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.nation.Nation import com.unciv.models.skins.SkinCache import com.unciv.models.tilesets.TileSetCache -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.centerX import com.unciv.ui.components.extensions.centerY @@ -35,6 +34,7 @@ import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.surroundWithThinCircle import com.unciv.ui.components.extensions.toGroup import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.FontRulesetIcons import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.utils.debug import kotlin.math.atan2 @@ -87,7 +87,7 @@ object ImageGetter { SkinCache.assembleSkinConfigs(ruleset.mods) BaseScreen.setSkin() - Fonts.addRulesetImages(ruleset) + FontRulesetIcons.addRulesetImages(ruleset) } /** Loads all atlas/texture files from a folder, as controlled by an Atlases.json */ diff --git a/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt b/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt index b82f9cb9a4..8bbf2678c2 100644 --- a/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt +++ b/core/src/com/unciv/ui/objectdescriptions/BaseUnitDescriptions.kt @@ -15,8 +15,8 @@ import com.unciv.models.ruleset.unit.UnitMovementType import com.unciv.models.ruleset.unit.UnitType import com.unciv.models.stats.Stat import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.getConsumesAmountString +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.civilopediascreen.FormattedLine diff --git a/core/src/com/unciv/ui/objectdescriptions/TechnologyDescriptions.kt b/core/src/com/unciv/ui/objectdescriptions/TechnologyDescriptions.kt index b857c3d3d1..a8bf0794f4 100644 --- a/core/src/com/unciv/ui/objectdescriptions/TechnologyDescriptions.kt +++ b/core/src/com/unciv/ui/objectdescriptions/TechnologyDescriptions.kt @@ -12,8 +12,8 @@ import com.unciv.models.ruleset.unique.UniqueFlag import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.center +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.PortraitUnavailableWonderForTechTree import com.unciv.ui.screens.civilopediascreen.FormattedLine diff --git a/core/src/com/unciv/ui/popups/options/AdvancedTab.kt b/core/src/com/unciv/ui/popups/options/AdvancedTab.kt index 3559ec42ad..2513948bac 100644 --- a/core/src/com/unciv/ui/popups/options/AdvancedTab.kt +++ b/core/src/com/unciv/ui/popups/options/AdvancedTab.kt @@ -21,31 +21,31 @@ import com.unciv.models.metadata.ModCategories import com.unciv.models.metadata.ScreenSize import com.unciv.models.translations.TranslationFileWriter import com.unciv.models.translations.tr -import com.unciv.ui.popups.ConfirmPopup -import com.unciv.ui.screens.basescreen.BaseScreen -import com.unciv.ui.components.FontFamilyData -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.widgets.UncivSlider import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.disable -import com.unciv.ui.components.input.keyShortcuts -import com.unciv.ui.components.input.onActivation -import com.unciv.ui.components.input.onChange -import com.unciv.ui.components.input.onClick import com.unciv.ui.components.extensions.setFontColor import com.unciv.ui.components.extensions.toCheckBox import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.components.extensions.withoutItem +import com.unciv.ui.components.fonts.FontFamilyData +import com.unciv.ui.components.fonts.Fonts +import com.unciv.ui.components.input.keyShortcuts +import com.unciv.ui.components.input.onActivation +import com.unciv.ui.components.input.onChange +import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.UncivSlider +import com.unciv.ui.popups.ConfirmPopup +import com.unciv.ui.screens.basescreen.BaseScreen +import com.unciv.utils.Concurrency import com.unciv.utils.Display import com.unciv.utils.ScreenOrientation -import com.unciv.utils.Concurrency import com.unciv.utils.launchOnGLThread +import java.util.UUID +import java.util.zip.Deflater import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.UUID -import java.util.zip.Deflater fun advancedTab( optionsPopup: OptionsPopup, diff --git a/core/src/com/unciv/ui/screens/basescreen/BaseScreen.kt b/core/src/com/unciv/ui/screens/basescreen/BaseScreen.kt index e622eaaf4e..9517d897eb 100644 --- a/core/src/com/unciv/ui/screens/basescreen/BaseScreen.kt +++ b/core/src/com/unciv/ui/screens/basescreen/BaseScreen.kt @@ -18,8 +18,8 @@ import com.badlogic.gdx.utils.viewport.ExtendViewport import com.unciv.UncivGame import com.unciv.models.TutorialTrigger import com.unciv.models.skins.SkinStrings -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.isNarrowerThan4to3 +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.DispatcherVetoer import com.unciv.ui.components.input.KeyShortcutDispatcher import com.unciv.ui.components.input.KeyShortcutDispatcherVeto diff --git a/core/src/com/unciv/ui/screens/basescreen/StageMouseOverDebug.kt b/core/src/com/unciv/ui/screens/basescreen/StageMouseOverDebug.kt index 5eb07e552f..1d8da5817a 100644 --- a/core/src/com/unciv/ui/screens/basescreen/StageMouseOverDebug.kt +++ b/core/src/com/unciv/ui/screens/basescreen/StageMouseOverDebug.kt @@ -12,7 +12,7 @@ import com.badlogic.gdx.scenes.scene2d.Stage import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Align -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/ui/screens/cityscreen/CityStatsTable.kt b/core/src/com/unciv/ui/screens/cityscreen/CityStatsTable.kt index 1f6c379bb8..ca6f46ad8d 100644 --- a/core/src/com/unciv/ui/screens/cityscreen/CityStatsTable.kt +++ b/core/src/com/unciv/ui/screens/cityscreen/CityStatsTable.kt @@ -17,8 +17,6 @@ import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.Stat import com.unciv.models.translations.tr -import com.unciv.ui.components.widgets.ExpanderTab -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.colorFromRGB @@ -26,9 +24,11 @@ import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toGroup import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.ExpanderTab import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen diff --git a/core/src/com/unciv/ui/screens/cityscreen/ConstructionInfoTable.kt b/core/src/com/unciv/ui/screens/cityscreen/ConstructionInfoTable.kt index 574092316d..eb7b9bfb84 100644 --- a/core/src/com/unciv/ui/screens/cityscreen/ConstructionInfoTable.kt +++ b/core/src/com/unciv/ui/screens/cityscreen/ConstructionInfoTable.kt @@ -13,11 +13,11 @@ import com.unciv.models.ruleset.PerpetualConstruction import com.unciv.models.ruleset.PerpetualStatConversion import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.isEnabled import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.ConfirmPopup diff --git a/core/src/com/unciv/ui/screens/civilopediascreen/CivilopediaScreen.kt b/core/src/com/unciv/ui/screens/civilopediascreen/CivilopediaScreen.kt index cd1a78a31d..83d4d2df0b 100644 --- a/core/src/com/unciv/ui/screens/civilopediascreen/CivilopediaScreen.kt +++ b/core/src/com/unciv/ui/screens/civilopediascreen/CivilopediaScreen.kt @@ -14,11 +14,11 @@ import com.unciv.models.ruleset.unique.IHasUniques import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.INamed import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.toImageButton import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.keyShortcuts diff --git a/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt b/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt index 284fbdecce..36f8d33a69 100644 --- a/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt +++ b/core/src/com/unciv/ui/screens/diplomacyscreen/CityStateDiplomacyTable.kt @@ -23,12 +23,12 @@ import com.unciv.models.ruleset.Quest import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick import com.unciv.ui.components.widgets.ColorMarkupLabel import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt b/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt index 0a7d0088f9..f5e8bba0ec 100644 --- a/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/screens/diplomacyscreen/DiplomacyScreen.kt @@ -16,13 +16,13 @@ import com.unciv.logic.trade.Trade import com.unciv.models.translations.tr import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicTrackChooserFlags -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.setFontSize 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.components.fonts.Fonts import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.onActivation diff --git a/core/src/com/unciv/ui/screens/diplomacyscreen/MajorCivDiplomacyTable.kt b/core/src/com/unciv/ui/screens/diplomacyscreen/MajorCivDiplomacyTable.kt index 1bb88fca6b..34e88708dc 100644 --- a/core/src/com/unciv/ui/screens/diplomacyscreen/MajorCivDiplomacyTable.kt +++ b/core/src/com/unciv/ui/screens/diplomacyscreen/MajorCivDiplomacyTable.kt @@ -15,11 +15,11 @@ import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType import com.unciv.models.ruleset.ModOptionsConstants import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick import com.unciv.ui.popups.ConfirmPopup import kotlin.math.roundToInt diff --git a/core/src/com/unciv/ui/screens/overviewscreen/EspionageOverviewScreen.kt b/core/src/com/unciv/ui/screens/overviewscreen/EspionageOverviewScreen.kt index e60c161ed9..0ee61e18c6 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/EspionageOverviewScreen.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/EspionageOverviewScreen.kt @@ -11,18 +11,18 @@ import com.unciv.logic.civilization.Civilization import com.unciv.models.Spy import com.unciv.models.SpyAction import com.unciv.models.translations.tr -import com.unciv.ui.images.ImageGetter -import com.unciv.ui.screens.pickerscreens.PickerScreen -import com.unciv.ui.components.widgets.AutoScrollPane -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.extensions.addSeparatorVertical -import com.unciv.ui.components.input.keyShortcuts -import com.unciv.ui.components.input.onActivation -import com.unciv.ui.components.input.onClick import com.unciv.ui.components.extensions.setSize import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts +import com.unciv.ui.components.input.KeyCharAndCode +import com.unciv.ui.components.input.keyShortcuts +import com.unciv.ui.components.input.onActivation +import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.AutoScrollPane +import com.unciv.ui.images.ImageGetter +import com.unciv.ui.screens.pickerscreens.PickerScreen /** Screen used for moving spies between cities */ class EspionageOverviewScreen(val civInfo: Civilization) : PickerScreen(true) { diff --git a/core/src/com/unciv/ui/screens/overviewscreen/GlobalPoliticsOverviewTable.kt b/core/src/com/unciv/ui/screens/overviewscreen/GlobalPoliticsOverviewTable.kt index 304c2de866..2e9d85abf8 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/GlobalPoliticsOverviewTable.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/GlobalPoliticsOverviewTable.kt @@ -16,9 +16,6 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.map.HexMath import com.unciv.models.ruleset.Policy.PolicyBranchType import com.unciv.models.ruleset.unique.UniqueType -import com.unciv.ui.components.widgets.AutoScrollPane -import com.unciv.ui.components.widgets.ColorMarkupLabel -import com.unciv.ui.components.Fonts import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.addBorder import com.unciv.ui.components.extensions.addSeparator @@ -26,7 +23,10 @@ import com.unciv.ui.components.extensions.addSeparatorVertical import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.AutoScrollPane +import com.unciv.ui.components.widgets.ColorMarkupLabel import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.diplomacyscreen.DiplomacyScreen diff --git a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt index 05fa28db1a..22251f6764 100644 --- a/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt +++ b/core/src/com/unciv/ui/screens/overviewscreen/UnitOverviewTab.kt @@ -16,10 +16,6 @@ import com.unciv.logic.map.tile.Tile import com.unciv.models.UnitActionType import com.unciv.models.UpgradeUnitAction import com.unciv.models.ruleset.unit.BaseUnit -import com.unciv.ui.components.widgets.ExpanderTab -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.widgets.TabbedPager -import com.unciv.ui.components.widgets.UnitGroup import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.brighten import com.unciv.ui.components.extensions.center @@ -28,7 +24,11 @@ import com.unciv.ui.components.extensions.equalizeColumns 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.components.fonts.Fonts import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.ExpanderTab +import com.unciv.ui.components.widgets.TabbedPager +import com.unciv.ui.components.widgets.UnitGroup import com.unciv.ui.images.IconTextButton import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.UnitUpgradeMenu diff --git a/core/src/com/unciv/ui/screens/pickerscreens/ImprovementPickerScreen.kt b/core/src/com/unciv/ui/screens/pickerscreens/ImprovementPickerScreen.kt index 3b9d4b9327..d55983f4ee 100644 --- a/core/src/com/unciv/ui/screens/pickerscreens/ImprovementPickerScreen.kt +++ b/core/src/com/unciv/ui/screens/pickerscreens/ImprovementPickerScreen.kt @@ -12,11 +12,11 @@ import com.unciv.models.ruleset.unique.LocalUniqueCache import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.stats.Stats import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onDoubleClick diff --git a/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt b/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt index 645ae92fb5..d69b9ff489 100644 --- a/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt +++ b/core/src/com/unciv/ui/screens/pickerscreens/TechPickerScreen.kt @@ -15,12 +15,12 @@ import com.unciv.models.UncivSound import com.unciv.models.ruleset.tech.Technology import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onDoubleClick import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/ui/screens/savescreens/LoadOrSaveScreen.kt b/core/src/com/unciv/ui/screens/savescreens/LoadOrSaveScreen.kt index 8571b05e01..06d8360143 100644 --- a/core/src/com/unciv/ui/screens/savescreens/LoadOrSaveScreen.kt +++ b/core/src/com/unciv/ui/screens/savescreens/LoadOrSaveScreen.kt @@ -4,24 +4,24 @@ import com.badlogic.gdx.files.FileHandle import com.badlogic.gdx.scenes.scene2d.ui.CheckBox import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton -import com.unciv.UncivGame import com.unciv.Constants +import com.unciv.UncivGame import com.unciv.models.translations.tr -import com.unciv.ui.screens.pickerscreens.PickerScreen -import com.unciv.ui.popups.ConfirmPopup -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.UncivDateFormat.formatDate import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.enable +import com.unciv.ui.components.extensions.pad +import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts +import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onChange import com.unciv.ui.components.input.onDoubleClick -import com.unciv.ui.components.extensions.pad -import com.unciv.ui.components.extensions.toLabel -import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.popups.ConfirmPopup +import com.unciv.ui.screens.pickerscreens.PickerScreen import com.unciv.utils.Concurrency import com.unciv.utils.launchOnGLThread import java.util.Date diff --git a/core/src/com/unciv/ui/screens/victoryscreen/LineChart.kt b/core/src/com/unciv/ui/screens/victoryscreen/LineChart.kt index 588730c454..58e2b4fd1a 100644 --- a/core/src/com/unciv/ui/screens/victoryscreen/LineChart.kt +++ b/core/src/com/unciv/ui/screens/victoryscreen/LineChart.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup import com.badlogic.gdx.utils.Align import com.unciv.logic.civilization.Civilization -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.victoryscreen.VictoryScreenCivGroup.DefeatedPlayerStyle import kotlin.math.abs diff --git a/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenReplay.kt b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenReplay.kt index 1320dd8fce..ac20174773 100644 --- a/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenReplay.kt +++ b/core/src/com/unciv/ui/screens/victoryscreen/VictoryScreenReplay.kt @@ -5,13 +5,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Timer import com.unciv.models.UncivSound -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.widgets.TabbedPager -import com.unciv.ui.components.widgets.UncivSlider import com.unciv.ui.components.YearTextUtil -import com.unciv.ui.components.input.onClick import com.unciv.ui.components.extensions.setSize import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.Fonts +import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.TabbedPager +import com.unciv.ui.components.widgets.UncivSlider import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.worldscreen.WorldScreen diff --git a/core/src/com/unciv/ui/screens/worldscreen/TechPolicyDiplomacyButtons.kt b/core/src/com/unciv/ui/screens/worldscreen/TechPolicyDiplomacyButtons.kt index 67b6984c42..a6e4c6feb4 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/TechPolicyDiplomacyButtons.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/TechPolicyDiplomacyButtons.kt @@ -7,10 +7,10 @@ import com.badlogic.gdx.scenes.scene2d.ui.Container import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.models.UncivSound import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.onActivation import com.unciv.ui.images.ImageGetter diff --git a/core/src/com/unciv/ui/screens/worldscreen/bottombar/BattleTable.kt b/core/src/com/unciv/ui/screens/worldscreen/bottombar/BattleTable.kt index a500783285..1f427ae6bc 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/bottombar/BattleTable.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/bottombar/BattleTable.kt @@ -18,14 +18,14 @@ import com.unciv.models.UncivSound import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.tr import com.unciv.ui.audio.SoundPlayer -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.widgets.UnitGroup import com.unciv.ui.components.extensions.addBorderAllowOpacity import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.UnitGroup import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.worldscreen.WorldScreen diff --git a/core/src/com/unciv/ui/screens/worldscreen/mainmenu/WorldScreenMusicPopup.kt b/core/src/com/unciv/ui/screens/worldscreen/mainmenu/WorldScreenMusicPopup.kt index b43a9d043e..c0f55a7766 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/mainmenu/WorldScreenMusicPopup.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/mainmenu/WorldScreenMusicPopup.kt @@ -9,10 +9,10 @@ import com.unciv.UncivGame import com.unciv.models.metadata.GameSettings import com.unciv.models.metadata.ScreenSize import com.unciv.ui.audio.MusicController -import com.unciv.ui.components.widgets.ExpanderTab -import com.unciv.ui.components.Fonts -import com.unciv.ui.components.input.onClick import com.unciv.ui.components.extensions.setSize +import com.unciv.ui.components.fonts.Fonts +import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.ExpanderTab import com.unciv.ui.images.ImageGetter import com.unciv.ui.popups.Popup import com.unciv.ui.popups.options.addMusicControls diff --git a/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBar.kt b/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBar.kt index 644ab73307..ba27a6fbbc 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBar.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBar.kt @@ -8,11 +8,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.utils.Align import com.unciv.logic.civilization.Civilization import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.setFontSize import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toTextButton +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onClick diff --git a/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBarResources.kt b/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBarResources.kt index acca1b9a59..a3332e5133 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBarResources.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/topbar/WorldScreenTopBarResources.kt @@ -8,11 +8,11 @@ import com.unciv.logic.civilization.Civilization import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unique.UniqueType -import com.unciv.ui.components.Fonts import com.unciv.ui.components.MayaCalendar import com.unciv.ui.components.YearTextUtil import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toStringSigned +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.onClick import com.unciv.ui.images.ImageGetter import com.unciv.ui.screens.overviewscreen.EmpireOverviewCategories diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt index 8acbcfe947..6be772c607 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionModifiers.kt @@ -5,7 +5,7 @@ import com.unciv.models.ruleset.unique.Unique import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.removeConditionals import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts object UnitActionModifiers { fun canUse(unit: MapUnit, actionUnique: Unique): Boolean { diff --git a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionsFromUniques.kt b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionsFromUniques.kt index bfcd14a877..23a2c6d114 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionsFromUniques.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/unit/actions/UnitActionsFromUniques.kt @@ -19,7 +19,7 @@ import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.translations.fillPlaceholders import com.unciv.models.translations.removeConditionals import com.unciv.models.translations.tr -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.popups.ConfirmPopup import com.unciv.ui.screens.pickerscreens.ImprovementPickerScreen diff --git a/desktop/src/com/unciv/app/desktop/DesktopFont.kt b/desktop/src/com/unciv/app/desktop/DesktopFont.kt index 10f02c7d34..f353ee91d3 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopFont.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopFont.kt @@ -2,10 +2,10 @@ package com.unciv.app.desktop import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Pixmap -import com.unciv.ui.components.FontFamilyData -import com.unciv.ui.components.FontImplementation -import com.unciv.ui.components.FontMetricsCommon -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.FontFamilyData +import com.unciv.ui.components.fonts.FontImplementation +import com.unciv.ui.components.fonts.FontMetricsCommon +import com.unciv.ui.components.fonts.Fonts import java.awt.Color import java.awt.Font import java.awt.FontMetrics diff --git a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt index 57af05ef9d..0cb4a9049c 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt @@ -10,7 +10,7 @@ import com.unciv.logic.files.SETTINGS_FILE_NAME import com.unciv.logic.files.UncivFiles import com.unciv.models.metadata.ScreenSize import com.unciv.models.metadata.WindowState -import com.unciv.ui.components.Fonts +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.utils.Display import com.unciv.utils.Log diff --git a/tests/src/com/unciv/dev/FasterUIDevelopment.kt b/tests/src/com/unciv/dev/FasterUIDevelopment.kt index ab1de42ffd..1db01b0ca7 100644 --- a/tests/src/com/unciv/dev/FasterUIDevelopment.kt +++ b/tests/src/com/unciv/dev/FasterUIDevelopment.kt @@ -14,12 +14,12 @@ import com.badlogic.gdx.scenes.scene2d.utils.Layout import com.unciv.UncivGame import com.unciv.dev.FasterUIDevelopment.DevElement import com.unciv.logic.files.UncivFiles -import com.unciv.ui.components.FontFamilyData -import com.unciv.ui.components.FontImplementation -import com.unciv.ui.components.FontMetricsCommon -import com.unciv.ui.components.Fonts import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.toLabel +import com.unciv.ui.components.fonts.FontFamilyData +import com.unciv.ui.components.fonts.FontImplementation +import com.unciv.ui.components.fonts.FontMetricsCommon +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageWithCustomSize import com.unciv.ui.screens.basescreen.BaseScreen