mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 19:08:48 -04:00
Modding: allow mods to supply custom fonts (#8715)
* Modding: allow mods to supply custom fonts * Cleanup * Code cleanup --------- Co-authored-by: vegeta1k95 <vfylfhby>
This commit is contained in:
parent
96fdbbff09
commit
c593056e42
@ -19,7 +19,6 @@ import com.unciv.logic.files.UncivFiles
|
|||||||
import com.unciv.logic.event.EventBus
|
import com.unciv.logic.event.EventBus
|
||||||
import com.unciv.ui.screens.basescreen.UncivStage
|
import com.unciv.ui.screens.basescreen.UncivStage
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
import com.unciv.ui.components.Fonts
|
|
||||||
import com.unciv.utils.Log
|
import com.unciv.utils.Log
|
||||||
import com.unciv.utils.concurrency.Concurrency
|
import com.unciv.utils.concurrency.Concurrency
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -41,7 +40,6 @@ open class AndroidLauncher : AndroidApplication() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val settings = UncivFiles.getSettingsForPlatformLaunchers(filesDir.path)
|
val settings = UncivFiles.getSettingsForPlatformLaunchers(filesDir.path)
|
||||||
val fontFamily = settings.fontFamily
|
|
||||||
|
|
||||||
// Manage orientation lock and display cutout
|
// Manage orientation lock and display cutout
|
||||||
val platformSpecificHelper = PlatformSpecificHelpersAndroid(this)
|
val platformSpecificHelper = PlatformSpecificHelpersAndroid(this)
|
||||||
@ -51,7 +49,7 @@ open class AndroidLauncher : AndroidApplication() {
|
|||||||
|
|
||||||
val androidParameters = UncivGameParameters(
|
val androidParameters = UncivGameParameters(
|
||||||
crashReportSysInfo = CrashReportSysInfoAndroid,
|
crashReportSysInfo = CrashReportSysInfoAndroid,
|
||||||
fontImplementation = NativeFontAndroid((Fonts.ORIGINAL_FONT_SIZE * settings.fontSizeMultiplier).toInt(), fontFamily),
|
fontImplementation = FontAndroid(),
|
||||||
customFileLocationHelper = customFileLocationHelper,
|
customFileLocationHelper = customFileLocationHelper,
|
||||||
platformSpecificHelper = platformSpecificHelper
|
platformSpecificHelper = platformSpecificHelper
|
||||||
)
|
)
|
||||||
|
112
android/src/com/unciv/app/NativeFontAndroid.kt → android/src/com/unciv/app/FontAndroid.kt
Executable file → Normal file
112
android/src/com/unciv/app/NativeFontAndroid.kt → android/src/com/unciv/app/FontAndroid.kt
Executable file → Normal file
@ -9,55 +9,95 @@ import android.graphics.fonts.FontFamily
|
|||||||
import android.graphics.fonts.FontStyle
|
import android.graphics.fonts.FontStyle
|
||||||
import android.graphics.fonts.SystemFonts
|
import android.graphics.fonts.SystemFonts
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.unciv.ui.components.FontFamilyData
|
import com.unciv.ui.components.FontFamilyData
|
||||||
import com.unciv.ui.components.NativeFontImplementation
|
import com.unciv.ui.components.FontImplementation
|
||||||
|
import com.unciv.ui.components.Fonts
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
|
||||||
/**
|
class FontAndroid : FontImplementation {
|
||||||
* Created by tian on 2016/10/2.
|
|
||||||
*/
|
private val fontList: HashSet<Font> = hashSetOf()
|
||||||
class NativeFontAndroid(
|
private val paint: Paint = Paint()
|
||||||
private val size: Int,
|
private var currentFontFamily: String? = null
|
||||||
private val fontFamily: String
|
|
||||||
) : NativeFontImplementation {
|
init {
|
||||||
private val fontList by lazy{
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) emptySet()
|
fontList.addAll(SystemFonts.getAvailableFonts())
|
||||||
else SystemFonts.getAvailableFonts()
|
paint.isAntiAlias = true
|
||||||
|
paint.strokeWidth = 0f
|
||||||
|
paint.setARGB(255, 255, 255, 255)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val paint by lazy{ createPaint() }
|
override fun setFontFamily(fontFamilyData: FontFamilyData, size: Int) {
|
||||||
fun createPaint() = Paint().apply {
|
paint.textSize = size.toFloat()
|
||||||
typeface = if (fontFamily.isNotBlank() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
||||||
// Helper within the VERSION_CODES.Q gate: Evaluate a Font's desirability (lower = better) for a given family.
|
// Don't have to reload typeface if font-family didn't change
|
||||||
fun Font.matchesFamily(family: String): Int {
|
if (currentFontFamily != fontFamilyData.invariantName) {
|
||||||
val name = file?.nameWithoutExtension ?: return Int.MAX_VALUE
|
currentFontFamily = fontFamilyData.invariantName
|
||||||
if (name == family) return 0
|
|
||||||
if (!name.startsWith("$family-")) return Int.MAX_VALUE
|
// Mod font
|
||||||
if (style.weight == FontStyle.FONT_WEIGHT_NORMAL && style.slant == FontStyle.FONT_SLANT_UPRIGHT) return 1
|
if (fontFamilyData.filePath != null)
|
||||||
return 2 +
|
{
|
||||||
abs(style.weight - FontStyle.FONT_WEIGHT_NORMAL) / 100 +
|
paint.typeface = createTypefaceCustom(fontFamilyData.filePath!!)
|
||||||
abs(style.slant - FontStyle.FONT_SLANT_UPRIGHT)
|
|
||||||
}
|
}
|
||||||
|
// System font
|
||||||
|
else
|
||||||
|
{
|
||||||
|
paint.typeface = createTypefaceSystem(fontFamilyData.invariantName)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTypefaceSystem(name: String): Typeface {
|
||||||
|
if (name.isNotBlank() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||||
|
{
|
||||||
val font = fontList.mapNotNull {
|
val font = fontList.mapNotNull {
|
||||||
val distanceToRegular = it.matchesFamily(fontFamily)
|
val distanceToRegular = it.matchesFamily(name)
|
||||||
if (distanceToRegular == Int.MAX_VALUE) null else it to distanceToRegular
|
if (distanceToRegular == Int.MAX_VALUE) null else it to distanceToRegular
|
||||||
}.minByOrNull { it.second }?.first
|
}.minByOrNull { it.second }?.first
|
||||||
if (font != null) {
|
|
||||||
Typeface.CustomFallbackBuilder(FontFamily.Builder(font).build())
|
|
||||||
.setSystemFallback(fontFamily).build()
|
|
||||||
} else Typeface.create(fontFamily, Typeface.NORMAL)
|
|
||||||
} else Typeface.create(fontFamily, Typeface.NORMAL)
|
|
||||||
|
|
||||||
isAntiAlias = true
|
if (font != null)
|
||||||
textSize = size.toFloat()
|
{
|
||||||
strokeWidth = 0f
|
return Typeface.CustomFallbackBuilder(FontFamily.Builder(font).build())
|
||||||
setARGB(255, 255, 255, 255)
|
.setSystemFallback(name).build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Typeface.create(name, Typeface.NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createTypefaceCustom(path: String): Typeface {
|
||||||
|
return try
|
||||||
|
{
|
||||||
|
Typeface.createFromFile(Gdx.files.local(path).file())
|
||||||
|
}
|
||||||
|
catch (e: Exception)
|
||||||
|
{
|
||||||
|
// Falling back to default
|
||||||
|
Typeface.create(Fonts.DEFAULT_FONT_FAMILY, Typeface.NORMAL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper within the VERSION_CODES.Q gate: Evaluate a Font's desirability (lower = better) for a given family. */
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
|
private fun Font.matchesFamily(family: String): Int {
|
||||||
|
val name = file?.nameWithoutExtension ?: return Int.MAX_VALUE
|
||||||
|
if (name == family) return 0
|
||||||
|
if (!name.startsWith("$family-")) return Int.MAX_VALUE
|
||||||
|
if (style.weight == FontStyle.FONT_WEIGHT_NORMAL && style.slant == FontStyle.FONT_SLANT_UPRIGHT) return 1
|
||||||
|
return 2 +
|
||||||
|
abs(style.weight - FontStyle.FONT_WEIGHT_NORMAL) / 100 +
|
||||||
|
abs(style.slant - FontStyle.FONT_SLANT_UPRIGHT)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFontSize(): Int {
|
override fun getFontSize(): Int {
|
||||||
return size
|
return paint.textSize.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCharPixmap(char: Char): Pixmap {
|
override fun getCharPixmap(char: Char): Pixmap {
|
||||||
@ -65,7 +105,7 @@ class NativeFontAndroid(
|
|||||||
var width = paint.measureText(char.toString()).toInt()
|
var width = paint.measureText(char.toString()).toInt()
|
||||||
var height = (metric.descent - metric.ascent).toInt()
|
var height = (metric.descent - metric.ascent).toInt()
|
||||||
if (width == 0) {
|
if (width == 0) {
|
||||||
height = size
|
height = getFontSize()
|
||||||
width = height
|
width = height
|
||||||
}
|
}
|
||||||
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
||||||
@ -84,7 +124,7 @@ class NativeFontAndroid(
|
|||||||
return pixmap
|
return pixmap
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAvailableFontFamilies(): Sequence<FontFamilyData> {
|
override fun getSystemFonts(): Sequence<FontFamilyData> {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q)
|
||||||
return sequenceOf(FontFamilyData("sans-serif"), FontFamilyData("serif"), FontFamilyData("mono"))
|
return sequenceOf(FontFamilyData("sans-serif"), FontFamilyData("serif"), FontFamilyData("mono"))
|
||||||
|
|
@ -27,6 +27,7 @@ import com.unciv.ui.audio.MusicController
|
|||||||
import com.unciv.ui.audio.MusicMood
|
import com.unciv.ui.audio.MusicMood
|
||||||
import com.unciv.ui.audio.MusicTrackChooserFlags
|
import com.unciv.ui.audio.MusicTrackChooserFlags
|
||||||
import com.unciv.ui.audio.SoundPlayer
|
import com.unciv.ui.audio.SoundPlayer
|
||||||
|
import com.unciv.ui.components.FontImplementation
|
||||||
import com.unciv.ui.crashhandling.CrashScreen
|
import com.unciv.ui.crashhandling.CrashScreen
|
||||||
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
|
import com.unciv.ui.crashhandling.wrapCrashHandlingUnit
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
@ -73,6 +74,10 @@ object GUI {
|
|||||||
return UncivGame.Current.settings
|
return UncivGame.Current.settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFontImpl(): FontImplementation {
|
||||||
|
return UncivGame.Current.fontImplementation!!
|
||||||
|
}
|
||||||
|
|
||||||
fun isWorldLoaded(): Boolean {
|
fun isWorldLoaded(): Boolean {
|
||||||
return UncivGame.Current.worldScreen != null
|
return UncivGame.Current.worldScreen != null
|
||||||
}
|
}
|
||||||
@ -216,7 +221,7 @@ class UncivGame(parameters: UncivGameParameters) : Game() {
|
|||||||
|
|
||||||
// Loading available fonts can take a long time on Android phones.
|
// Loading available fonts can take a long time on Android phones.
|
||||||
// Therefore we initialize the lazy parameters in the font implementation, while we're in another thread, to avoid ANRs on main thread
|
// Therefore we initialize the lazy parameters in the font implementation, while we're in another thread, to avoid ANRs on main thread
|
||||||
fontImplementation?.getCharPixmap('S')
|
fontImplementation?.setFontFamily(settings.fontFamilyData, settings.getFontSize())
|
||||||
|
|
||||||
// This stuff needs to run on the main thread because it needs the GL context
|
// This stuff needs to run on the main thread because it needs the GL context
|
||||||
launchOnGLThread {
|
launchOnGLThread {
|
||||||
|
@ -4,11 +4,11 @@ import com.unciv.logic.files.CustomFileLocationHelper
|
|||||||
import com.unciv.ui.crashhandling.CrashReportSysInfo
|
import com.unciv.ui.crashhandling.CrashReportSysInfo
|
||||||
import com.unciv.ui.components.AudioExceptionHelper
|
import com.unciv.ui.components.AudioExceptionHelper
|
||||||
import com.unciv.ui.components.GeneralPlatformSpecificHelpers
|
import com.unciv.ui.components.GeneralPlatformSpecificHelpers
|
||||||
import com.unciv.ui.components.NativeFontImplementation
|
import com.unciv.ui.components.FontImplementation
|
||||||
|
|
||||||
class UncivGameParameters(val crashReportSysInfo: CrashReportSysInfo? = null,
|
class UncivGameParameters(val crashReportSysInfo: CrashReportSysInfo? = null,
|
||||||
val cancelDiscordEvent: (() -> Unit)? = null,
|
val cancelDiscordEvent: (() -> Unit)? = null,
|
||||||
val fontImplementation: NativeFontImplementation? = null,
|
val fontImplementation: FontImplementation? = null,
|
||||||
val consoleMode: Boolean = false,
|
val consoleMode: Boolean = false,
|
||||||
val customFileLocationHelper: CustomFileLocationHelper? = null,
|
val customFileLocationHelper: CustomFileLocationHelper? = null,
|
||||||
val platformSpecificHelper: GeneralPlatformSpecificHelpers? = null,
|
val platformSpecificHelper: GeneralPlatformSpecificHelpers? = null,
|
||||||
|
@ -6,6 +6,7 @@ import com.unciv.Constants
|
|||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.multiplayer.FriendList
|
import com.unciv.logic.multiplayer.FriendList
|
||||||
import com.unciv.models.UncivSound
|
import com.unciv.models.UncivSound
|
||||||
|
import com.unciv.ui.components.FontFamilyData
|
||||||
import com.unciv.ui.components.Fonts
|
import com.unciv.ui.components.Fonts
|
||||||
import java.text.Collator
|
import java.text.Collator
|
||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
@ -96,7 +97,7 @@ class GameSettings {
|
|||||||
/** Saves the last successful new game's setup */
|
/** Saves the last successful new game's setup */
|
||||||
var lastGameSetup: GameSetupInfo? = null
|
var lastGameSetup: GameSetupInfo? = null
|
||||||
|
|
||||||
var fontFamily: String = Fonts.DEFAULT_FONT_FAMILY
|
var fontFamilyData: FontFamilyData = FontFamilyData.default
|
||||||
var fontSizeMultiplier: Float = 1f
|
var fontSizeMultiplier: Float = 1f
|
||||||
|
|
||||||
var enableEasterEggs: Boolean = true
|
var enableEasterEggs: Boolean = true
|
||||||
@ -139,6 +140,10 @@ class GameSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getFontSize(): Int {
|
||||||
|
return (Fonts.ORIGINAL_FONT_SIZE * fontSizeMultiplier).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
fun getCurrentLocale(): Locale {
|
fun getCurrentLocale(): Locale {
|
||||||
if (locale == null)
|
if (locale == null)
|
||||||
updateLocaleFromLanguage()
|
updateLocaleFromLanguage()
|
||||||
|
@ -12,15 +12,24 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|||||||
import com.badlogic.gdx.utils.Array
|
import com.badlogic.gdx.utils.Array
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.GUI
|
||||||
import com.unciv.UncivGame
|
import com.unciv.UncivGame
|
||||||
import com.unciv.models.translations.tr
|
import com.unciv.models.translations.tr
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
|
||||||
|
|
||||||
interface NativeFontImplementation {
|
|
||||||
|
interface FontImplementation {
|
||||||
|
fun setFontFamily(fontFamilyData: FontFamilyData, size: Int)
|
||||||
fun getFontSize(): Int
|
fun getFontSize(): Int
|
||||||
fun getCharPixmap(char: Char): Pixmap
|
fun getCharPixmap(char: Char): Pixmap
|
||||||
fun getAvailableFontFamilies(): Sequence<FontFamilyData>
|
fun getSystemFonts(): Sequence<FontFamilyData>
|
||||||
|
|
||||||
|
fun getBitmapFont(): BitmapFont {
|
||||||
|
val fontData = NativeBitmapFontData(this)
|
||||||
|
val font = BitmapFont(fontData, fontData.regions, false)
|
||||||
|
font.setOwnsTexture(true)
|
||||||
|
return font
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If save in `GameSettings` need use invariantFamily.
|
// If save in `GameSettings` need use invariantFamily.
|
||||||
@ -28,8 +37,13 @@ interface NativeFontImplementation {
|
|||||||
// If save localName in `GameSettings` may generate garbled characters by encoding.
|
// If save localName in `GameSettings` may generate garbled characters by encoding.
|
||||||
class FontFamilyData(
|
class FontFamilyData(
|
||||||
val localName: String,
|
val localName: String,
|
||||||
val invariantName: String = localName
|
val invariantName: String = localName,
|
||||||
|
val filePath: String? = null
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
// For serialization
|
||||||
|
constructor() : this(default.localName, default.invariantName)
|
||||||
|
|
||||||
// Implement kotlin equality contract such that _only_ the invariantName field is compared.
|
// Implement kotlin equality contract such that _only_ the invariantName field is compared.
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return if (other is FontFamilyData) invariantName == other.invariantName
|
return if (other is FontFamilyData) invariantName == other.invariantName
|
||||||
@ -39,16 +53,16 @@ class FontFamilyData(
|
|||||||
override fun hashCode() = invariantName.hashCode()
|
override fun hashCode() = invariantName.hashCode()
|
||||||
|
|
||||||
/** For SelectBox usage */
|
/** For SelectBox usage */
|
||||||
override fun toString() = localName
|
override fun toString() = localName.tr()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val default = FontFamilyData("Default Font".tr(), Fonts.DEFAULT_FONT_FAMILY)
|
val default = FontFamilyData("Default Font", Fonts.DEFAULT_FONT_FAMILY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This class is loosely based on libgdx's FreeTypeBitmapFontData
|
// This class is loosely based on libgdx's FreeTypeBitmapFontData
|
||||||
class NativeBitmapFontData(
|
class NativeBitmapFontData(
|
||||||
private val fontImplementation: NativeFontImplementation
|
private val fontImplementation: FontImplementation
|
||||||
) : BitmapFontData(), Disposable {
|
) : BitmapFontData(), Disposable {
|
||||||
|
|
||||||
val regions: Array<TextureRegion>
|
val regions: Array<TextureRegion>
|
||||||
@ -80,6 +94,8 @@ class NativeBitmapFontData(
|
|||||||
// Set space glyph.
|
// Set space glyph.
|
||||||
val spaceGlyph = getGlyph(' ')
|
val spaceGlyph = getGlyph(' ')
|
||||||
spaceXadvance = spaceGlyph.xadvance.toFloat()
|
spaceXadvance = spaceGlyph.xadvance.toFloat()
|
||||||
|
|
||||||
|
setScale(Constants.defaultFontSize / Fonts.ORIGINAL_FONT_SIZE)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getGlyph(ch: Char): Glyph {
|
override fun getGlyph(ch: Char): Glyph {
|
||||||
@ -167,29 +183,17 @@ object Fonts {
|
|||||||
* Do not call from normal code - reset the Skin instead: `BaseScreen.setSkin()`
|
* Do not call from normal code - reset the Skin instead: `BaseScreen.setSkin()`
|
||||||
*/
|
*/
|
||||||
fun resetFont() {
|
fun resetFont() {
|
||||||
val fontData = NativeBitmapFontData(UncivGame.Current.fontImplementation!!)
|
val settings = GUI.getSettings()
|
||||||
font = BitmapFont(fontData, fontData.regions, false)
|
val fontImpl = GUI.getFontImpl()
|
||||||
font.setOwnsTexture(true)
|
fontImpl.setFontFamily(settings.fontFamilyData, settings.getFontSize())
|
||||||
font.data.setScale(Constants.defaultFontSize / ORIGINAL_FONT_SIZE)
|
font = fontImpl.getBitmapFont()
|
||||||
}
|
|
||||||
|
|
||||||
/** This resets all cached font data and allows changing the font */
|
|
||||||
fun resetFont(newFamily: String) {
|
|
||||||
try {
|
|
||||||
val fontImplementationClass = UncivGame.Current.fontImplementation!!::class.java
|
|
||||||
val fontImplementationConstructor = fontImplementationClass.constructors.first()
|
|
||||||
val newFontImpl = fontImplementationConstructor.newInstance((ORIGINAL_FONT_SIZE * UncivGame.Current.settings.fontSizeMultiplier).toInt(), newFamily)
|
|
||||||
if (newFontImpl is NativeFontImplementation)
|
|
||||||
UncivGame.Current.fontImplementation = newFontImpl
|
|
||||||
} catch (ex: Exception) {}
|
|
||||||
BaseScreen.setSkin() // calls our resetFont() - needed - the Skin seems to cache glyphs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Reduce the font list returned by platform-specific code to font families (plain variant if possible) */
|
/** Reduce the font list returned by platform-specific code to font families (plain variant if possible) */
|
||||||
fun getAvailableFontFamilyNames(): Sequence<FontFamilyData> {
|
fun getSystemFonts(): Sequence<FontFamilyData> {
|
||||||
val fontImplementation = UncivGame.Current.fontImplementation
|
val fontImplementation = UncivGame.Current.fontImplementation
|
||||||
?: return emptySequence()
|
?: return emptySequence()
|
||||||
return fontImplementation.getAvailableFontFamilies()
|
return fontImplementation.getSystemFonts()
|
||||||
.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.localName })
|
.sortedWith(compareBy(UncivGame.Current.settings.getCollatorFromLocale()) { it.localName })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,25 +116,57 @@ private fun addFontFamilySelect(table: Table, settings: GameSettings, selectBoxM
|
|||||||
// Therefore, _selecting_ an item in a `SelectBox` by an instance of `FontFamilyData` where only the `invariantName` is valid won't work properly.
|
// Therefore, _selecting_ an item in a `SelectBox` by an instance of `FontFamilyData` where only the `invariantName` is valid won't work properly.
|
||||||
//
|
//
|
||||||
// This is why it's _not_ `fontSelectBox.selected = FontFamilyData(settings.fontFamily)`
|
// This is why it's _not_ `fontSelectBox.selected = FontFamilyData(settings.fontFamily)`
|
||||||
val fontToSelect = settings.fontFamily
|
val fontToSelect = settings.fontFamilyData
|
||||||
fontSelectBox.selected = fonts.firstOrNull { it.invariantName == fontToSelect } // will default to first entry if `null` is passed
|
fontSelectBox.selected = fonts.firstOrNull { it.invariantName == fontToSelect.invariantName } // will default to first entry if `null` is passed
|
||||||
|
|
||||||
selectCell.setActor(fontSelectBox).minWidth(selectBoxMinWidth).pad(10f)
|
selectCell.setActor(fontSelectBox).minWidth(selectBoxMinWidth).pad(10f)
|
||||||
|
|
||||||
fontSelectBox.onChange {
|
fontSelectBox.onChange {
|
||||||
settings.fontFamily = fontSelectBox.selected.invariantName
|
settings.fontFamilyData = fontSelectBox.selected
|
||||||
Fonts.resetFont(settings.fontFamily)
|
|
||||||
onFontChange()
|
onFontChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a heavy operation and causes ANRs
|
||||||
Concurrency.run("Add Font Select") {
|
Concurrency.run("Add Font Select") {
|
||||||
// This is a heavy operation and causes ANRs
|
|
||||||
val fonts = Array<FontFamilyData>().apply {
|
val fonts = Array<FontFamilyData>()
|
||||||
add(FontFamilyData.default)
|
|
||||||
for (font in Fonts.getAvailableFontFamilyNames())
|
// Add default font
|
||||||
add(font)
|
fonts.add(FontFamilyData.default)
|
||||||
|
|
||||||
|
// Add mods fonts
|
||||||
|
val modsDir = Gdx.files.local("mods/")
|
||||||
|
for (mod in modsDir.list()) {
|
||||||
|
|
||||||
|
// Not a dir, continue
|
||||||
|
if (!mod.isDirectory)
|
||||||
|
continue
|
||||||
|
|
||||||
|
val modFontsDir = mod.child("fonts")
|
||||||
|
|
||||||
|
// Mod doesn't have fonts, continue
|
||||||
|
if (!modFontsDir.exists())
|
||||||
|
continue
|
||||||
|
|
||||||
|
// Find .ttf files and add construct FontFamilyData
|
||||||
|
for (fontFile in modFontsDir.list()) {
|
||||||
|
if (fontFile.extension().lowercase() == "ttf") {
|
||||||
|
fonts.add(
|
||||||
|
FontFamilyData(
|
||||||
|
"${fontFile.nameWithoutExtension()} (${mod.name()})",
|
||||||
|
fontFile.nameWithoutExtension(),
|
||||||
|
fontFile.path())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add system fonts
|
||||||
|
for (font in Fonts.getSystemFonts())
|
||||||
|
fonts.add(font)
|
||||||
|
|
||||||
launchOnGLThread { loadFontSelect(fonts, selectCell) }
|
launchOnGLThread { loadFontSelect(fonts, selectCell) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -154,10 +186,8 @@ private fun addFontSizeMultiplier(
|
|||||||
settings.save()
|
settings.save()
|
||||||
}
|
}
|
||||||
fontSizeSlider.onChange {
|
fontSizeSlider.onChange {
|
||||||
if (!fontSizeSlider.isDragging) {
|
if (!fontSizeSlider.isDragging)
|
||||||
Fonts.resetFont(settings.fontFamily)
|
|
||||||
onFontChange()
|
onFontChange()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
table.add(fontSizeSlider).pad(5f).row()
|
table.add(fontSizeSlider).pad(5f).row()
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ import com.unciv.logic.files.SETTINGS_FILE_NAME
|
|||||||
import com.unciv.logic.files.UncivFiles
|
import com.unciv.logic.files.UncivFiles
|
||||||
import com.unciv.models.metadata.ScreenSize
|
import com.unciv.models.metadata.ScreenSize
|
||||||
import com.unciv.models.metadata.WindowState
|
import com.unciv.models.metadata.WindowState
|
||||||
import com.unciv.ui.components.Fonts
|
|
||||||
import com.unciv.utils.Log
|
import com.unciv.utils.Log
|
||||||
import com.unciv.utils.debug
|
import com.unciv.utils.debug
|
||||||
import java.awt.GraphicsEnvironment
|
import java.awt.GraphicsEnvironment
|
||||||
@ -73,7 +72,7 @@ internal object DesktopLauncher {
|
|||||||
val platformSpecificHelper = PlatformSpecificHelpersDesktop(config)
|
val platformSpecificHelper = PlatformSpecificHelpersDesktop(config)
|
||||||
val desktopParameters = UncivGameParameters(
|
val desktopParameters = UncivGameParameters(
|
||||||
cancelDiscordEvent = { discordTimer?.cancel() },
|
cancelDiscordEvent = { discordTimer?.cancel() },
|
||||||
fontImplementation = NativeFontDesktop((Fonts.ORIGINAL_FONT_SIZE * settings.fontSizeMultiplier).toInt(), settings.fontFamily),
|
fontImplementation = FontDesktop(),
|
||||||
customFileLocationHelper = CustomFileLocationHelperDesktop(),
|
customFileLocationHelper = CustomFileLocationHelperDesktop(),
|
||||||
crashReportSysInfo = CrashReportSysInfoDesktop(),
|
crashReportSysInfo = CrashReportSysInfoDesktop(),
|
||||||
platformSpecificHelper = platformSpecificHelper,
|
platformSpecificHelper = platformSpecificHelper,
|
||||||
|
61
desktop/src/com/unciv/app/desktop/NativeFontDesktop.kt → desktop/src/com/unciv/app/desktop/FontDesktop.kt
Executable file → Normal file
61
desktop/src/com/unciv/app/desktop/NativeFontDesktop.kt → desktop/src/com/unciv/app/desktop/FontDesktop.kt
Executable file → Normal file
@ -1,35 +1,66 @@
|
|||||||
package com.unciv.app.desktop
|
package com.unciv.app.desktop
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
import com.badlogic.gdx.graphics.Pixmap
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
import com.unciv.ui.components.FontFamilyData
|
import com.unciv.ui.components.FontFamilyData
|
||||||
import com.unciv.ui.components.NativeFontImplementation
|
import com.unciv.ui.components.FontImplementation
|
||||||
|
import com.unciv.ui.components.Fonts
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class NativeFontDesktop(private val size: Int, private val fontFamily: String) :
|
|
||||||
NativeFontImplementation {
|
class FontDesktop : FontImplementation {
|
||||||
private val font by lazy {
|
|
||||||
Font(fontFamily, Font.PLAIN, size)
|
private lateinit var font: Font
|
||||||
|
private lateinit var metric: FontMetrics
|
||||||
|
|
||||||
|
override fun setFontFamily(fontFamilyData: FontFamilyData, size: Int) {
|
||||||
|
|
||||||
|
// Mod font
|
||||||
|
if (fontFamilyData.filePath != null)
|
||||||
|
{
|
||||||
|
this.font = createFontFromFile(fontFamilyData.filePath!!, size)
|
||||||
|
}
|
||||||
|
// System font
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.font = Font(fontFamilyData.invariantName, Font.PLAIN, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bufferedImage = BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
|
val graphics = bufferedImage.createGraphics()
|
||||||
|
this.metric = graphics.getFontMetrics(font)
|
||||||
|
graphics.dispose()
|
||||||
}
|
}
|
||||||
private val metric by lazy {
|
|
||||||
val bi = BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)
|
private fun createFontFromFile(path: String, size: Int): Font {
|
||||||
val g = bi.createGraphics()
|
var font: Font
|
||||||
g.font = font
|
try
|
||||||
val fontMetrics = g.fontMetrics
|
{
|
||||||
g.dispose()
|
// Try to create and register new font
|
||||||
fontMetrics
|
val fontFile = Gdx.files.local(path).file()
|
||||||
|
val ge = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||||
|
font = Font.createFont(Font.TRUETYPE_FONT, fontFile).deriveFont(size.toFloat())
|
||||||
|
ge.registerFont(font)
|
||||||
|
}
|
||||||
|
catch (e: Exception)
|
||||||
|
{
|
||||||
|
// Fallback to default, if failed.
|
||||||
|
font = Font(Fonts.DEFAULT_FONT_FAMILY, Font.PLAIN, size)
|
||||||
|
}
|
||||||
|
return font
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFontSize(): Int {
|
override fun getFontSize(): Int {
|
||||||
return size
|
return font.size
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getCharPixmap(char: Char): Pixmap {
|
override fun getCharPixmap(char: Char): Pixmap {
|
||||||
var width = metric.charWidth(char)
|
var width = metric.charWidth(char)
|
||||||
var height = metric.ascent + metric.descent
|
var height = metric.ascent + metric.descent
|
||||||
if (width == 0) {
|
if (width == 0) {
|
||||||
height = size
|
height = font.size
|
||||||
width = height
|
width = height
|
||||||
}
|
}
|
||||||
val bi = BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR)
|
val bi = BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
@ -50,7 +81,7 @@ class NativeFontDesktop(private val size: Int, private val fontFamily: String) :
|
|||||||
return pixmap
|
return pixmap
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAvailableFontFamilies(): Sequence<FontFamilyData> {
|
override fun getSystemFonts(): Sequence<FontFamilyData> {
|
||||||
val cjkLanguage = " CJK " +System.getProperty("user.language").uppercase()
|
val cjkLanguage = " CJK " +System.getProperty("user.language").uppercase()
|
||||||
return GraphicsEnvironment.getLocalGraphicsEnvironment().allFonts.asSequence()
|
return GraphicsEnvironment.getLocalGraphicsEnvironment().allFonts.asSequence()
|
||||||
.filter { " CJK " !in it.fontName || cjkLanguage in it.fontName }
|
.filter { " CJK " !in it.fontName || cjkLanguage in it.fontName }
|
@ -19,7 +19,7 @@ import com.unciv.ui.images.ImageWithCustomSize
|
|||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
import com.unciv.ui.components.FontFamilyData
|
import com.unciv.ui.components.FontFamilyData
|
||||||
import com.unciv.ui.components.Fonts
|
import com.unciv.ui.components.Fonts
|
||||||
import com.unciv.ui.components.NativeFontImplementation
|
import com.unciv.ui.components.FontImplementation
|
||||||
import com.unciv.ui.components.extensions.center
|
import com.unciv.ui.components.extensions.center
|
||||||
import com.unciv.ui.components.extensions.toLabel
|
import com.unciv.ui.components.extensions.toLabel
|
||||||
import com.unciv.utils.concurrency.Concurrency
|
import com.unciv.utils.concurrency.Concurrency
|
||||||
@ -62,7 +62,7 @@ object FasterUIDevelopment {
|
|||||||
|
|
||||||
class UIDevGame : Game() {
|
class UIDevGame : Game() {
|
||||||
val game = UncivGame(UncivGameParameters(
|
val game = UncivGame(UncivGameParameters(
|
||||||
fontImplementation = NativeFontDesktop()
|
fontImplementation = FontDesktop()
|
||||||
))
|
))
|
||||||
override fun create() {
|
override fun create() {
|
||||||
UncivGame.Current = game
|
UncivGame.Current = game
|
||||||
@ -126,7 +126,7 @@ object FasterUIDevelopment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class NativeFontDesktop : NativeFontImplementation {
|
class FontDesktop : FontImplementation {
|
||||||
private val font by lazy {
|
private val font by lazy {
|
||||||
Font(Fonts.DEFAULT_FONT_FAMILY, Font.PLAIN, Fonts.ORIGINAL_FONT_SIZE.toInt())
|
Font(Fonts.DEFAULT_FONT_FAMILY, Font.PLAIN, Fonts.ORIGINAL_FONT_SIZE.toInt())
|
||||||
}
|
}
|
||||||
@ -139,6 +139,10 @@ class NativeFontDesktop : NativeFontImplementation {
|
|||||||
fontMetrics
|
fontMetrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun setFontFamily(fontFamilyData: FontFamilyData, size: Int) {
|
||||||
|
// Empty
|
||||||
|
}
|
||||||
|
|
||||||
override fun getFontSize(): Int {
|
override fun getFontSize(): Int {
|
||||||
return Fonts.ORIGINAL_FONT_SIZE.toInt()
|
return Fonts.ORIGINAL_FONT_SIZE.toInt()
|
||||||
}
|
}
|
||||||
@ -168,7 +172,7 @@ class NativeFontDesktop : NativeFontImplementation {
|
|||||||
return pixmap
|
return pixmap
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAvailableFontFamilies(): Sequence<FontFamilyData> {
|
override fun getSystemFonts(): Sequence<FontFamilyData> {
|
||||||
return sequenceOf(FontFamilyData(Fonts.DEFAULT_FONT_FAMILY))
|
return sequenceOf(FontFamilyData(Fonts.DEFAULT_FONT_FAMILY))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user