diff --git a/android/assets/skin/Arial.ttf b/android/assets/skin/Arial.ttf deleted file mode 100644 index ab68fb19..00000000 Binary files a/android/assets/skin/Arial.ttf and /dev/null differ diff --git a/android/assets/skin/OFL.txt b/android/assets/skin/OFL.txt deleted file mode 100644 index 17588bc2..00000000 --- a/android/assets/skin/OFL.txt +++ /dev/null @@ -1,94 +0,0 @@ -Copyright (c) 2011, Ang�lica D�iaz (http://typereview.wordpress.com|angiecina@gmail.com), -with Reserved Font Name "Esteban" - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/android/src/core/java/nativefont/NativeFontAndroid.java b/android/src/core/java/nativefont/NativeFontAndroid.java new file mode 100755 index 00000000..53d7a8f3 --- /dev/null +++ b/android/src/core/java/nativefont/NativeFontAndroid.java @@ -0,0 +1,78 @@ +package core.java.nativefont; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Typeface; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.android.AndroidApplication; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; + +import java.io.ByteArrayOutputStream; +import java.util.HashMap; + +/** + * Created by tian on 2016/10/2. + */ + +public class NativeFontAndroid implements NativeFontListener { + private HashMap fontFaces = new HashMap(); + private AndroidApplication androidApplication = (AndroidApplication) Gdx.app; + @Override + public Pixmap getFontPixmap(String txt, NativeFontPaint vpaint) { + Paint paint = new Paint(); + + if (!vpaint.getTTFName().equals("")) { + // Typeface fontFace = fontFaces.get(vpaint.getTTFName()); + Gdx.app.log("app",Gdx.files.internal(vpaint.getTTFName() + + (vpaint.getTTFName().endsWith(".ttf") ? "" + : ".ttf")).file().getPath()); + Typeface fontFace = Typeface.createFromAsset(androidApplication.getAssets(),vpaint.getTTFName() + + (vpaint.getTTFName().endsWith(".ttf") ? "" + : ".ttf")); + fontFaces.put(vpaint.getTTFName(), fontFace); + paint.setTypeface(fontFace); + } + paint.setAntiAlias(true); + paint.setTextSize(vpaint.getTextSize()); + Paint.FontMetrics fm = paint.getFontMetrics(); + int w = (int) paint.measureText(txt); + int h = (int) (fm.descent - fm.ascent); + if (w == 0) { + w = h = vpaint.getTextSize(); + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + // 如果是描边类型 + if (vpaint.getStrokeColor() != null) { + // 绘制外层 + paint.setColor(getColor(vpaint.getStrokeColor())); + paint.setStrokeWidth(vpaint.getStrokeWidth()); // 描边宽度 + paint.setStyle(Paint.Style.FILL_AND_STROKE); // 描边种类 + paint.setFakeBoldText(true); // 外层text采用粗体 + canvas.drawText(txt, 0, -fm.ascent, paint); + paint.setFakeBoldText(false); + } else { + paint.setUnderlineText(vpaint.getUnderlineText()); + paint.setStrikeThruText(vpaint.getStrikeThruText()); + paint.setFakeBoldText(vpaint.getFakeBoldText()); + } + // 绘制内层 + paint.setStrokeWidth(0); + paint.setColor(getColor(vpaint.getColor())); + canvas.drawText(txt, 0, -fm.ascent, paint); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.PNG, 100, buffer); + byte[] encodedData = buffer.toByteArray(); + Pixmap pixmap = new Pixmap(encodedData, 0, encodedData.length); + bitmap = null; + canvas = null; + return pixmap; + } + + private int getColor(Color color) { + return (((((int) (color.a * 255.0f)) << 24) | (((int) (color.r * 255.0f)) << 16)) | (((int) (color.g * 255.0f)) << 8)) | ((int) (color.b * 255.0f)); + } +} diff --git a/build.gradle b/build.gradle index bc122ac7..2285ff81 100644 --- a/build.gradle +++ b/build.gradle @@ -122,4 +122,4 @@ project(":core") { tasks.eclipse.doLast { delete ".project" -} \ No newline at end of file +} diff --git a/core/src/com/unciv/models/metadata/GameSettings.kt b/core/src/com/unciv/models/metadata/GameSettings.kt index d3778156..f85393ac 100644 --- a/core/src/com/unciv/models/metadata/GameSettings.kt +++ b/core/src/com/unciv/models/metadata/GameSettings.kt @@ -7,6 +7,7 @@ class GameSettings { var showResourcesAndImprovements: Boolean = true var checkForDueUnits: Boolean = true var singleTapMove: Boolean = false + var fontSet:String = "NativeFont(Recommended)" var language: String = "English" var resolution: String = "1050x700" var tutorialsShown = ArrayList() diff --git a/core/src/com/unciv/ui/LanguagePickerScreen.kt b/core/src/com/unciv/ui/LanguagePickerScreen.kt index f7f4df86..c33cfaa7 100644 --- a/core/src/com/unciv/ui/LanguagePickerScreen.kt +++ b/core/src/com/unciv/ui/LanguagePickerScreen.kt @@ -1,6 +1,5 @@ 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 @@ -11,8 +10,6 @@ import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.tr import com.unciv.ui.pickerscreens.PickerScreen 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){ @@ -77,24 +74,7 @@ class LanguagePickerScreen: PickerScreen(){ rightSideButton.onClick { - if (Fonts().containsFont(Fonts().getFontForLanguage(chosenLanguage))) - pickLanguage() - else { - val spaceSplitLang = chosenLanguage.replace("_"," ") - YesNoPopupTable("This language requires you to download fonts.\n" + - "Do you want to download fonts for $spaceSplitLang?", - { - val downloading = PopupTable(this) - downloading.add("Downloading...".toLabel()) - downloading.open() - Gdx.input.inputProcessor = null // no interaction until download is over - - kotlin.concurrent.thread { - Fonts().downloadFontForLanguage(chosenLanguage) - shouldPickLanguage = true - } - },this) - } + pickLanguage() } } @@ -105,12 +85,4 @@ class LanguagePickerScreen: PickerScreen(){ 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/Fonts.kt b/core/src/com/unciv/ui/utils/Fonts.kt index 5ec00b14..2eafa2b5 100644 --- a/core/src/com/unciv/ui/utils/Fonts.kt +++ b/core/src/com/unciv/ui/utils/Fonts.kt @@ -1,40 +1,68 @@ package com.unciv.ui.utils import com.badlogic.gdx.Gdx +import com.badlogic.gdx.graphics.Color 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 com.unciv.models.gamebasics.tr +import com.unciv.ui.worldscreen.optionstable.PopupTable +import core.java.nativefont.NativeFont +import core.java.nativefont.NativeFontPaint import java.io.FileOutputStream +import java.io.FileInputStream import java.net.URL +import java.security.* 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" + fun download(link: String,fontForLanguage: String) { + if (!Gdx.files.local("fonts").exists()) + Gdx.files.local("fonts").mkdirs() + val input = URL(link).openStream() + val output = FileOutputStream(Gdx.files.local("fonts/$fontForLanguage.ttf").file()) + input.use { + output.use { + input.copyTo(output) + } + } } - - val chineseFont = "WenQuanYiMicroHei" - - fun getCharsForFont(font: String): String { + fun getMD5(fontForLanguage: String):String { + val sb = StringBuffer("") + val md = MessageDigest.getInstance("MD5") + if (Gdx.files.local("fonts/$fontForLanguage.ttf").exists()) { + md.update(FileInputStream(Gdx.files.local("fonts/$fontForLanguage.ttf").file()).readBytes()) + val b = md.digest() + for (i in b) { + var d = i.toInt() + if (d < 0) d = i + 256 + if (d < 16) sb.append("0") + sb.append(Integer.toHexString(d)) + } + return sb.toString() + } + return "" + } + fun containsFont(): Boolean { + if (Gdx.files.local("fonts/WenQuanYiMicroHei.ttf").exists()) + return true + return false + } + fun getCharsForFont(): 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 charSet = HashSet() charSet.addAll(defaultText.asIterable()) - if(Gdx.files.internal("BasicHelp/BasicHelp_Simplified_Chinese.json").exists()) - charSet.addAll(Gdx.files.internal("BasicHelp/BasicHelp_Simplified_Chinese.json").readString().asIterable()) + if(Gdx.files.internal("jsons/BasicHelp/BasicHelp_Simplified_Chinese.json").exists()) + charSet.addAll(Gdx.files.internal("jsons/BasicHelp/BasicHelp_Simplified_Chinese.json").readString().asIterable()) if (Gdx.files.internal("jsons/Nations_Simplified_Chinese.json").exists()) charSet.addAll(Gdx.files.internal("jsons/Nations_Simplified_Chinese.json").readString().asIterable()) if (Gdx.files.internal("jsons/Tutorials/Tutorials_Simplified_Chinese.json").exists()) @@ -46,66 +74,41 @@ class Fonts { } } 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/layerssss/wqy/raw/gh-pages/fonts/WenQuanYiMicroHei.ttf", localPath)//This font is licensed under Apache2.0 or GPLv3 - } - - 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.local(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 getFont(size: Int): BitmapFont { + if(UnCivGame.Current.settings.fontSet=="WenQuanYiMicroHei"){ + val fontForLanguage="WenQuanYiMicroHei" + val keyForFont = "$fontForLanguage $size" + if (fontCache.containsKey(keyForFont)) + return fontCache[keyForFont]!! + if (getMD5(fontForLanguage)!="96574d6f2f2bbd4a3ce56979623b1952"){ + Gdx.files.local("fonts/$fontForLanguage.ttf").delete() + UnCivGame.Current.settings.fontSet="NativeFont(Recommended)" + Gdx.app.postRunnable { + val downloading = PopupTable(UnCivGame.Current.worldScreen) + downloading.add("Checksum error!\nIf you want to use the font \"WenQuanYiMicroHei\", please download again.".toLabel().setFontColor(Color.RED)).row() + downloading.addButton("Close".tr()) { downloading.remove() }.row() + downloading.open() + } + } + else { + val generator = FreeTypeFontGenerator(Gdx.files.local("fonts/WenQuanYiMicroHei.ttf")) + val parameter = FreeTypeFontGenerator.FreeTypeFontParameter() + parameter.size = size + parameter.minFilter = Texture.TextureFilter.Linear + parameter.magFilter = Texture.TextureFilter.Linear + parameter.characters = getCharsForFont() + val font = generator.generateFont(parameter) + fontCache[keyForFont] = font + return font + } + } + val fontForLanguage ="Nativefont" + val keyForFont = "$fontForLanguage $size" + if (fontCache.containsKey(keyForFont))return fontCache[keyForFont]!! + val font=NativeFont(NativeFontPaint(size)) + font.appendText(getCharsForFont()) + fontCache[keyForFont] = font + return font + } } diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt index 39e05bf5..0617f08c 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt @@ -1,7 +1,7 @@ package com.unciv.ui.worldscreen.optionstable import com.badlogic.gdx.Gdx -import com.badlogic.gdx.graphics.g2d.Batch +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.ui.* import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener @@ -11,6 +11,7 @@ import com.unciv.models.gamebasics.GameBasics import com.unciv.models.gamebasics.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen +import java.io.IOException import kotlin.concurrent.thread class Language(val language:String){ @@ -75,6 +76,8 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr settings.autoAssignCityProduction= !settings.autoAssignCityProduction update() } + + addFontSelectBox(innerTable) addLanguageSelectBox(innerTable) @@ -196,6 +199,62 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr }) } + private fun addFontSelectBox(innerTable: PopupTable) { + innerTable.add("Fontset".toLabel()) + val FontSetSelectBox = SelectBox(skin) + val FontSetArray = Array() + FontSetArray.add("NativeFont(Recommended)") + FontSetArray.add("WenQuanYiMicroHei") + FontSetSelectBox.items = FontSetArray + FontSetSelectBox.selected = UnCivGame.Current.settings.fontSet + innerTable.add(FontSetSelectBox).pad(10f).row() + + FontSetSelectBox.addListener(object : ChangeListener() { + override fun changed(event: ChangeEvent?, actor: Actor?) { + UnCivGame.Current.settings.fontSet = FontSetSelectBox.selected + if (FontSetSelectBox.selected == "NativeFont(Recommended)"||Fonts().containsFont()) { + selectFont() + } + else { + YesNoPopupTable("This Font requires you to download fonts.\n" + + "Do you want to download fonts(about 4.2MB)?", + { + val downloading = PopupTable(screen) + downloading.add("Downloading...\n".toLabel()).row() + downloading.add("Warning:Don't switch this game to background until download finished.".toLabel().setFontColor(Color.RED)).row() + downloading.open() + Gdx.input.inputProcessor = null + thread { + try { + Fonts().download("https://github.com/layerssss/wqy/raw/gh-pages/fonts/WenQuanYiMicroHei.ttf", "WenQuanYiMicroHei")//This font is licensed under Apache2.0 or GPLv3 + Gdx.app.postRunnable { + selectFont() + } + } + catch (e: IOException) { + Gdx.app.postRunnable { + FontSetSelectBox.selected = "NativeFont(Recommended)" + val downloading = PopupTable(UnCivGame.Current.worldScreen) + downloading.add("Download failed!\nPlease check your internet connection.".toLabel().setFontColor(Color.RED)).row() + downloading.addButton("Close".tr()) { downloading.remove() }.row() + downloading.open() + } + } + } + }, UnCivGame.Current.worldScreen, {FontSetSelectBox.selected = "NativeFont(Recommended)"}) + } + } + }) + } + + fun selectFont(){ + UnCivGame.Current.settings.save() + CameraStageBaseScreen.resetFonts() + UnCivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) + UnCivGame.Current.setWorldScreen() + WorldScreenOptionsTable(UnCivGame.Current.worldScreen) + } + private fun addLanguageSelectBox(innerTable: PopupTable) { innerTable.add("Language".toLabel()) val languageSelectBox = SelectBox(skin) @@ -209,27 +268,7 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr languageSelectBox.addListener(object : ChangeListener() { override fun changed(event: ChangeEvent?, actor: Actor?) { selectedLanguage = languageSelectBox.selected.language - if (Fonts().containsFont(Fonts().getFontForLanguage(selectedLanguage))) - selectLanguage() - else { - val spaceSplitLang = selectedLanguage.replace("_", " ") - YesNoPopupTable("This language requires you to download fonts.\n" + - "Do you want to download fonts for $spaceSplitLang?", - { - - val downloading = PopupTable(screen) - downloading.add("Downloading...".toLabel()) - downloading.open() - Gdx.input.inputProcessor = null // no interaction until download is over - - 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 - } - }) - } + selectLanguage() } }) @@ -245,25 +284,11 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr } } - fun selectLanguage(){ UnCivGame.Current.settings.language = selectedLanguage UnCivGame.Current.settings.save() - - CameraStageBaseScreen.resetFonts() - UnCivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) UnCivGame.Current.setWorldScreen() WorldScreenOptionsTable(UnCivGame.Current.worldScreen) } - - var shouldSelectLanguage = false - override fun draw(batch: Batch?, parentAlpha: Float) { - if(shouldSelectLanguage){ - shouldSelectLanguage=false - selectLanguage() - } - super.draw(batch, parentAlpha) - } } - diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt index 663aeac7..5ac9c103 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt @@ -8,12 +8,12 @@ import com.unciv.ui.utils.onClick import com.unciv.ui.utils.toLabel class YesNoPopupTable(question:String, action:()->Unit, - screen: CameraStageBaseScreen = UnCivGame.Current.worldScreen) : PopupTable(screen){ + screen: CameraStageBaseScreen = UnCivGame.Current.worldScreen, restoredefault:()->Unit = {}) : PopupTable(screen){ init{ if(!screen.hasPopupOpen) { screen.hasPopupOpen=true add(question.toLabel()).colspan(2).row() - add(TextButton("No".tr(), skin).onClick { close() }) + add(TextButton("No".tr(), skin).onClick { close(); restoredefault() }) add(TextButton("Yes".tr(), skin).onClick { close(); action() }) open() } diff --git a/core/src/core/java/nativefont/NativeFont.java b/core/src/core/java/nativefont/NativeFont.java new file mode 100755 index 00000000..ef96af43 --- /dev/null +++ b/core/src/core/java/nativefont/NativeFont.java @@ -0,0 +1,299 @@ +package core.java.nativefont; + +import com.badlogic.gdx.Application; +import com.badlogic.gdx.Gdx; +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.PixmapPacker; +import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.GdxRuntimeException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +/** + * Created by tian on 2016/10/2. + */ + +public class NativeFont extends BitmapFont { + private static NativeFontListener listener; + private static boolean robovm; + + private Set charSet; + private BitmapFontData data; + private HashMap emojiSet; + private Texture.TextureFilter magFilter; + private Texture.TextureFilter minFilter; + private PixmapPacker packer; + private int pageWidth; + private NativeFontPaint paint; + private int size; + + public class EmojiDate { + public String path; + public int size; + + public EmojiDate(String path, int size) { + this.path = path; + this.size = size; + } + } + + + public NativeFont() { + this(new NativeFontPaint()); + } + + public NativeFont(NativeFontPaint paint) { + super(new BitmapFontData(), new TextureRegion(), false); + this.pageWidth = 512; + this.paint = new NativeFontPaint(); + this.charSet = new HashSet(); + this.packer = null; + this.minFilter = Texture.TextureFilter.Linear; + this.magFilter = Texture.TextureFilter.Linear; + this.emojiSet = new HashMap(); + updataSize(paint.getTextSize()); + if (listener == null) createListener(); + this.paint = paint; + } + + private void createListener() { + String className = "core.java.nativefont.NativeFont"; + if (Gdx.app.getType() == Application.ApplicationType.Desktop) { + className += "Desktop"; + } else if (Gdx.app.getType() == Application.ApplicationType.Android) { + className += "Android"; + } else if (Gdx.app.getType() == Application.ApplicationType.iOS) { + if (robovm) + className += "IOS"; + else + className += "IOSMoe"; + }else if (Gdx.app.getType() == Application.ApplicationType.WebGL){ + className += "Html"; + } + try { + Class claz = (Class) Gdx.app.getClass().getClassLoader().loadClass(className); + listener = claz.newInstance(); + } catch (Exception e) { + throw new GdxRuntimeException("Class Not Found:" + e.getMessage()); + } + } + + public void updataSize(int newSize) { + this.data = getData(); + this.size = Math.max(newSize, this.size); + this.data.down = (float) (-this.size); + this.data.ascent = (float) (-this.size); + this.data.capHeight = (float) this.size; + this.data.lineHeight = (float) this.size; + } + + public NativeFont setTextColor(Color color) { + this.paint.setColor(color); + return this; + } + + public NativeFont setStrokeColor(Color color) { + this.paint.setStrokeColor(color); + return this; + } + + public NativeFont setStrokeWidth(int width) { + this.paint.setStrokeWidth(width); + return this; + } + + public NativeFont setSize(int size) { + this.paint.setTextSize(size); + return this; + } + + public NativeFont setBold(boolean istrue) { + this.paint.setFakeBoldText(istrue); + return this; + } + + public NativeFont setUnderline(boolean istrue) { + this.paint.setUnderlineText(istrue); + return this; + } + + public NativeFont setStrikeThru(boolean istrue) { + this.paint.setStrikeThruText(istrue); + return this; + } + + public NativeFont setPaint(NativeFontPaint paint) { + this.paint = paint; + return this; + } + + public NativeFont addEmojiPath(String emojiKey, String imgPath, int size) { + this.emojiSet.put(emojiKey, new EmojiDate(imgPath, size)); + return this; + } + + public NativeFont appendEmoji(String txt, String imgname, int size) { + Pixmap pixmap = new Pixmap(Gdx.files.internal(imgname)); + // Pixmap.setFilter(Pixmap.Filter.BiLinear); + Pixmap pixmap2 = new Pixmap(size, size, Pixmap.Format.RGBA8888); + pixmap2.setFilter(Pixmap.Filter.BiLinear); + pixmap2.drawPixmap(pixmap, 0, 0, pixmap.getWidth(), pixmap.getHeight(), 0, 0, size, size); + pixmap.dispose(); + appendEmoji(txt, pixmap2); + return this; + } + + public NativeFont appendEmoji(String txt, Pixmap pixmap) { + if (this.charSet.add(txt)) { + if (this.packer == null) { + this.packer = new PixmapPacker(this.pageWidth, this.pageWidth, Pixmap.Format.RGBA8888, 2, false); + } + putGlyph(txt.charAt(0), pixmap); + updataSize(pixmap.getHeight()); + upData(); + } + return this; + } + + public NativeFont createText(String characters) { + if (!(characters == null || characters.length() == 0)) { + create(characters, true); + end(); + } + return this; + } + + public NativeFont appendText(String characters) { + if (!(characters == null || characters.length() == 0)) { + create(characters, false); + } + return this; + } + + private void create(String characters, boolean haveMinPageSize) { + char c; + characters = characters.replaceAll("[\\t\\n\\x0B\\f\\r]", ""); + Array cs = new Array(); + for (char c2 : characters.toCharArray()) { + if (this.charSet.add((String.valueOf(c2)))) { + cs.add((String.valueOf(c2))); + } + } + if (haveMinPageSize) { + this.pageWidth = (this.paint.getTextSize() + 2) * ((int) (Math.sqrt((double) cs.size) + 1.0d)); + } + if (this.packer == null) { + this.packer = new PixmapPacker(this.pageWidth, this.pageWidth, Pixmap.Format.RGBA8888, 2, false); + } + + char c2; + for (int i = 0; i < cs.size; i++) { + String txt = cs.get(i); + c2 = txt.charAt(0); + String css = String.valueOf(c2); + if (this.emojiSet.get(css) != null) { + this.charSet.remove(css); + EmojiDate date = this.emojiSet.get(css); + appendEmoji(c2 + "", date.path, date.size); + } else { + putGlyph(c2, this.listener.getFontPixmap(txt, this.paint)); + } + } + + updataSize(this.size); + upData(); + if (getRegions().size == 1) { + setOwnsTexture(true); + } else { + setOwnsTexture(false); + } + } + + private void putGlyph(char c, Pixmap pixmap) { + Rectangle rect = this.packer.pack(String.valueOf(c), pixmap); + pixmap.dispose(); + int pIndex = this.packer.getPageIndex((String.valueOf(c))); + Glyph glyph = new Glyph(); + glyph.id = c; + glyph.page = pIndex; + glyph.srcX = (int) rect.x; + glyph.srcY = (int) rect.y; + glyph.width = (int) rect.width; + glyph.height = (int) rect.height; + glyph.xadvance = glyph.width; + this.data.setGlyph(c, glyph); + } + + private void upData() { + Glyph spaceGlyph = this.data.getGlyph(' '); + if (spaceGlyph == null) { + spaceGlyph = new Glyph(); + Glyph xadvanceGlyph = this.data.getGlyph('l'); + if (xadvanceGlyph == null) { + xadvanceGlyph = this.data.getFirstGlyph(); + } + spaceGlyph.xadvance = xadvanceGlyph.xadvance; + spaceGlyph.id = 32; + this.data.setGlyph(32, spaceGlyph); + } + this.data.spaceXadvance = (float) (spaceGlyph.xadvance + spaceGlyph.width); + + Array pages = this.packer.getPages(); + Array regions = getRegions(); + int regSize = regions.size - 1; + for (int i = 0; i < pages.size; i++) { + Page p = pages.get(i); + if (i > regSize) { + p.updateTexture(this.minFilter, this.magFilter, false); + regions.add(new TextureRegion(p.getTexture())); + } else { + if (p.updateTexture(this.minFilter, this.magFilter, false)) { + regions.set(i, new TextureRegion(p.getTexture())); + } + } + } + + for (Glyph[] page : this.data.glyphs) { + if (page == null) continue; + + for (Glyph glyph : page) { + if (glyph != null) { + TextureRegion region = (TextureRegion) getRegions().get(glyph.page); + if (region == null) { + throw new IllegalArgumentException("BitmapFont texture region array cannot contain null elements."); + } + this.data.setGlyphRegion(glyph, region); + } + } + } + } + + public NativeFont end() { + this.paint = null; + this.charSet.clear(); + this.charSet = null; + this.packer.dispose(); + this.packer = null; + return this; + } + + public void dispose() { + end(); + super.dispose(); + } + + public static void setRobovm() { + robovm = true; + } + + public static NativeFontListener getListener() { + return listener; + } +} diff --git a/core/src/core/java/nativefont/NativeFontListener.java b/core/src/core/java/nativefont/NativeFontListener.java new file mode 100755 index 00000000..a8de2ba2 --- /dev/null +++ b/core/src/core/java/nativefont/NativeFontListener.java @@ -0,0 +1,11 @@ +package core.java.nativefont; + +import com.badlogic.gdx.graphics.Pixmap; + +/** + * Created by tian on 2016/10/2. + */ + +public interface NativeFontListener { + Pixmap getFontPixmap(String str, NativeFontPaint freePaint); +} diff --git a/core/src/core/java/nativefont/NativeFontPaint.java b/core/src/core/java/nativefont/NativeFontPaint.java new file mode 100755 index 00000000..a832a201 --- /dev/null +++ b/core/src/core/java/nativefont/NativeFontPaint.java @@ -0,0 +1,146 @@ +package core.java.nativefont; + +import com.badlogic.gdx.graphics.Color; + +/** + * Created by tian on 2016/10/2. + */ + +public class NativeFontPaint { + private int textSize = 30;// 字号 + private Color color = Color.WHITE;// 颜色 + private boolean isFakeBoldText = false;// 是否粗体 + private boolean isUnderlineText = false;// 是否下划线 + private boolean isStrikeThruText = false;// 是否删除线 + private Color strokeColor = null;// 描边颜色 + private int strokeWidth = 3;// 描边宽度 + private String ttfName = ""; + + public String getName() { + StringBuffer name = new StringBuffer(); + name.append(ttfName).append("_").append(textSize).append("_").append(color.toIntBits()) + .append("_").append(booleanToInt(isFakeBoldText)).append("_") + .append(booleanToInt(isUnderlineText)); + if (strokeColor != null) { + name.append("_").append(strokeColor.toIntBits()).append("_").append(strokeWidth); + } + return name.toString(); + } + + private int booleanToInt(boolean b) { + return b == true ? 0 : 1; + } + + public NativeFontPaint() { + } + + public NativeFontPaint(String ttfName, int textSize, Color color, Color stroke, int strokeWidth, + boolean bold, boolean line, boolean thru) { + this.ttfName = ttfName; + this.textSize = textSize; + this.color = color; + this.strokeColor = stroke; + this.strokeWidth = strokeWidth; + this.isFakeBoldText = bold; + this.isUnderlineText = line; + this.isStrikeThruText = thru; + } + + public NativeFontPaint(String ttfName) { + this.ttfName = ttfName; + } + + public NativeFontPaint(String ttfName, int size) { + this.ttfName = ttfName; + this.textSize = size; + } + + public NativeFontPaint(String ttfName, int size, Color color) { + this.ttfName = ttfName; + this.textSize = size; + this.color = color; + } + + public NativeFontPaint(String ttfName, Color color) { + this.ttfName = ttfName; + this.color = color; + } + + public NativeFontPaint(int size) { + this.textSize = size; + } + + public NativeFontPaint(Color color) { + this.color = color; + } + + public NativeFontPaint(int size, Color color) { + this.textSize = size; + this.color = color; + } + + public int getTextSize() { + return textSize; + } + + public void setTextSize(int textSize) { + this.textSize = textSize; + } + + public Color getColor() { + return color; + } + + public void setColor(Color color) { + this.color = color; + } + + public boolean getFakeBoldText() { + return isFakeBoldText; + } + + public void setFakeBoldText(boolean isFakeBoldText) { + this.isFakeBoldText = isFakeBoldText; + } + + public boolean getUnderlineText() { + return isUnderlineText; + } + + public void setUnderlineText(boolean isUnderlineText) { + this.isUnderlineText = isUnderlineText; + } + + public boolean getStrikeThruText() { + return isStrikeThruText; + } + + public void setStrikeThruText(boolean isStrikeThruText) { + this.isStrikeThruText = isStrikeThruText; + } + + public Color getStrokeColor() { + return strokeColor; + } + + public void setStrokeColor(Color strokeColor) { + this.strokeColor = strokeColor; + } + + public int getStrokeWidth() { + return strokeWidth; + } + + public void setStrokeWidth(int strokeWidth) { + this.strokeWidth = strokeWidth; + } + + public void setTTFName(String ttfName) { + this.ttfName = ttfName; + } + + public String getTTFName() { + return ttfName; + } + +} diff --git a/desktop/src/core/java/nativefont/NativeFontDesktop.java b/desktop/src/core/java/nativefont/NativeFontDesktop.java new file mode 100755 index 00000000..66734044 --- /dev/null +++ b/desktop/src/core/java/nativefont/NativeFontDesktop.java @@ -0,0 +1,128 @@ +package core.java.nativefont; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Pixmap; + + +import java.awt.BasicStroke; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.font.TextAttribute; +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.AttributedString; +import java.util.HashMap; + +import javax.imageio.ImageIO; + +import static javax.swing.UIManager.getColor; + +/** + * Created by tian on 2016/10/2. + */ + +public class NativeFontDesktop implements NativeFontListener { + private HashMap fonts = new HashMap(); + private HashMap metrics = new HashMap(); + private AttributedString as; + + public Pixmap getFontPixmap(String txt, NativeFontPaint vpaint) { + Font font = getFont(vpaint); + FontMetrics fm = metrics.get(vpaint.getName()); + int strWidth = fm.stringWidth(txt); + int strHeight = fm.getAscent() + fm.getDescent(); + if (strWidth == 0) { + strWidth = strHeight = vpaint.getTextSize(); + } + BufferedImage bi = new BufferedImage(strWidth, strHeight, + BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D g = bi.createGraphics(); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g.setFont(font); + if (vpaint.getStrokeColor() != null) { + // 描边 + GlyphVector v = font.createGlyphVector(fm.getFontRenderContext(), + txt); + Shape shape = v.getOutline(); + g.setColor(getColor(vpaint.getColor())); + g.translate(0, fm.getAscent()); + g.fill(shape); + g.setStroke(new BasicStroke(vpaint.getStrokeWidth())); + g.setColor(getColor(vpaint.getStrokeColor())); + g.draw(shape); + } else if (vpaint.getUnderlineText() == true) { + // 下划线 + AttributedString as = new AttributedString(txt); + as.addAttribute(TextAttribute.FONT, font); + as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + g.setColor(getColor(vpaint.getColor())); + g.drawString(as.getIterator(), 0, fm.getAscent()); + } else if (vpaint.getStrikeThruText() == true) { + // 删除线 + AttributedString as = new AttributedString(txt); + as.addAttribute(TextAttribute.FONT, font); + as.addAttribute(TextAttribute.STRIKETHROUGH, + TextAttribute.STRIKETHROUGH_ON); + g.setColor(getColor(vpaint.getColor())); + g.drawString(as.getIterator(), 0, fm.getAscent()); + } else { + // 普通 + g.setColor(getColor(vpaint.getColor())); + g.drawString(txt, 0, fm.getAscent()); + } + + Pixmap pixmap = null; + + try { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + ImageIO.write(bi, "png", buffer); + + pixmap = new Pixmap(buffer.toByteArray(), 0, buffer.toByteArray().length); + buffer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return pixmap; + } + + private Font getFont(NativeFontPaint vpaint) { + boolean isBolo = vpaint.getFakeBoldText() || vpaint.getStrokeColor() != null; + Font font = fonts.get(vpaint.getName()); + if (font == null) { + if (vpaint.getTTFName().equals("")) { + font = new Font("", isBolo ? Font.BOLD : Font.PLAIN, vpaint.getTextSize()); + } else { + try { + ByteArrayInputStream in = new ByteArrayInputStream(Gdx.files.internal(vpaint.getTTFName() + (vpaint.getTTFName() + .endsWith(".ttf") ? "" : ".ttf")).readBytes()); + BufferedInputStream fb = new BufferedInputStream(in); + font = Font.createFont(Font.TRUETYPE_FONT, fb).deriveFont(Font.BOLD, vpaint.getTextSize()); + fb.close(); + in.close(); + } catch (FontFormatException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + fonts.put(vpaint.getName(), font); + BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR); + Graphics2D g = bi.createGraphics(); + g.setFont(font); + FontMetrics fm = g.getFontMetrics(); + metrics.put(vpaint.getName(), fm); + } + return font; + } + +} diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3d74a158..56e0614b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ -#Wed Apr 24 09:17:57 IDT 2019 +#Sat Aug 24 11:02:13 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip -distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc64d8b400e1fb2c3b +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip