Custom desktop font (#6377)

* Custom desktop font

* Add `getDesktopAllFonts` to setting custom desktop font.

* Custom font.
`desktopFontFamily` change to `fontFamily`.
Add GameSettings.getSettingsForPlatformLaunchers().

* Add `Custom font` setting UI.

* Add `Custom font` on Android.

* `Default Font` use translations.

* format

* remove open fun.

Co-authored-by: Yair Morgenstern <yairm210@hotmail.com>
This commit is contained in:
Tang
2022-03-21 14:12:16 -05:00
committed by GitHub
parent 130fd653a4
commit c1737b6183
10 changed files with 153 additions and 26 deletions

View File

@ -2,12 +2,16 @@ package com.unciv.models.metadata
import com.badlogic.gdx.Application
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.unciv.JsonParser
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.GameSaver
import com.unciv.ui.utils.Fonts
import java.text.Collator
import java.util.*
import kotlin.collections.HashSet
import kotlin.io.path.Path
data class WindowState (val width: Int = 900, val height: Int = 600)
@ -65,6 +69,8 @@ class GameSettings {
/** Saves the last successful new game's setup */
var lastGameSetup: GameSetupInfo? = null
var fontFamily: String = Fonts.DEFAULT_FONT_FAMILY
init {
// 26 = Android Oreo. Versions below may display permanent icon in notification bar.
if (Gdx.app?.type == Application.ApplicationType.Android && Gdx.app.version < 26) {
@ -104,6 +110,24 @@ class GameSettings {
fun getCollatorFromLocale(): Collator {
return Collator.getInstance(getCurrentLocale())
}
companion object {
/** Specialized function to access settings before Gdx is initialized.
*
* @param base Path to the directory where the file should be - if not set, the OS current directory is used (which is "/" on Android)
*/
fun getSettingsForPlatformLaunchers(base: String = ""): GameSettings {
// FileHandle is Gdx, but the class and JsonParser are not dependent on app initialization
// If fact, at this point Gdx.app or Gdx.files are null but this still works.
val file = FileHandle(Path(base, GameSaver.settingsFileName).toString())
return if (file.exists())
JsonParser().getFromJson(
GameSettings::class.java,
file
)
else GameSettings().apply { isFreshlyCreated = true }
}
}
}
enum class LocaleCode(var language: String, var country: String) {

View File

@ -18,6 +18,23 @@ import com.unciv.models.stats.Stat
interface NativeFontImplementation {
fun getFontSize(): Int
fun getCharPixmap(char: Char): Pixmap
fun getAvailableFont(): Collection<FontData>
}
// If save in `GameSettings` need use enName.
// If show to user need use localName.
// If save localName in `GameSettings` may generate garbled characters by encoding.
data class FontData(val localName: String, val enName: String = localName) {
override fun equals(other: Any?): Boolean {
return if (other is FontData) enName == other.enName
else super.equals(other)
}
override fun hashCode(): Int {
var result = localName.hashCode()
result = 31 * result + enName.hashCode()
return result
}
}
// This class is loosely based on libgdx's FreeTypeBitmapFontData
@ -128,8 +145,9 @@ object Fonts {
* 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 font:BitmapFont
lateinit var font: BitmapFont
fun resetFont() {
val fontData = NativeBitmapFontData(UncivGame.Current.fontImplementation!!)
font = BitmapFont(fontData, fontData.regions, false)
@ -137,6 +155,11 @@ object Fonts {
font.data.setScale(Constants.defaultFontSize / ORIGINAL_FONT_SIZE)
}
fun getAvailableFontFamilyNames(): Collection<FontData> {
if (UncivGame.Current.fontImplementation == null) return emptyList()
return UncivGame.Current.fontImplementation!!.getAvailableFont()
}
/**
* Turn a TextureRegion into a Pixmap.
*
@ -145,15 +168,15 @@ object Fonts {
* @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 {
fun extractPixmapFromTextureRegion(textureRegion: TextureRegion): Pixmap {
val textureData = textureRegion.texture.textureData
if (!textureData.isPrepared) {
textureData.prepare()
}
val pixmap = Pixmap(
textureRegion.regionWidth,
textureRegion.regionHeight,
textureData.format
textureRegion.regionWidth,
textureRegion.regionHeight,
textureData.format
)
val textureDataPixmap = textureData.consumePixmap()
pixmap.drawPixmap(

View File

@ -368,6 +368,8 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) {
}
}
addFontFamilySelect(Fonts.getAvailableFontFamilyNames())
addTranslationGeneration()
addSetUserId()
@ -879,6 +881,34 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) {
}
}
private fun Table.addFontFamilySelect(fonts: Collection<FontData>) {
if (fonts.isEmpty()) return
add("Font family".toLabel()).left().fillX()
val fontSelectBox = SelectBox<String>(skin)
val fontsLocalName = GdxArray<String>().apply { add("Default Font".tr()) }
val fontsEnName = GdxArray<String>().apply { add("") }
for (font in fonts) {
fontsLocalName.add(font.localName)
fontsEnName.add(font.enName)
}
val selectedIndex = fontsEnName.indexOf(settings.fontFamily).let { if (it == -1) 0 else it }
fontSelectBox.items = fontsLocalName
fontSelectBox.selected = fontsLocalName[selectedIndex]
add(fontSelectBox).minWidth(selectBoxMinWidth).pad(10f).row()
fontSelectBox.onChange {
settings.fontFamily = fontsEnName[fontSelectBox.selectedIndex]
ToastPopup(
"You need to restart the game for this change to take effect.", previousScreen
)
}
}
private fun Table.addTranslationGeneration() {
if (Gdx.app.type == Application.ApplicationType.Desktop) {
val generateTranslationsButton = "Generate translation files".toTextButton()