diff --git a/core/src/com/unciv/MainMenuScreen.kt b/core/src/com/unciv/MainMenuScreen.kt index bcfe7e0d32..b26a943080 100644 --- a/core/src/com/unciv/MainMenuScreen.kt +++ b/core/src/com/unciv/MainMenuScreen.kt @@ -75,7 +75,7 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize { val table = Table().pad(15f, 30f, 15f, 30f) table.background = skinStrings.getUiBackground( "MainMenuScreen/MenuButton", - skinStrings.roundedEdgeRectangle, + skinStrings.roundedEdgeRectangleShape, skinStrings.skinConfig.baseColor ) table.add(ImageGetter.getImage(icon)).size(50f).padRight(30f) diff --git a/core/src/com/unciv/models/skins/SkinConfig.kt b/core/src/com/unciv/models/skins/SkinConfig.kt index 0db75dcc4f..aec7881dc3 100644 --- a/core/src/com/unciv/models/skins/SkinConfig.kt +++ b/core/src/com/unciv/models/skins/SkinConfig.kt @@ -18,17 +18,20 @@ class SkinElement { class SkinConfig { var baseColor: Color = Color(0x004085bf) + var clearColor: Color = Color(0x000033ff) var skinVariants: HashMap = HashMap() fun clone(): SkinConfig { val toReturn = SkinConfig() toReturn.baseColor = baseColor.cpy() + toReturn.clearColor = clearColor.cpy() toReturn.skinVariants.putAll(skinVariants.map { Pair(it.key, it.value.clone()) }) return toReturn } fun updateConfig(other: SkinConfig) { baseColor = other.baseColor.cpy() + clearColor = other.clearColor.cpy() for ((variantName, element) in other.skinVariants){ skinVariants[variantName] = element.clone() } diff --git a/core/src/com/unciv/models/skins/SkinStrings.kt b/core/src/com/unciv/models/skins/SkinStrings.kt index 530e95043b..47696bf052 100644 --- a/core/src/com/unciv/models/skins/SkinStrings.kt +++ b/core/src/com/unciv/models/skins/SkinStrings.kt @@ -9,12 +9,13 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) { private val skinLocation = "Skins/$skin/" val skinConfig = SkinCache[skin] ?: SkinConfig() - val roundedEdgeRectangle = skinLocation + "roundedEdgeRectangle" - val rectangleWithOutline = skinLocation + "rectangleWithOutline" - val selectBox = skinLocation + "select-box" - val selectBoxPressed = skinLocation + "select-box-pressed" - val checkbox = skinLocation + "checkbox" - val checkboxPressed = skinLocation + "checkbox-pressed" + // Default shapes must always end with "Shape" so the UiElementDocsWriter can identify them + val roundedEdgeRectangleShape = skinLocation + "roundedEdgeRectangle" + val rectangleWithOutlineShape = skinLocation + "rectangleWithOutline" + val selectBoxShape = skinLocation + "select-box" + val selectBoxPressedShape = skinLocation + "select-box-pressed" + val checkboxShape = skinLocation + "checkbox" + val checkboxPressedShape = skinLocation + "checkbox-pressed" /** * Gets either a drawable which was defined inside skinConfig for the given path or the drawable @@ -26,6 +27,10 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) { * If the UI element is used in multiple Screens start the path with General * e.g. General/Tooltip * + * If the UI element has multiple states with different tints use a distinct + * name for every state e.g. + * - CityScreen/CityConstructionTable/QueueEntry + * - CityScreen/CityConstructionTable/QueueEntrySelected * * @param default The path to the background which should be used if path is not available. * Should be one of the predefined ones inside SkinStrings or null to get a diff --git a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt index 276fd92e20..7c7822c40e 100644 --- a/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityConstructionsTable.kt @@ -292,7 +292,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) { if (constructionQueueIndex == selectedQueueEntry) table.background = BaseScreen.skinStrings.getUiBackground( - "CityScreen/CityConstructionTable/QueueEntry", + "CityScreen/CityConstructionTable/QueueEntrySelected", tintColor = Color.GREEN.darken(0.5f) ) @@ -356,7 +356,7 @@ class CityConstructionsTable(private val cityScreen: CityScreen) { if (!isSelectedQueueEntry() && cityScreen.selectedConstruction == construction) { pickConstructionButton.background = BaseScreen.skinStrings.getUiBackground( - "CityScreen/CityConstructionTable/PickConstructionButton", + "CityScreen/CityConstructionTable/PickConstructionButtonSelected", tintColor = Color.GREEN.darken(0.5f) ) } diff --git a/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt b/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt index 9f8ce075e4..d3909810c2 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt @@ -17,7 +17,7 @@ class CityScreenCityPickerTable(private val cityScreen: CityScreen) : Table() { fun update() { val city = cityScreen.city val civInfo = city.civInfo - background = BaseScreen.skinStrings.getUiBackground("CityScreen/CityPickerTable", BaseScreen.skinStrings.roundedEdgeRectangle, civInfo.nation.getOuterColor()) + background = BaseScreen.skinStrings.getUiBackground("CityScreen/CityPickerTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, civInfo.nation.getOuterColor()) clear() if (civInfo.cities.size > 1) { diff --git a/core/src/com/unciv/ui/images/ImageGetter.kt b/core/src/com/unciv/ui/images/ImageGetter.kt index be1c8f7987..ca184ae4cc 100644 --- a/core/src/com/unciv/ui/images/ImageGetter.kt +++ b/core/src/com/unciv/ui/images/ImageGetter.kt @@ -191,39 +191,6 @@ object ImageGetter { return drawable.tint(tintColor) } - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.roundedEdgeRectangle, tintColor)", "com.unciv.ui.utils.BaseScreen")) - fun getRoundedEdgeRectangle(tintColor: Color? = null): NinePatchDrawable { - val drawable = getNinePatch("Skins/${UncivGame.Current.settings.skin}/roundedEdgeRectangle") - - if (tintColor == null) return drawable - return drawable.tint(tintColor) - } - - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.rectangleWithOutline)", "com.unciv.ui.utils.BaseScreen")) - fun getRectangleWithOutline(): NinePatchDrawable { - return getNinePatch("Skins/${UncivGame.Current.settings.skin}/rectangleWithOutline") - } - - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.selectBox)", "com.unciv.ui.utils.BaseScreen")) - fun getSelectBox(): NinePatchDrawable { - return getNinePatch("Skins/${UncivGame.Current.settings.skin}/select-box") - } - - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.selectBoxPressed)", "com.unciv.ui.utils.BaseScreen")) - fun getSelectBoxPressed(): NinePatchDrawable { - return getNinePatch("Skins/${UncivGame.Current.settings.skin}/select-box-pressed") - } - - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.checkbox)", "com.unciv.ui.utils.BaseScreen")) - fun getCheckBox(): NinePatchDrawable { - return getNinePatch("Skins/${UncivGame.Current.settings.skin}/checkbox") - } - - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, BaseScreen.skinStrings.checkboxPressed)", "com.unciv.ui.utils.BaseScreen")) - fun getCheckBoxPressed(): NinePatchDrawable { - return getNinePatch("Skins/${UncivGame.Current.settings.skin}/checkbox-pressed") - } - fun imageExists(fileName: String) = textureRegionDrawables.containsKey(fileName) fun techIconExists(techName: String) = imageExists("TechIcons/$techName") fun unitIconExists(unitName: String) = imageExists("UnitIcons/$unitName") @@ -342,14 +309,6 @@ object ImageGetter { fun getCircle() = getImage("OtherIcons/Circle") fun getTriangle() = getImage("OtherIcons/Triangle") - @Deprecated("Use SkinStrings.getUiBackground instead to make UI element moddable", ReplaceWith("BaseScreen.skinStrings.getUiBackground(path, tintColor=color)", "com.unciv.ui.utils.BaseScreen")) - fun getBackground(color: Color): Drawable { - val drawable = getDrawable("") - drawable.minHeight = 0f - drawable.minWidth = 0f - return drawable.tint(color) - } - fun getRedCross(size: Float, alpha: Float): Actor { val redCross = getImage("OtherIcons/Close") redCross.setSize(size, size) diff --git a/core/src/com/unciv/ui/multiplayer/MultiplayerScreen.kt b/core/src/com/unciv/ui/multiplayer/MultiplayerScreen.kt index d0bfa18e7f..0c3f4414e9 100644 --- a/core/src/com/unciv/ui/multiplayer/MultiplayerScreen.kt +++ b/core/src/com/unciv/ui/multiplayer/MultiplayerScreen.kt @@ -59,6 +59,9 @@ class MultiplayerScreen(previousScreen: BaseScreen) : PickerScreen() { } game.onlineMultiplayer.requestUpdate() + + pickerPane.bottomTable.background = skinStrings.getUiBackground("MultiplayerScreen/BottomTable", tintColor = skinStrings.skinConfig.clearColor) + pickerPane.topTable.background = skinStrings.getUiBackground("MultiplayerScreen/TopTable", tintColor = skinStrings.skinConfig.clearColor) } private fun setupRightSideButton() { diff --git a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt index a80843640a..6dd3e7351b 100644 --- a/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/GameOptionsTable.kt @@ -29,6 +29,7 @@ class GameOptionsTable( init { getGameOptionsTable() + background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/GameOptionsTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor) } fun update() { diff --git a/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt index addcba2591..db121f00c2 100644 --- a/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/MapOptionsTable.kt @@ -36,6 +36,7 @@ class MapOptionsTable(private val newGameScreen: NewGameScreen): Table() { //defaults().pad(5f) - each nested table having the same can give 'stairs' effects, // better control directly. Besides, the first Labels/Buttons should have 10f to look nice addMapTypeSelection() + background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/MapOptionsTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor) } private fun addMapTypeSelection() { diff --git a/core/src/com/unciv/ui/newgamescreen/NationTable.kt b/core/src/com/unciv/ui/newgamescreen/NationTable.kt index 79b73544f0..a6ac8033fe 100644 --- a/core/src/com/unciv/ui/newgamescreen/NationTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/NationTable.kt @@ -53,7 +53,7 @@ class NationTable(val nation: Nation, width: Float, minHeight: Float, ruleset: R if (ruleset != null) { titleTable.padBottom(borderWidth) // visual centering including upper border innerTable.background = BaseScreen.skinStrings.getUiBackground( - "NewGameScreen/NationTable/InnerTable", + "NewGameScreen/NationTable/RightInnerTable", tintColor = textBackgroundColor ) val lines = nation.getCivilopediaTextLines(ruleset) @@ -67,10 +67,6 @@ class NationTable(val nation: Nation, width: Float, minHeight: Float, ruleset: R borderTable.add(innerTable).pad(borderWidth).grow() add(borderTable).pad(borderWidth).width(width).minHeight(minHeight - totalPadding) } else { - innerTable.background = BaseScreen.skinStrings.getUiBackground( - "NewGameScreen/NationTable/InnerTable", - tintColor = outerColor - ) add(innerTable).width(width).minHeight(minHeight - totalPadding) } diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index a1fa62c274..926f825264 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -76,6 +76,9 @@ class NewGameScreen( if (isNarrowerThan4to3()) initPortrait() else initLandscape() + pickerPane.bottomTable.background = skinStrings.getUiBackground("NewGameScreen/BottomTable", tintColor = skinStrings.skinConfig.clearColor) + pickerPane.topTable.background = skinStrings.getUiBackground("NewGameScreen/TopTable", tintColor = skinStrings.skinConfig.clearColor) + if (UncivGame.Current.settings.lastGameSetup != null) { rightSideGroup.addActorAt(0, VerticalGroup().padBottom(5f)) val resetToDefaultsButton = "Reset to defaults".toTextButton() diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index c6649f481b..ad85dbc5c6 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -61,6 +61,7 @@ class PlayerPickerTable( top() add(ScrollPane(playerListTable).apply { setOverscroll(false, false) }).width(civBlocksWidth) update() + background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/PlayerPickerTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor) } /** diff --git a/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt index 472ac30191..b47a4cd6cf 100644 --- a/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/NotificationsOverviewTable.kt @@ -79,7 +79,7 @@ class NotificationsOverviewTable( val label = WrappableLabel(notification.text, labelWidth, Color.BLACK, 20) notificationTable.add(label) - notificationTable.background = BaseScreen.skinStrings.getUiBackground("OverviewScreen/NotificationOverviewTable/Notification", BaseScreen.skinStrings.roundedEdgeRectangle) + notificationTable.background = BaseScreen.skinStrings.getUiBackground("OverviewScreen/NotificationOverviewTable/Notification", BaseScreen.skinStrings.roundedEdgeRectangleShape) notificationTable.touchable = Touchable.enabled notificationTable.onClick { UncivGame.Current.resetToWorldScreen() diff --git a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt index 2683f34e11..1c86a10f43 100644 --- a/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ModManagementScreen.kt @@ -134,6 +134,9 @@ class ModManagementScreen( reloadOnlineMods() else refreshOnlineModTable() + + pickerPane.bottomTable.background = skinStrings.getUiBackground("ModManagementScreen/BottomTable", tintColor = skinStrings.skinConfig.clearColor) + pickerPane.topTable.background = skinStrings.getUiBackground("ModManagementScreen/TopTable", tintColor = skinStrings.skinConfig.clearColor) } private fun initPortrait() { diff --git a/core/src/com/unciv/ui/pickerscreens/TechButton.kt b/core/src/com/unciv/ui/pickerscreens/TechButton.kt index c38dee0114..4e1d6cc747 100644 --- a/core/src/com/unciv/ui/pickerscreens/TechButton.kt +++ b/core/src/com/unciv/ui/pickerscreens/TechButton.kt @@ -24,7 +24,7 @@ class TechButton(techName:String, private val techManager: TechManager, isWorldS init { touchable = Touchable.enabled - background = BaseScreen.skinStrings.getUiBackground("TechPickerScreen/TechButton", BaseScreen.skinStrings.roundedEdgeRectangle) + background = BaseScreen.skinStrings.getUiBackground("TechPickerScreen/TechButton", BaseScreen.skinStrings.roundedEdgeRectangleShape) pad(10f) if (ImageGetter.techIconExists(techName)) diff --git a/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt index 017a94f63b..9551467f45 100644 --- a/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt @@ -73,6 +73,8 @@ class TechPickerScreen( createTechTable() setButtonsInfo() topTable.add(techTable) + techTable.background = skinStrings.getUiBackground("TechPickerScreen/Background", tintColor = skinStrings.skinConfig.clearColor) + pickerPane.bottomTable.background = skinStrings.getUiBackground("TechPickerScreen/BottomTable", tintColor = skinStrings.skinConfig.clearColor) rightSideButton.setText("Pick a tech".tr()) rightSideButton.onClick(UncivSound.Paper) { diff --git a/core/src/com/unciv/ui/saves/LoadGameScreen.kt b/core/src/com/unciv/ui/saves/LoadGameScreen.kt index 59bf0d2201..2159c4a56c 100644 --- a/core/src/com/unciv/ui/saves/LoadGameScreen.kt +++ b/core/src/com/unciv/ui/saves/LoadGameScreen.kt @@ -83,6 +83,8 @@ class LoadGameScreen(previousScreen:BaseScreen) : LoadOrSaveScreen() { rightSideButton.onActivation { onLoadGame() } rightSideButton.keyShortcuts.add(KeyCharAndCode.RETURN) rightSideButton.isVisible = false + pickerPane.bottomTable.background = skinStrings.getUiBackground("LoadGameScreen/BottomTable", tintColor = skinStrings.skinConfig.clearColor) + pickerPane.topTable.background = skinStrings.getUiBackground("LoadGameScreen/TopTable", tintColor = skinStrings.skinConfig.clearColor) } override fun resetWindowState() { diff --git a/core/src/com/unciv/ui/tilegroups/CityButton.kt b/core/src/com/unciv/ui/tilegroups/CityButton.kt index ab2b40d410..a06ce4de5e 100644 --- a/core/src/com/unciv/ui/tilegroups/CityButton.kt +++ b/core/src/com/unciv/ui/tilegroups/CityButton.kt @@ -140,7 +140,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab if (!showAdditionalInfoTags || tileGroup.tileInfo.airUnits.isEmpty()) return val secondaryColor = city.civInfo.nation.getInnerColor() val airUnitTable = Table() - airUnitTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/CityButton/AirUnitTable", BaseScreen.skinStrings.roundedEdgeRectangle, city.civInfo.nation.getOuterColor()).apply { setMinSize(0f,0f) } + airUnitTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/CityButton/AirUnitTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, city.civInfo.nation.getOuterColor()).apply { setMinSize(0f,0f) } val aircraftImage = ImageGetter.getImage("OtherIcons/Aircraft") aircraftImage.color = secondaryColor airUnitTable.add(aircraftImage).size(15f) @@ -194,7 +194,7 @@ class CityButton(val city: CityInfo, private val tileGroup: WorldTileGroup): Tab } val iconTable = IconTable().apply { isTransform = false } iconTable.touchable = Touchable.enabled - iconTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/CityButton/IconTable", BaseScreen.skinStrings.roundedEdgeRectangle, city.civInfo.nation.getOuterColor()) + iconTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/CityButton/IconTable", BaseScreen.skinStrings.roundedEdgeRectangleShape, city.civInfo.nation.getOuterColor()) if (city.isInResistance()) { val resistanceImage = ImageGetter.getImage("StatIcons/Resistance") diff --git a/core/src/com/unciv/ui/utils/BaseScreen.kt b/core/src/com/unciv/ui/utils/BaseScreen.kt index e7d635509f..04e5a5a932 100644 --- a/core/src/com/unciv/ui/utils/BaseScreen.kt +++ b/core/src/com/unciv/ui/utils/BaseScreen.kt @@ -110,6 +110,10 @@ abstract class BaseScreen : Screen { companion object { var enableSceneDebug = false + /** Colour to use for empty sections of the screen. + * Gets overwritten by SkinConfig.clearColor after starting Unciv */ + var clearColor = Color(0f, 0f, 0.2f, 1f) + lateinit var skin: Skin lateinit var skinStrings: SkinStrings fun setSkin() { @@ -117,15 +121,15 @@ abstract class BaseScreen : Screen { skinStrings = SkinStrings() skin = Skin().apply { add("Nativefont", Fonts.font, BitmapFont::class.java) - add("RoundedEdgeRectangle", skinStrings.getUiBackground("", skinStrings.roundedEdgeRectangle), Drawable::class.java) + add("RoundedEdgeRectangle", skinStrings.getUiBackground("", skinStrings.roundedEdgeRectangleShape), Drawable::class.java) add("Rectangle", ImageGetter.getDrawable(""), Drawable::class.java) add("Circle", ImageGetter.getDrawable("OtherIcons/Circle").apply { setMinSize(20f, 20f) }, Drawable::class.java) add("Scrollbar", ImageGetter.getDrawable("").apply { setMinSize(10f, 10f) }, Drawable::class.java) - add("RectangleWithOutline",skinStrings.getUiBackground("", skinStrings.rectangleWithOutline), Drawable::class.java) - add("Select-box", skinStrings.getUiBackground("", skinStrings.selectBox), Drawable::class.java) - add("Select-box-pressed", skinStrings.getUiBackground("", skinStrings.selectBoxPressed), Drawable::class.java) - add("Checkbox", skinStrings.getUiBackground("", skinStrings.checkbox), Drawable::class.java) - add("Checkbox-pressed", skinStrings.getUiBackground("", skinStrings.checkboxPressed), Drawable::class.java) + add("RectangleWithOutline",skinStrings.getUiBackground("", skinStrings.rectangleWithOutlineShape), Drawable::class.java) + add("Select-box", skinStrings.getUiBackground("", skinStrings.selectBoxShape), Drawable::class.java) + add("Select-box-pressed", skinStrings.getUiBackground("", skinStrings.selectBoxPressedShape), Drawable::class.java) + add("Checkbox", skinStrings.getUiBackground("", skinStrings.checkboxShape), Drawable::class.java) + add("Checkbox-pressed", skinStrings.getUiBackground("", skinStrings.checkboxPressedShape), Drawable::class.java) load(Gdx.files.internal("Skin.json")) } skin.get(TextButton.TextButtonStyle::class.java).font = Fonts.font @@ -142,9 +146,8 @@ abstract class BaseScreen : Screen { font = Fonts.font listStyle.font = Fonts.font } + clearColor = skinStrings.skinConfig.clearColor } - /** Colour to use for empty sections of the screen. */ - val clearColor = Color(0f, 0f, 0.2f, 1f) } /** @return `true` if the screen is higher than it is wide */ diff --git a/core/src/com/unciv/ui/utils/UncivTooltip.kt b/core/src/com/unciv/ui/utils/UncivTooltip.kt index 5c8d2a3062..a2ddbca80c 100644 --- a/core/src/com/unciv/ui/utils/UncivTooltip.kt +++ b/core/src/com/unciv/ui/utils/UncivTooltip.kt @@ -15,7 +15,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Tooltip import com.badlogic.gdx.utils.Align import com.unciv.models.translations.tr -import com.unciv.ui.images.ImageGetter import com.unciv.ui.utils.extensions.toLabel /** @@ -186,7 +185,7 @@ class UncivTooltip ( val label = text.toLabel(BaseScreen.skinStrings.skinConfig.baseColor, 38) label.setAlignment(Align.center) - val background = BaseScreen.skinStrings.getUiBackground("General/Tooltip", BaseScreen.skinStrings.roundedEdgeRectangle, Color.LIGHT_GRAY) + val background = BaseScreen.skinStrings.getUiBackground("General/Tooltip", BaseScreen.skinStrings.roundedEdgeRectangleShape, Color.LIGHT_GRAY) // This controls text positioning relative to the background. // The minute fiddling makes both single caps and longer text look centered. @Suppress("SpellCheckingInspection") diff --git a/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt b/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt index 80ced6a3d0..f599a52def 100644 --- a/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt +++ b/core/src/com/unciv/ui/victoryscreen/VictoryScreen.kt @@ -283,7 +283,7 @@ class VictoryScreen(val worldScreen: WorldScreen) : PickerScreen() { labelText = Constants.unknownNationName } - civGroup.background = skinStrings.getUiBackground("VictoryScreen/CivGroup", skinStrings.roundedEdgeRectangle, backgroundColor) + civGroup.background = skinStrings.getUiBackground("VictoryScreen/CivGroup", skinStrings.roundedEdgeRectangleShape, backgroundColor) val label = labelText.toLabel(labelColor) label.setAlignment(Align.center) diff --git a/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt b/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt index 5c9b737e2c..dde9a9946c 100644 --- a/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt +++ b/core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt @@ -71,7 +71,7 @@ class NotificationsScroll( for (notification in notifications.asReversed().toList()) { // toList to avoid concurrency problems val listItem = Table() - listItem.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/Notification", BaseScreen.skinStrings.roundedEdgeRectangle) + listItem.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/Notification", BaseScreen.skinStrings.roundedEdgeRectangleShape) val labelWidth = maxEntryWidth - iconSize * notification.icons.size - 10f val label = WrappableLabel(notification.text, labelWidth, Color.BLACK, 30) diff --git a/core/src/com/unciv/ui/worldscreen/PlayerReadyScreen.kt b/core/src/com/unciv/ui/worldscreen/PlayerReadyScreen.kt index 155b403189..a22eb8230b 100644 --- a/core/src/com/unciv/ui/worldscreen/PlayerReadyScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/PlayerReadyScreen.kt @@ -15,7 +15,7 @@ class PlayerReadyScreen(worldScreen: WorldScreen) : BaseScreen() { table.touchable = Touchable.enabled val curCiv = worldScreen.viewingCiv table.background = skinStrings.getUiBackground( - "PlayerReadyScreen", + "PlayerReadyScreen/Background", tintColor = curCiv.nation.getOuterColor() ) diff --git a/core/src/com/unciv/ui/worldscreen/TechPolicyDiplomacyButtons.kt b/core/src/com/unciv/ui/worldscreen/TechPolicyDiplomacyButtons.kt index 663bdb2501..663c83ee2c 100644 --- a/core/src/com/unciv/ui/worldscreen/TechPolicyDiplomacyButtons.kt +++ b/core/src/com/unciv/ui/worldscreen/TechPolicyDiplomacyButtons.kt @@ -44,7 +44,7 @@ class TechPolicyDiplomacyButtons(val worldScreen: WorldScreen) : Table(BaseScree add(espionageButtonHolder).padTop(10f) add().growX() // Allows Policy and Diplo buttons to keep to the left - pickTechButton.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/PickTechButton", BaseScreen.skinStrings.roundedEdgeRectangle, colorFromRGB(7, 46, 43)) + pickTechButton.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/PickTechButton", BaseScreen.skinStrings.roundedEdgeRectangleShape, colorFromRGB(7, 46, 43)) pickTechButton.defaults().pad(20f) pickTechButton.add(pickTechLabel) techButtonHolder.onClick(UncivSound.Paper) { diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt index 265fd74201..c4f446b4c4 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt @@ -80,10 +80,10 @@ class WorldScreenTopBar(val worldScreen: WorldScreen) : Table() { resourceTable.background = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/ResourceTable", tintColor = backColor) add(statsTable).colspan(3).growX().row() add(resourceTable).colspan(3).growX().row() - val leftFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/LeftAttachment", BaseScreen.skinStrings.roundedEdgeRectangle, backColor) + val leftFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/LeftAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor) leftFillerCell = add(BackgroundActor(leftFillerBG, Align.topLeft)) add().growX() - val rightFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/RightAttachment", BaseScreen.skinStrings.roundedEdgeRectangle, backColor) + val rightFillerBG = BaseScreen.skinStrings.getUiBackground("WorldScreen/TopBar/RightAttachment", BaseScreen.skinStrings.roundedEdgeRectangleShape, backColor) rightFillerCell = add(BackgroundActor(rightFillerBG, Align.topRight)) pack() } diff --git a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt index c285f4cf64..88e5c54403 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt @@ -65,6 +65,7 @@ internal object DesktopLauncher { if (!isRunFromJAR) { UniqueDocsWriter().write() + UiElementDocsWriter().write() } val platformSpecificHelper = PlatformSpecificHelpersDesktop(config) diff --git a/desktop/src/com/unciv/app/desktop/UiElementDocsWriter.kt b/desktop/src/com/unciv/app/desktop/UiElementDocsWriter.kt new file mode 100644 index 0000000000..9a66139353 --- /dev/null +++ b/desktop/src/com/unciv/app/desktop/UiElementDocsWriter.kt @@ -0,0 +1,40 @@ +package com.unciv.app.desktop + +import java.io.File + +class UiElementDocsWriter { + fun write() { + val lines = File("../../docs/Modders/Creating-a-UI-skin.md").readLines() + val startIndex = lines.indexOf("") + val endIndex = lines.indexOf("") + + val table = mutableListOf( + "", + "| Directory | Name | Default shape | Image |", + "|---|:---:|:---:|---|" + ) + + val elements = mutableListOf() + + File("../../core/src/com/unciv/").walk().forEach { file -> + if (file.path.endsWith(".kt")) { + val results = Regex("getUiBackground\\((\\X*?)\"(?.*)\"[ ,\n\r]*((BaseScreen\\.)?skinStrings\\.(?.*)Shape)?\\X*?\\)") + .findAll(file.readText()) + for (result in results) { + val path = result.groups["path"]?.value + val name = path?.takeLastWhile { it != '/' } ?: "" + val defaultShape = result.groups["defaultShape"]?.value + if (name.isNotBlank()) + elements.add("| ${path!!.dropLast(name.length)} | $name | $defaultShape | |") + } + } + } + + table.addAll(elements.sorted()) + table.add("") + + val newLines = lines.subList(0, startIndex) + table + lines.subList(endIndex + 1, lines.size) + + File("../../docs/Modders/Creating-a-UI-skin.md").writeText(newLines.joinToString("\n")) + } +} diff --git a/docs/Modders/Creating-a-UI-skin.md b/docs/Modders/Creating-a-UI-skin.md index cfb39db640..cdfcc65f0a 100644 --- a/docs/Modders/Creating-a-UI-skin.md +++ b/docs/Modders/Creating-a-UI-skin.md @@ -8,7 +8,7 @@ Just like [tilesets](Creating-a-custom-tileset.md), UI skins can be used to alte We use so called 9.png (or Ninepatch) files for every skin image because UI elements need a way to be resized based on game window size and resolution. Ninepatch files can be created manually by adding black pixels around your custom images in a specific manner or by using [Android Studio's Draw 9-patch tool](https://developer.android.com/studio/write/draw9patch) or [this tool by romannurik](https://romannurik.github.io/AndroidAssetStudio/nine-patches.html) for example. You may also check if your favorite image creation tool supports nine patches itself to generate them more easily. -Every skin image needs to be **gray scale** since colors are applied later in game. The color for the image can be modified using the [skinConfig](Creating-a-UI-skin.md#tint). Please note that tileable ninepatches and ninepatches with multiple stretch areas are not supported because of technical restrictions by libgdx. +A skin image can either be gray scale and later be colored in game by modifying the `tint` in the [skinConfig](Creating-a-UI-skin.md#tint) or be colored directly in the image. When coloring the image directly it is important to set the tint of the UI element to white. Please note that tileable ninepatches and ninepatches with multiple stretch areas are not supported because of technical restrictions by libgdx. There are 6 basic shapes which can be placed inside the `Images/Skins/MyCoolSkinExample` folder: - checkbox @@ -20,29 +20,39 @@ There are 6 basic shapes which can be placed inside the `Images/Skins/MyCoolSkin These shapes are used all over Unciv and can be replaced to make a lot of UI elements change appearance at once. To change just one specific element use the [table](Creating-a-UI-skin.md#Available-UI-elements) below to create an image at the specified directory using the specified name inside `Images/Skins/MyCoolSkinExample`. See the image below for an example file structure. ![skinExample](https://user-images.githubusercontent.com/24532072/198904598-0d298035-5b02-431b-bfb4-7da4b9c821c9.png) +## Limitations + +- UI elements which change color because they have multiple states can not be given multiple colors based on their state using tint + - When coloring the image directly, setting the tint of the UI element to white overwrites these states +- Tileable ninepatches and ninepatches with multiple stretch areas are not supported because of technical restrictions by libgdx + ## Available UI elements + + | Directory | Name | Default shape | Image | |---|:---:|:---:|---| -| CivilopediaScreen/ | EntryButton | null | | +| CityScreen/ | CityInfoTable | null | | +| CityScreen/ | CityPickerTable | roundedEdgeRectangle | | +| CityScreen/CitizenManagementTable/ | AvoidCell | null | | +| CityScreen/CitizenManagementTable/ | FocusCell | null | | +| CityScreen/CitizenManagementTable/ | ResetCell | null | | | CityScreen/CityConstructionTable/ | AvailableConstructionsTable | null | | | CityScreen/CityConstructionTable/ | ConstructionsQueueTable | null | | | CityScreen/CityConstructionTable/ | Header | null | | | CityScreen/CityConstructionTable/ | PickConstructionButton | null | | +| CityScreen/CityConstructionTable/ | PickConstructionButtonSelected | null | | | CityScreen/CityConstructionTable/ | QueueEntry | null | | -| CityScreen/ | CityInfoTable | null | | -| CityScreen/CitizenManagementTable/ | AvoidCell | null | | -| CityScreen/CitizenManagementTable/ | FocusCell | null | | -| CityScreen/CitizenManagementTable/ | ResetCell | null | | -| CityScreen/ | CityPickerTable | roundedEdgeRectangle | | +| CityScreen/CityConstructionTable/ | QueueEntrySelected | null | | | CityScreen/CityScreenTileTable/ | Background | null | | | CityScreen/CityScreenTileTable/ | InnerTable | null | | | CityScreen/CityStatsTable/ | Background | null | | | CityScreen/CityStatsTable/ | InnerTable | null | | | CityScreen/ConstructionInfoTable/ | Background | null | | | CityScreen/ConstructionInfoTable/ | SelectedConstructionTable | null | | +| CivilopediaScreen/ | EntryButton | null | | | General/ | Border | null | | | General/ | ExpanderTab | null | | | General/ | HealthBar | null | | @@ -51,12 +61,24 @@ These shapes are used all over Unciv and can be replaced to make a lot of UI ele | General/Popup/ | Background | null | | | General/Popup/ | InnerTable | null | | | LanguagePickerScreen/ | LanguageTable | null | | +| LoadGameScreen/ | BottomTable | null | | +| LoadGameScreen/ | TopTable | null | | +| MainMenuScreen/ | Background | null | | | MainMenuScreen/ | MenuButton | roundedEdgeRectangle | | | MapEditor/MapEditorToolsDrawer/ | Handle | null | | | ModManagementOptions/ | ExpanderTab | null | | +| ModManagementScreen/ | BottomTable | null | | +| ModManagementScreen/ | TopTable | null | | +| MultiplayerScreen/ | BottomTable | null | | +| MultiplayerScreen/ | TopTable | null | | +| NewGameScreen/ | BottomTable | null | | +| NewGameScreen/ | GameOptionsTable | null | | +| NewGameScreen/ | MapOptionsTable | null | | +| NewGameScreen/ | PlayerPickerTable | null | | +| NewGameScreen/ | TopTable | null | | | NewGameScreen/NationTable/ | Background | null | | | NewGameScreen/NationTable/ | BorderTable | null | | -| NewGameScreen/NationTable/ | InnerTable | null | | +| NewGameScreen/NationTable/ | RightInnerTable | null | | | NewGameScreen/NationTable/ | Title | null | | | NewGameScreen/PlayerPickerTable/ | PlayerTable | null | | | OverviewScreen/DiplomacyOverviewTab/ | CivTable | null | | @@ -64,24 +86,28 @@ These shapes are used all over Unciv and can be replaced to make a lot of UI ele | OverviewScreen/ReligionOverviewTab/ | BeliefDescription | null | | | OverviewScreen/TradesOverviewTab/ | OffersTable | null | | | OverviewScreen/UnitOverviewTab/ | UnitSupplyTable | null | | +| PlayerReadyScreen/ | Background | null | | +| TechPickerScreen/ | Background | null | | +| TechPickerScreen/ | BottomTable | null | | | TechPickerScreen/ | TechButton | roundedEdgeRectangle | | | VictoryScreen/ | CivGroup | roundedEdgeRectangle | | | WorldScreen/ | AirUnitTable | null | | +| WorldScreen/ | BattleTable | null | | +| WorldScreen/ | Notification | roundedEdgeRectangle | | +| WorldScreen/ | PickTechButton | roundedEdgeRectangle | | +| WorldScreen/ | TileInfoTable | null | | +| WorldScreen/ | TutorialTaskTable | null | | +| WorldScreen/ | UnitTable | null | | | WorldScreen/CityButton/ | AirUnitTable | roundedEdgeRectangle | | | WorldScreen/CityButton/ | IconTable | roundedEdgeRectangle | | | WorldScreen/CityButton/ | InfluenceBar | null | | -| WorldScreen/ | Notification | null | | -| WorldScreen/ | PickTechButton | roundedEdgeRectangle | | -| WorldScreen/ | TutorialTaskTable | null | | -| WorldScreen/TopBar/ | ResourceTable | null | | -| WorldScreen/TopBar/ | StatsTable | null | | -| WorldScreen/TopBar/ | LeftAttachment | roundedEdgeRectangle | | -| WorldScreen/TopBar/ | RightAttachment | roundedEdgeRectangle | | -| WorldScreen/ | BattleTable | null | | -| WorldScreen/ | TileInfoTable | null | | | WorldScreen/Minimap/ | Background | null | | | WorldScreen/Minimap/ | Border | null | | -| WorldScreen/ | UnitTable | null | | +| WorldScreen/TopBar/ | LeftAttachment | roundedEdgeRectangle | | +| WorldScreen/TopBar/ | ResourceTable | null | | +| WorldScreen/TopBar/ | RightAttachment | roundedEdgeRectangle | | +| WorldScreen/TopBar/ | StatsTable | null | | + ## SkinConfig @@ -92,32 +118,34 @@ To create a config for your skin you just need to create a new .json file under This is an example of such a config file that will be explain below: ```json +{ "baseColor": {"r":1,"g":0,"b":0,"a":1}, "skinVariants": { "MainMenuScreen/MenuButton": { - "image": "MyCoolNewDesign", + "image": "MyCoolNewDesign" }, "TechPickerScreen/TechButton": { - "image": "MyCoolNewDesign", - "alpha": 0.7 + "image": "MyCoolNewDesign", + "alpha": 0.7 }, "WorldScreen/TopBar/ResourceTable": { - "alpha": 0.8 + "alpha": 0.8 }, "WorldScreen/UnitTable": { - "tint": {"r": 1, "g": 0, "b": 0}, - "image": "WorldScreen/TopBar/ResourceTable", - "alpha": 0.4 + "tint": {"r": 1, "g": 0, "b": 0}, + "image": "WorldScreen/TopBar/ResourceTable", + "alpha": 0.4 }, "WorldScreen/Minimap/Background": { - "tint": {"r": 0.2, "g": 0.4, "b": 0.45, "a": 1} - }, + "tint": {"r": 0.2, "g": 0.4, "b": 0.45, "a": 1} + } } +} ``` ### baseColor -A color defined with normalized RGBA values. Default value: "{"r": 0, "g": 0.251, "b": 0.522, "a": 0.749}" +A color defined with normalized RGBA values. Default value: `{"r": 0, "g": 0.251, "b": 0.522, "a": 0.749}` Defines the color unciv uses in most ui elements as default @@ -147,4 +175,4 @@ The color this UI element should have. A float value. Default value: null -The alpha this UI element should have. Overwrites the alpha value of tint if specified. +The alpha this UI element should have. Overwrites the alpha value of tint if specified. \ No newline at end of file diff --git a/docs/Modders/uniques.md b/docs/Modders/uniques.md index 73be258568..894dacac1e 100644 --- a/docs/Modders/uniques.md +++ b/docs/Modders/uniques.md @@ -1697,6 +1697,11 @@ Simple unique parameters are explained by mouseover. Complex parameters are expl Applicable to: Conditional +??? example "<if starting in the [era]>" + Example: "<if starting in the [Ancient era]>" + + Applicable to: Conditional + ??? example "<if no other Civilization has researched this>" Applicable to: Conditional