diff --git a/android/assets/jsons/Translations.json b/android/assets/jsons/Translations.json index 67617833..061b917f 100644 --- a/android/assets/jsons/Translations.json +++ b/android/assets/jsons/Translations.json @@ -244,6 +244,8 @@ Portuguese:"Desfazer unidade" } + "Explore":{} + "Do you really want to disband this unit?":{ Italian:"Vuoi davvero sciogliere questa unità?" Russian:"Вы действительно хотите распустить этот юнит?" @@ -1894,7 +1896,7 @@ Portuguese:"Drenar pântano" } - "Ancient Ruins":{ + "Ancient ruins":{ Simplified_Chinese:"远古遗址" } "City Ruins":{ diff --git a/core/src/com/unciv/ui/LanguagePickerScreen.kt b/core/src/com/unciv/ui/LanguagePickerScreen.kt index 39c35e55..fdb88cf5 100644 --- a/core/src/com/unciv/ui/LanguagePickerScreen.kt +++ b/core/src/com/unciv/ui/LanguagePickerScreen.kt @@ -1,5 +1,6 @@ package com.unciv.ui +import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Touchable 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.tr import com.unciv.ui.pickerscreens.PickerScreen -import com.unciv.ui.utils.ImageGetter -import com.unciv.ui.utils.enable -import com.unciv.ui.utils.onClick +import com.unciv.ui.utils.* +import com.unciv.ui.worldscreen.optionstable.PopupTable +import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable class LanguageTable(val language:String,skin: Skin):Table(skin){ @@ -71,12 +72,44 @@ class LanguagePickerScreen: PickerScreen(){ } rightSideButton.setText("Pick language".tr()) + + rightSideButton.onClick { - UnCivGame.Current.settings.language = chosenLanguage - UnCivGame.Current.settings.save() - UnCivGame.Current.startNewGame() - dispose() + if (Fonts().containsFont(Fonts().getFontForLanguage(chosenLanguage))) + pickLanguage() + else { + 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) + } + } \ No newline at end of file diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index e6b35121..00c43dc9 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -5,19 +5,13 @@ import com.badlogic.gdx.Input import com.badlogic.gdx.Screen import com.badlogic.gdx.graphics.Color 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.BitmapFont 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.ui.* import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.utils.viewport.ExtendViewport import com.unciv.UnCivGame -import com.unciv.models.gamebasics.GameBasics -import java.io.FileOutputStream -import java.net.URL open class CameraStageBaseScreen : Screen { @@ -69,14 +63,14 @@ open class CameraStageBaseScreen : Screen { } fun resetFonts(){ - skin.get(TextButton.TextButtonStyle::class.java).font = getFont(20) + skin.get(TextButton.TextButtonStyle::class.java).font = Fonts().getFont(20) skin.get(Label.LabelStyle::class.java).apply { - font = getFont(18) + font = Fonts().getFont(18) fontColor= Color.WHITE } - skin.get(TextField.TextFieldStyle::class.java).font = getFont(18) - skin.get(SelectBox.SelectBoxStyle::class.java).font = getFont(20) - skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = getFont(20) + skin.get(TextField.TextFieldStyle::class.java).font = Fonts().getFont(18) + skin.get(SelectBox.SelectBoxStyle::class.java).font = Fonts().getFont(20) + skin.get(SelectBox.SelectBoxStyle::class.java).listStyle.font = Fonts().getFont(20) } 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} - -// Contains e.g. "Arial 22", fontname and size, to BitmapFont -val fontCache = HashMap() - -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() - 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 { 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. return this // for chaining } diff --git a/core/src/com/unciv/ui/utils/Fonts.kt b/core/src/com/unciv/ui/utils/Fonts.kt new file mode 100644 index 00000000..27cd9ee1 --- /dev/null +++ b/core/src/com/unciv/ui/utils/Fonts.kt @@ -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() + } + + 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() + 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 + } +} \ No newline at end of file diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt index 2f720936..1d743ad7 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt @@ -11,7 +11,7 @@ import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.center import com.unciv.ui.utils.onClick -open class PopupTable: Table(){ +open class PopupTable: Table(CameraStageBaseScreen.skin){ init { val tileTableBackground = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f)) background = tileTableBackground @@ -21,7 +21,7 @@ open class PopupTable: Table(){ } 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) add(button).row() } @@ -32,7 +32,6 @@ class YesNoPopupTable(question:String, action:()->Unit, init{ if(!isOpen) { isOpen=true - val skin = CameraStageBaseScreen.skin add(Label(question, skin)).colspan(2).row() add(TextButton("No".tr(), skin).apply { onClick { close() } }) diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt index f22d08b3..aa8cd1b5 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenDisplayOptionsTable.kt @@ -1,5 +1,7 @@ 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.ui.Label 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.models.gamebasics.GameBasics import com.unciv.ui.utils.CameraStageBaseScreen +import com.unciv.ui.utils.Fonts import com.unciv.ui.utils.center 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(){ + val languageSelectBox = SelectBox(CameraStageBaseScreen.skin) + init { update() } + + fun update() { val settings = UnCivGame.Current.settings settings.save() @@ -28,33 +47,39 @@ class WorldScreenDisplayOptionsTable : PopupTable(){ 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(CameraStageBaseScreen.skin) val languageArray = com.badlogic.gdx.utils.Array() GameBasics.Translations.getLanguages().map { Language(it) }.sortedByDescending { it.percentComplete } .forEach { languageArray.add(it) } languageSelectBox.items = languageArray languageSelectBox.selected = languageArray.first { it.language== UnCivGame.Current.settings.language} add(languageSelectBox).pad(10f).row() + languageSelectBox.addListener(object : ChangeListener() { override fun changed(event: ChangeEvent?, actor: Actor?) { - 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()) + val selectedLanguage = languageSelectBox.selected.language + if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage))) + selectLanguage() + else { + YesNoPopupTable("This language requires you to download fonts.\n" + + "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) 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) + } } \ No newline at end of file