Font download now preceded by a "requires fonts, do you want to download?" message that allows you to opt out

This commit is contained in:
Yair Morgenstern 2018-12-10 10:41:13 +02:00
parent d1df5a2fdf
commit 1ba0929869
6 changed files with 220 additions and 118 deletions

View file

@ -244,6 +244,8 @@
Portuguese:"Desfazer unidade" Portuguese:"Desfazer unidade"
} }
"Explore":{}
"Do you really want to disband this unit?":{ "Do you really want to disband this unit?":{
Italian:"Vuoi davvero sciogliere questa unità?" Italian:"Vuoi davvero sciogliere questa unità?"
Russian:"Вы действительно хотите распустить этот юнит?" Russian:"Вы действительно хотите распустить этот юнит?"
@ -1894,7 +1896,7 @@
Portuguese:"Drenar pântano" Portuguese:"Drenar pântano"
} }
"Ancient Ruins":{ "Ancient ruins":{
Simplified_Chinese:"远古遗址" Simplified_Chinese:"远古遗址"
} }
"City Ruins":{ "City Ruins":{

View file

@ -1,5 +1,6 @@
package com.unciv.ui package com.unciv.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Label
@ -9,9 +10,9 @@ import com.unciv.UnCivGame
import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tr import com.unciv.models.gamebasics.tr
import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.*
import com.unciv.ui.utils.enable import com.unciv.ui.worldscreen.optionstable.PopupTable
import com.unciv.ui.utils.onClick import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable
class LanguageTable(val language:String,skin: Skin):Table(skin){ class LanguageTable(val language:String,skin: Skin):Table(skin){
@ -71,12 +72,44 @@ class LanguagePickerScreen: PickerScreen(){
} }
rightSideButton.setText("Pick language".tr()) rightSideButton.setText("Pick language".tr())
rightSideButton.onClick { rightSideButton.onClick {
UnCivGame.Current.settings.language = chosenLanguage if (Fonts().containsFont(Fonts().getFontForLanguage(chosenLanguage)))
UnCivGame.Current.settings.save() pickLanguage()
UnCivGame.Current.startNewGame() else {
dispose() YesNoPopupTable("This language requires you to download fonts.\n" +
"Do you want to download fonts for $chosenLanguage?",
{
val downloading = PopupTable()
downloading.add(Label("Downloading...",skin))
downloading.pack()
downloading.center(stage)
stage.addActor(downloading)
Gdx.input.inputProcessor = null // no interaction until download is over
kotlin.concurrent.thread {
Fonts().downloadFontForLanguage(chosenLanguage)
shouldPickLanguage = true
}
},this)
}
} }
} }
fun pickLanguage(){
UnCivGame.Current.settings.language = chosenLanguage
UnCivGame.Current.settings.save()
CameraStageBaseScreen.resetFonts()
UnCivGame.Current.startNewGame()
dispose()
}
var shouldPickLanguage=false
override fun render(delta: Float) {
if(shouldPickLanguage)
pickLanguage()
super.render(delta)
}
} }

View file

@ -5,19 +5,13 @@ import com.badlogic.gdx.Input
import com.badlogic.gdx.Screen import com.badlogic.gdx.Screen
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20 import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.Batch import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import com.badlogic.gdx.scenes.scene2d.* import com.badlogic.gdx.scenes.scene2d.*
import com.badlogic.gdx.scenes.scene2d.ui.* import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.viewport.ExtendViewport import com.badlogic.gdx.utils.viewport.ExtendViewport
import com.unciv.UnCivGame import com.unciv.UnCivGame
import com.unciv.models.gamebasics.GameBasics
import java.io.FileOutputStream
import java.net.URL
open class CameraStageBaseScreen : Screen { open class CameraStageBaseScreen : Screen {
@ -69,14 +63,14 @@ open class CameraStageBaseScreen : Screen {
} }
fun resetFonts(){ fun resetFonts(){
skin.get<TextButton.TextButtonStyle>(TextButton.TextButtonStyle::class.java).font = getFont(20) skin.get<TextButton.TextButtonStyle>(TextButton.TextButtonStyle::class.java).font = Fonts().getFont(20)
skin.get<Label.LabelStyle>(Label.LabelStyle::class.java).apply { skin.get<Label.LabelStyle>(Label.LabelStyle::class.java).apply {
font = getFont(18) font = Fonts().getFont(18)
fontColor= Color.WHITE fontColor= Color.WHITE
} }
skin.get<TextField.TextFieldStyle>(TextField.TextFieldStyle::class.java).font = getFont(18) skin.get<TextField.TextFieldStyle>(TextField.TextFieldStyle::class.java).font = Fonts().getFont(18)
skin.get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).font = getFont(20) skin.get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).font = Fonts().getFont(20)
skin.get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).listStyle.font = getFont(20) skin.get<SelectBox.SelectBoxStyle>(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts().getFont(20)
} }
internal var batch: Batch = SpriteBatch() internal var batch: Batch = SpriteBatch()
} }
@ -121,85 +115,9 @@ fun Actor.center(parent:Stage){ centerX(parent); centerY(parent)}
fun Label.setFontColor(color:Color): Label {style=Label.LabelStyle(style).apply { fontColor=color }; return this} fun Label.setFontColor(color:Color): Label {style=Label.LabelStyle(style).apply { fontColor=color }; return this}
// Contains e.g. "Arial 22", fontname and size, to BitmapFont
val fontCache = HashMap<String,BitmapFont>()
fun getFontForLanguage(): String {
if(UnCivGame.Current.settings.language.contains("Chinese")) return chineseFont
else return "Arial"
}
val chineseFont = "SimSun"
fun getCharsForFont(font:String): String {
val defaultText = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽaäàâăbcčćdđeéfghiîjklmnoöpqrsșštțuüvwxyzž" +
"АБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюя" +
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάΆέΈέΉίϊΐΊόΌύΰϋΎΫΏĂÂÊÉÔƠƯăâêôơưáéèíóú1234567890" +
"?'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|"
if(font=="Arial") return defaultText
if(font== chineseFont) {
val constants = "?'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|"
val charSet = HashSet<Char>()
charSet.addAll(constants.asIterable())
charSet.addAll(defaultText.asIterable())
for (entry in GameBasics.Translations.entries) {
for(lang in entry.value){
if(lang.key.contains("Chinese")) charSet.addAll(lang.value.asIterable())
}
}
return charSet.joinToString()
}
return ""
}
fun download(link: String, path: String) {
val input = URL(link).openStream()
val output = FileOutputStream(Gdx.files.local(path).file())
input.use {
output.use {
input.copyTo(output)
}
}
}
fun getFont(size: Int): BitmapFont {
val fontForLanguage = getFontForLanguage()
val keyForFont = "$fontForLanguage $size"
if(fontCache.containsKey(keyForFont)) return fontCache[keyForFont]!!
val generator:FreeTypeFontGenerator
if(Gdx.files.internal("skin/$fontForLanguage.ttf").exists())
generator = FreeTypeFontGenerator(Gdx.files.internal("skin/$fontForLanguage.ttf"))
else {
val localPath = "fonts/$fontForLanguage.ttf"
if (!Gdx.files.local("fonts/$fontForLanguage.ttf").exists()) {
if(!Gdx.files.local("fonts").exists())
Gdx.files.local("fonts").mkdirs()
if(fontForLanguage == chineseFont)
download("https://github.com/micmro/Stylify-Me/raw/master/.fonts/SimSun.ttf",localPath)
}
generator = FreeTypeFontGenerator(Gdx.files.internal(localPath))
}
val parameter = FreeTypeFontGenerator.FreeTypeFontParameter()
parameter.size = size
parameter.minFilter = Texture.TextureFilter.Linear
parameter.magFilter = Texture.TextureFilter.Linear
parameter.characters = getCharsForFont(fontForLanguage)
val font = generator.generateFont(parameter)
generator.dispose() // don't forget to dispose to avoid memory leaks!
fontCache[keyForFont]=font
return font
}
fun Label.setFontSize(size:Int): Label { fun Label.setFontSize(size:Int): Label {
style = Label.LabelStyle(style) style = Label.LabelStyle(style)
style.font = getFont(size) style.font = Fonts().getFont(size)
style = style // because we need it to call the SetStyle function. Yuk, I know. style = style // because we need it to call the SetStyle function. Yuk, I know.
return this // for chaining return this // for chaining
} }

View file

@ -0,0 +1,104 @@
package com.unciv.ui.utils
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.BitmapFont
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator
import com.unciv.UnCivGame
import com.unciv.models.gamebasics.GameBasics
import java.io.FileOutputStream
import java.net.URL
class Fonts {
companion object {
// Contains e.g. "Arial 22", fontname and size, to BitmapFont
val fontCache = HashMap<String, BitmapFont>()
}
fun getFontForLanguage(language:String): String {
if (language.contains("Chinese")) return chineseFont
else return "Arial"
}
val chineseFont = "SimSun"
fun getCharsForFont(font: String): String {
val defaultText = "ABCČĆDĐEFGHIJKLMNOPQRSŠTUVWXYZŽaäàâăbcčćdđeéfghiîjklmnoöpqrsșštțuüvwxyzž" +
"АБВГҐДЂЕЁЄЖЗЅИІЇЙЈКЛЉМНЊОПРСТЋУЎФХЦЧЏШЩЪЫЬЭЮЯабвгґдђеёєжзѕиіїйјклљмнњопрстћуўфхцчџшщъыьэюя" +
"ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάΆέΈέΉίϊΐΊόΌύΰϋΎΫΏĂÂÊÉÔƠƯăâêôơưáéèíóú1234567890" +
"?'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|"
if (font == "Arial") return defaultText
if (font == chineseFont) {
val constants = "?'“!”(%)[#]{@}/&\\<-+÷×=>®©\$€£¥¢:;,.*|"
val charSet = HashSet<Char>()
charSet.addAll(constants.asIterable())
charSet.addAll(defaultText.asIterable())
for (entry in GameBasics.Translations.entries) {
for (lang in entry.value) {
if (lang.key.contains("Chinese")) charSet.addAll(lang.value.asIterable())
}
}
return charSet.joinToString()
}
return ""
}
fun download(link: String, path: String) {
val input = URL(link).openStream()
val output = FileOutputStream(Gdx.files.local(path).file())
input.use {
output.use {
input.copyTo(output)
}
}
}
fun containsFont(font:String): Boolean {
if (Gdx.files.internal("skin/$font.ttf").exists())
return true
if (Gdx.files.local("fonts/$font.ttf").exists())
return true
return false
}
fun downloadFontForLanguage(language:String){
val font = getFontForLanguage(language)
if(containsFont(language)) return
if (!Gdx.files.local("fonts").exists())
Gdx.files.local("fonts").mkdirs()
val localPath = "fonts/$font.ttf"
if (font == chineseFont)
download("https://github.com/micmro/Stylify-Me/raw/master/.fonts/SimSun.ttf", localPath)
}
fun getFont(size: Int): BitmapFont {
val language = UnCivGame.Current.settings.language
val fontForLanguage = getFontForLanguage(language)
val keyForFont = "$fontForLanguage $size"
if (fontCache.containsKey(keyForFont)) return fontCache[keyForFont]!!
val generator: FreeTypeFontGenerator
if (Gdx.files.internal("skin/$fontForLanguage.ttf").exists())
generator = FreeTypeFontGenerator(Gdx.files.internal("skin/$fontForLanguage.ttf"))
else {
val localPath = "fonts/$fontForLanguage.ttf"
if(!containsFont(fontForLanguage)) downloadFontForLanguage(language)
generator = FreeTypeFontGenerator(Gdx.files.internal(localPath))
}
val parameter = FreeTypeFontGenerator.FreeTypeFontParameter()
parameter.size = size
parameter.minFilter = Texture.TextureFilter.Linear
parameter.magFilter = Texture.TextureFilter.Linear
parameter.characters = getCharsForFont(fontForLanguage)
val font = generator.generateFont(parameter)
generator.dispose() // don't forget to dispose to avoid memory leaks!
fontCache[keyForFont] = font
return font
}
}

View file

@ -11,7 +11,7 @@ import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.center import com.unciv.ui.utils.center
import com.unciv.ui.utils.onClick import com.unciv.ui.utils.onClick
open class PopupTable: Table(){ open class PopupTable: Table(CameraStageBaseScreen.skin){
init { init {
val tileTableBackground = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f)) val tileTableBackground = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
background = tileTableBackground background = tileTableBackground
@ -21,7 +21,7 @@ open class PopupTable: Table(){
} }
fun addButton(text:String, action:()->Unit){ fun addButton(text:String, action:()->Unit){
val button = TextButton(text.tr(), CameraStageBaseScreen.skin).apply { color= ImageGetter.getBlue() } val button = TextButton(text.tr(), skin).apply { color= ImageGetter.getBlue() }
button.onClick(action) button.onClick(action)
add(button).row() add(button).row()
} }
@ -32,7 +32,6 @@ class YesNoPopupTable(question:String, action:()->Unit,
init{ init{
if(!isOpen) { if(!isOpen) {
isOpen=true isOpen=true
val skin = CameraStageBaseScreen.skin
add(Label(question, skin)).colspan(2).row() add(Label(question, skin)).colspan(2).row()
add(TextButton("No".tr(), skin).apply { onClick { close() } }) add(TextButton("No".tr(), skin).apply { onClick { close() } })

View file

@ -1,5 +1,7 @@
package com.unciv.ui.worldscreen.optionstable package com.unciv.ui.worldscreen.optionstable
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
@ -7,14 +9,31 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
import com.unciv.UnCivGame import com.unciv.UnCivGame
import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.GameBasics
import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.Fonts
import com.unciv.ui.utils.center import com.unciv.ui.utils.center
import com.unciv.ui.worldscreen.WorldScreen import com.unciv.ui.worldscreen.WorldScreen
class Language(val language:String){
val percentComplete:Int
init{
val availableTranslations = GameBasics.Translations.filter { it.value.containsKey(language) }
if(language=="English") percentComplete = 100
else percentComplete = (availableTranslations.size*100 / GameBasics.Translations.size)
}
override fun toString(): String {
return "$language - $percentComplete%"
}
}
class WorldScreenDisplayOptionsTable : PopupTable(){ class WorldScreenDisplayOptionsTable : PopupTable(){
val languageSelectBox = SelectBox<Language>(CameraStageBaseScreen.skin)
init { init {
update() update()
} }
fun update() { fun update() {
val settings = UnCivGame.Current.settings val settings = UnCivGame.Current.settings
settings.save() settings.save()
@ -28,33 +47,39 @@ class WorldScreenDisplayOptionsTable : PopupTable(){
else addButton("{Show} {resources and improvements}") { settings.showResourcesAndImprovements = true; update() } else addButton("{Show} {resources and improvements}") { settings.showResourcesAndImprovements = true; update() }
class Language(val language:String){
val percentComplete:Int
init{
val availableTranslations = GameBasics.Translations.filter { it.value.containsKey(language) }
if(language=="English") percentComplete = 100
else percentComplete = (availableTranslations.size*100 / GameBasics.Translations.size)
}
override fun toString(): String {
return "$language - $percentComplete%"
}
}
val languageSelectBox = SelectBox<Language>(CameraStageBaseScreen.skin)
val languageArray = com.badlogic.gdx.utils.Array<Language>() val languageArray = com.badlogic.gdx.utils.Array<Language>()
GameBasics.Translations.getLanguages().map { Language(it) }.sortedByDescending { it.percentComplete } GameBasics.Translations.getLanguages().map { Language(it) }.sortedByDescending { it.percentComplete }
.forEach { languageArray.add(it) } .forEach { languageArray.add(it) }
languageSelectBox.items = languageArray languageSelectBox.items = languageArray
languageSelectBox.selected = languageArray.first { it.language== UnCivGame.Current.settings.language} languageSelectBox.selected = languageArray.first { it.language== UnCivGame.Current.settings.language}
add(languageSelectBox).pad(10f).row() add(languageSelectBox).pad(10f).row()
languageSelectBox.addListener(object : ChangeListener() { languageSelectBox.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) { override fun changed(event: ChangeEvent?, actor: Actor?) {
UnCivGame.Current.settings.language = languageSelectBox.selected.language val selectedLanguage = languageSelectBox.selected.language
UnCivGame.Current.settings.save() if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage)))
CameraStageBaseScreen.resetFonts() selectLanguage()
UnCivGame.Current.worldScreen = WorldScreen() else {
UnCivGame.Current.setWorldScreen() YesNoPopupTable("This language requires you to download fonts.\n" +
UnCivGame.Current.worldScreen.stage.addActor(WorldScreenDisplayOptionsTable()) "Do you want to download fonts for $selectedLanguage?",
{
val downloading = PopupTable()
downloading.add(Label("Downloading...", CameraStageBaseScreen.skin))
downloading.pack()
downloading.center(stage)
stage.addActor(downloading)
Gdx.input.inputProcessor = null // no interaction until download is over
kotlin.concurrent.thread {
Fonts().downloadFontForLanguage(selectedLanguage)
// The language selection must be done on the render thread, because it requires a GL context.
// This means that we have to tell the table to create it on render.
shouldSelectLanguage=true
}
})
}
} }
}) })
@ -92,4 +117,25 @@ class WorldScreenDisplayOptionsTable : PopupTable(){
center(UnCivGame.Current.worldScreen.stage) center(UnCivGame.Current.worldScreen.stage)
UnCivGame.Current.worldScreen.shouldUpdate=true UnCivGame.Current.worldScreen.shouldUpdate=true
} }
fun selectLanguage(){
UnCivGame.Current.settings.language = languageSelectBox.selected.language
UnCivGame.Current.settings.save()
CameraStageBaseScreen.resetFonts()
UnCivGame.Current.worldScreen = WorldScreen()
UnCivGame.Current.setWorldScreen()
UnCivGame.Current.worldScreen.stage.addActor(WorldScreenDisplayOptionsTable())
}
var shouldSelectLanguage = false
override fun draw(batch: Batch?, parentAlpha: Float) {
if(shouldSelectLanguage){
shouldSelectLanguage=false
selectLanguage()
}
super.draw(batch, parentAlpha)
}
} }