diff --git a/android/Images.Skin/Skins/Minimal/layer-container.9.png b/android/Images.Skin/Skins/Minimal/layer-container.9.png new file mode 100644 index 0000000000000..324cdc12dd800 Binary files /dev/null and b/android/Images.Skin/Skins/Minimal/layer-container.9.png differ diff --git a/android/Images.Skin/Skins/Minimal/slider-bar.9.png b/android/Images.Skin/Skins/Minimal/slider-bar.9.png new file mode 100644 index 0000000000000..434ebf1991068 Binary files /dev/null and b/android/Images.Skin/Skins/Minimal/slider-bar.9.png differ diff --git a/android/Images.Skin/Skins/Minimal/tab-active.9.png b/android/Images.Skin/Skins/Minimal/tab-active.9.png new file mode 100644 index 0000000000000..07b257b196ddc Binary files /dev/null and b/android/Images.Skin/Skins/Minimal/tab-active.9.png differ diff --git a/android/Images.Skin/Skins/Minimal/tab.9.png b/android/Images.Skin/Skins/Minimal/tab.9.png new file mode 100644 index 0000000000000..43ce757221810 Binary files /dev/null and b/android/Images.Skin/Skins/Minimal/tab.9.png differ diff --git a/android/assets/Skin.atlas b/android/assets/Skin.atlas index d7cb473130edb..a8c5f086b310e 100644 --- a/android/assets/Skin.atlas +++ b/android/assets/Skin.atlas @@ -6,7 +6,7 @@ filter: Linear, Linear repeat: none Skins/Minimal/checkbox rotate: false - xy: 291, 23 + xy: 291, 29 size: 31, 31 split: 0, 0, 0, 0 orig: 31, 31 @@ -14,15 +14,23 @@ Skins/Minimal/checkbox index: -1 Skins/Minimal/checkbox-pressed rotate: false - xy: 252, 23 + xy: 252, 29 size: 31, 31 split: 0, 0, 0, 0 orig: 31, 31 offset: 0, 0 index: -1 +Skins/Minimal/layer-container + rotate: false + xy: 64, 4 + size: 10, 10 + split: 3, 3, 3, 3 + orig: 10, 10 + offset: 0, 0 + index: -1 Skins/Minimal/rectangleWithOutline rotate: false - xy: 64, 5 + xy: 362, 37 size: 3, 3 split: 0, 0, 0, 0 orig: 3, 3 @@ -30,7 +38,7 @@ Skins/Minimal/rectangleWithOutline index: -1 Skins/Minimal/roundedEdgeRectangle rotate: false - xy: 4, 4 + xy: 4, 10 size: 52, 50 split: 19, 20, 19, 21 pad: 12, 13, 7, 7 @@ -39,7 +47,7 @@ Skins/Minimal/roundedEdgeRectangle index: -1 Skins/Minimal/roundedEdgeRectangle-mid rotate: false - xy: 110, 16 + xy: 110, 22 size: 38, 38 split: 17, 17, 15, 15 pad: 17, 17, -1, -1 @@ -48,7 +56,7 @@ Skins/Minimal/roundedEdgeRectangle-mid index: -1 Skins/Minimal/roundedEdgeRectangle-mid-border rotate: false - xy: 64, 16 + xy: 64, 22 size: 38, 38 split: 18, 18, 18, 18 orig: 38, 38 @@ -56,7 +64,7 @@ Skins/Minimal/roundedEdgeRectangle-mid-border index: -1 Skins/Minimal/roundedEdgeRectangle-small rotate: false - xy: 330, 30 + xy: 330, 36 size: 24, 24 split: 10, 10, 10, 10 pad: 10, 10, 2, 2 @@ -65,7 +73,7 @@ Skins/Minimal/roundedEdgeRectangle-small index: -1 Skins/Minimal/roundedTopEdgeRectangle-small rotate: false - xy: 394, 42 + xy: 394, 48 size: 24, 12 split: 10, 10, 10, 0 pad: 10, 10, -1, -1 @@ -74,7 +82,7 @@ Skins/Minimal/roundedTopEdgeRectangle-small index: -1 Skins/Minimal/roundedTopEdgeRectangle-small-border rotate: false - xy: 362, 42 + xy: 362, 48 size: 24, 12 split: 10, 10, 10, 0 orig: 24, 12 @@ -82,7 +90,7 @@ Skins/Minimal/roundedTopEdgeRectangle-small-border index: -1 Skins/Minimal/select-box rotate: false - xy: 204, 24 + xy: 204, 30 size: 40, 30 split: 7, 9, 7, 7 orig: 40, 30 @@ -90,9 +98,33 @@ Skins/Minimal/select-box index: -1 Skins/Minimal/select-box-pressed rotate: false - xy: 156, 24 + xy: 156, 30 size: 40, 30 split: 7, 9, 7, 7 orig: 40, 30 offset: 0, 0 index: -1 +Skins/Minimal/slider-bar + rotate: false + xy: 82, 11 + size: 12, 3 + split: 3, 3, 0, 0 + orig: 12, 3 + offset: 0, 0 + index: -1 +Skins/Minimal/tab + rotate: false + xy: 448, 46 + size: 14, 14 + split: 0, 0, 0, 0 + orig: 14, 14 + offset: 0, 0 + index: -1 +Skins/Minimal/tab-active + rotate: false + xy: 426, 46 + size: 14, 14 + split: 0, 0, 0, 3 + orig: 14, 14 + offset: 0, 0 + index: -1 diff --git a/android/assets/Skin.json b/android/assets/Skin.json index 912cc94ae1b19..9cc451edb5513 100644 --- a/android/assets/Skin.json +++ b/android/assets/Skin.json @@ -5,18 +5,45 @@ "title": "Nativefont" }, "com.badlogic.gdx.graphics.Color": { - "black": { - "r": 0, - "g": 0, - "b": 0, - "a": 1 - }, - "color": { - "r": 0.2, - "g": 0.3, - "b": 0.5, - "a": 1 - }, + "base-10": {"r": 0.086, "g": 0.098, "b": 0.145}, + "base-20": {"r": 0.144, "g": 0.164, "b": 0.242}, + "base-30": {"r": 0.189, "g": 0.215, "b": 0.318}, + "base-40": {"r": 0.241, "g": 0.273, "b": 0.405}, + "base-50": {"r": 0.296, "g": 0.336, "b": 0.498}, + "base-60": {"r": 0.354, "g": 0.403, "b": 0.596}, + "base-70": {"r": 0.444, "g": 0.489, "b": 0.669}, + "base-80": {"r": 0.549, "g": 0.586, "b": 0.732}, + "base-90": {"r": 0.658, "g": 0.686, "b": 0.797}, + "base-100": {"r": 0.769, "g": 0.788, "b": 0.863}, + + "base-10-transparent": {"r": 0.086, "g": 0.098, "b": 0.145, "a": 0.925}, + "base-20-transparent": {"r": 0.144, "g": 0.164, "b": 0.242, "a": 0.925}, + "base-30-transparent": {"r": 0.189, "g": 0.215, "b": 0.318, "a": 0.925}, + "base-40-transparent": {"r": 0.241, "g": 0.273, "b": 0.405, "a": 0.925}, + "base-50-transparent": {"r": 0.296, "g": 0.336, "b": 0.498, "a": 0.925}, + "base-60-transparent": {"r": 0.354, "g": 0.403, "b": 0.596, "a": 0.925}, + "base-70-transparent": {"r": 0.444, "g": 0.489, "b": 0.669, "a": 0.925}, + "base-80-transparent": {"r": 0.549, "g": 0.586, "b": 0.732, "a": 0.925}, + "base-90-transparent": {"r": 0.658, "g": 0.686, "b": 0.797, "a": 0.925}, + "base-100-transparent": {"r": 0.769, "g": 0.788, "b": 0.863, "a": 0.925}, + + "base-20-transparent-stacked": {"r": 0.189, "g": 0.215, "b": 0.318, "a": 0.422}, + "base-30-transparent-stacked": {"r": 0.241, "g": 0.273, "b": 0.405, "a": 0.422}, + + "negative-40": { "hex": "#722d38" }, + "negative-50": { "hex": "#833440" }, + "negative-60": { "hex": "#943b48" }, + + "primary-50": { "hex": "#447d4f" }, + "primary-60": { "hex": "#3e7248" }, + "primary-40": { "hex": "#3b6644" }, + + "text-primary": { "hex": "#f4f4f4ff" }, + "text-subdued": {"r": 0.769, "g": 0.788, "b": 0.863, "a": 0.675}, + "text-interactive": { "hex": "#ffffffff" }, + + "black": {"r": 0.024, "g": 0.027, "b": 0.035}, + "gray": { "r": 0.5, "g": 0.5, @@ -59,12 +86,6 @@ "b": 1, "a": 1 }, - "positive": { - "r": 0.12156863, - "g": 0.49411765, - "b": 0.21960784, - "a": 1 - }, "negative": { "r": 0.5529412, "g": 0.03137255, @@ -139,45 +160,142 @@ } }, "com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable": { - "button-c": { + "base-container": { + "name": "layer-container", + "color": "base-10" + }, + "base-container-transparent": { + "name": "layer-container", + "color": "base-10-transparent" + }, + + "layer1-container": { + "name": "layer-container", + "color": "base-20" + }, + "layer1-transparent-container": { + "name": "layer-container", + "color": "base-20-transparent" + }, + "layer1-transparent-stacked-container": { + "name": "layer-container", + "color": "base-20-transparent-stacked" + }, + + "layer2-container": { + "name": "layer-container", + "color": "base-30" + }, + "layer2-transparent-container": { + "name": "layer-container", + "color": "base-30-transparent" + }, + "layer2-transparent-container": { + "name": "layer-container", + "color": "base-30-transparent-stacked" + }, + + "button": { "name": "RoundedEdgeRectangle", - "color": "color" + "color": "base-50" }, - "button-p": { + "button-down": { "name": "RoundedEdgeRectangle", - "color": "pressed" + "color": "base-40" }, - "button-h": { + "button-hover": { "name": "RoundedEdgeRectangle", - "color": "highlight" + "color": "base-60" }, "button-disabled": { "name": "RoundedEdgeRectangle", - "color": "disabled" + "color": "base-20" + }, + + "button-main-menu": { + "name": "RoundedEdgeRectangle", + "color": "base-50-transparent" + }, + "button-main-menu-down": { + "name": "RoundedEdgeRectangle", + "color": "base-40-transparent" + }, + "button-main-menu-hover": { + "name": "RoundedEdgeRectangle", + "color": "base-60-transparent" }, - "button-positive": { + "button-main-menu-disabled": { "name": "RoundedEdgeRectangle", - "color": "positive" + "color": "base-20-transparent" + }, + + "button-tab": { + "name": "tab", + "color": "base-40" + }, + "button-tab-down": { + "name": "tab", + "color": "base-30" + }, + "button-tab-hover": { + "name": "tab", + "color": "base-50" + }, + "button-tab-disabled": { + "name": "tab", + "color": "base-20" + }, + + "button-tab-active": { + "name": "tab-active", + "color": "base-50" }, + "button-tab-active-down": { + "name": "tab-active", + "color": "base-40" + }, + "button-tab-active-hover": { + "name": "tab-active", + "color": "base-60" + }, + "button-tab-active-disabled": { + "name": "tab-active", + "color": "base-20" + }, + + "button-primary": { + "name": "RoundedEdgeRectangle", + "color": "primary-50" + }, + "button-primary-down": { + "name": "RoundedEdgeRectangle", + "color": "primary-40" + }, + "button-primary-hover": { + "name": "RoundedEdgeRectangle", + "color": "primary-60" + }, + "button-negative": { "name": "RoundedEdgeRectangle", - "color": "negative" + "color": "negative-50" }, "button-negative-pressed": { "name": "RoundedEdgeRectangle", - "color": "negative-selected" + "color": "negative-40" }, "button-negative-hover": { "name": "RoundedEdgeRectangle", - "color": "negative-highlight" + "color": "negative-60" }, + "checkbox-c": { "name": "Checkbox", - "color": "color" + "color": "base-50" }, "checkbox-pressed-c": { "name": "Checkbox-pressed", - "color": "color" + "color": "base-50" }, "checkbox-disabled-c": { "name": "Checkbox", @@ -187,17 +305,23 @@ "name": "Checkbox-pressed", "color": "disabled" }, - "list-c": { + + "list": { "name": "RectangleWithOutline", - "color": "color" + "color": "base-50" }, + "list-active": { + "name": "RectangleWithOutline", + "color": "base-60" + }, + "scrollbar-c": { "name": "Scrollbar", - "color": "color" + "color": "base-60" }, "select-box-c": { "name": "Select-box", - "color": "color" + "color": "base-60" }, "select-box-disabled": { "name": "Select-box", @@ -205,7 +329,7 @@ }, "select-box-pressed-c": { "name": "Select-box-pressed", - "color": "color" + "color": "base-60" }, "select-box-h": { "name": "Select-box", @@ -215,45 +339,52 @@ "name": "Scrollbar", "color": "default-clear" }, - "slider-knob-c": { - "name": "Circle", - "color": "color" + + "slider-knob": { + "name": "slider-knob", + "color": "base-50" }, - "slider-horizontal-s": { - "name": "Rectangle", - "color": "selection" + "slider-horizontal-bar-filled": { + "name": "slider-bar", + "color": "base-50" + }, + "slider-horizontal-bar-unfilled": { + "name": "slider-bar", + "color": "base-70" }, "slider-vertical-s": { "name": "Rectangle", "color": "selection" }, - "slider-knob-h": { - "name": "Circle", - "color": "highlight" + "slider-knob-hover": { + "name": "slider-knob", + "color": "base-60" }, - "slider-horizontal-p": { - "name": "Rectangle", - "color": "pressed" + "slider-knob-down": { + "name": "slider-knob", + "color": "base-40" }, "slider-vertical-p": { "name": "Rectangle", "color": "pressed" }, + "splitpane-horizontal-c": { "name": "RectangleWithOutline", - "color": "color" + "color": "base-50" }, "splitpane-vertical-c": { "name": "RectangleWithOutline", - "color": "color" + "color": "base-50" }, - "textfield-c": { + + "textfield": { "name": "RoundedEdgeRectangle", - "color": "color" + "color": "base-50" }, - "selection": { - "name": "Rectangle", - "color": "selection" + "textfield-active": { + "name": "RoundedEdgeRectangle", + "color": "base-60" }, "white": { "name": "Rectangle", @@ -262,9 +393,28 @@ }, "com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle": { "default": { - "up": "button-c", - "down": "button-p", - "over": "button-h" + "up": "button", + "down": "button-down", + "over": "button-hover", + "disabled": "button-tab-disabled" + }, + "main-menu": { + "up": "button-main-menu", + "down": "button-main-menu-down", + "over": "button-main-menu-hover", + "disabled": "button-tab-disabled" + }, + "tab": { + "up": "button-tab", + "down": "button-tab-down", + "over": "button-tab-hover", + "disabled": "button-tab-disabled" + }, + "tab-active": { + "up": "button-tab-active", + "down": "button-tab-active-down", + "over": "button-tab-active-hover", + "disabled": "button-tab-disabled" } }, "com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle": { @@ -274,16 +424,16 @@ "checkboxOff": "checkbox-c", "checkboxOffDisabled": "checkbox-disabled-c", "font": "button", - "fontColor": "color", - "downFontColor": "pressed", - "overFontColor": "highlight", - "disabledFontColor": "gray" + "fontColor": "text-primary", + "downFontColor": "text-primary", + "overFontColor": "text-primary", + "disabledFontColor": "text-primary" } }, "com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle": { "default": { "font": "font", - "fontColor": "color" + "fontColor": "text-primary" } }, "com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle": { @@ -291,8 +441,8 @@ "font": "font", "fontColorSelected": "white", "fontColorUnselected": "white", - "selection": "selection", - "background": "list-c" + "selection": "list-active", + "background": "list" } }, "com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle": { @@ -309,7 +459,7 @@ "com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle": { "default": { "font": "font", - "fontColor": "white", + "fontColor": "text-primary", "background": "select-box-c", "scrollStyle": "select-box-scroll", "listStyle": "default", @@ -320,17 +470,18 @@ }, "com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle": { "default-horizontal": { - "knobOver": "slider-knob-h", - "knobDown": "slider-knob-h", - "background": "slider-horizontal-p", - "knob": "slider-knob-c", - "knobBefore": "slider-horizontal-s" + "knobOver": "slider-knob-hover", + "knobDown": "slider-knob-down", + "background": "slider-bar", + "knob": "slider-knob", + "knobAfter": "slider-horizontal-bar-unfilled", + "knobBefore": "slider-horizontal-bar-filled" }, "default-vertical": { - "knobOver": "slider-knob-h", - "knobDown": "slider-knob-h", + "knobOver": "slider-knob-hover", + "knobDown": "slider-knob-down", "background": "slider-vertical-p", - "knob": "slider-knob-c", + "knob": "slider-knob", "knobBefore": "slider-vertical-s" } }, @@ -345,48 +496,39 @@ "com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle": { "default": { "font": "button", - "fontColor": "white", - "downFontColor": "white", - "overFontColor": "dark-gray", - "up": "button-c", - "down": "button-p", - "over": "button-h" + "fontColor": "text-primary", + "downFontColor": "text-primary", + "overFontColor": "text-primary", + "up": "button", + "down": "button-down", + "over": "button-hover" }, "positive": { "font": "button", - "fontColor": "white", - "downFontColor": "white", - "overFontColor": "dark-gray", - "up": "button-positive", - "down": "button-p", - "over": "button-h" + "fontColor": "text-primary", + "downFontColor": "text-primary", + "overFontColor": "text-primary", + "up": "button-primary", + "down": "button-primary-down", + "over": "button-primary-hover" }, "negative": { "font": "button", - "fontColor": "white", - "downFontColor": "white", - "overFontColor": "white", + "fontColor": "text-primary", + "downFontColor": "text-primary", + "overFontColor": "text-primary", "up": "button-negative", "down": "button-negative-pressed", "over": "button-negative-hover" - }, - "disabled": { - "font": "button", - "fontColor": "white", - "downFontColor": "white", - "overFontColor": "white", - "up": "button-disabled", - "down": "button-disabled", - "over": "button-disabled" } }, "com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle": { "default": { "font": "font", - "fontColor": "white", - "background": "textfield-c", + "fontColor": "text-primary", + "background": "textfield", "cursor": "white", - "selection": "selection" + "selection": "textfield-active" } }, "com.unciv.ui.screens.pickerscreens.PromotionScreenColors": { diff --git a/android/assets/Skin.png b/android/assets/Skin.png index 8bc279ea4a346..e45594f3fb53a 100644 Binary files a/android/assets/Skin.png and b/android/assets/Skin.png differ diff --git a/core/src/com/unciv/models/skins/SkinConfig.kt b/core/src/com/unciv/models/skins/SkinConfig.kt index 9fca0333ae005..0b4f630cbf47d 100644 --- a/core/src/com/unciv/models/skins/SkinConfig.kt +++ b/core/src/com/unciv/models/skins/SkinConfig.kt @@ -4,8 +4,8 @@ import com.badlogic.gdx.graphics.Color import com.unciv.Constants class SkinConfig(initialCapacity: Int) { - var baseColor: Color = Color(0x004085bf) - var clearColor: Color = Color(0x000033ff) + var baseColor: Color = Color(0x575b82ff) + var clearColor: Color = Color(0x161721ff) var defaultVariantTint: Color? = null var fallbackSkin: String? = Constants.defaultFallbackSkin var skinVariants: HashMap = HashMap(initialCapacity) diff --git a/core/src/com/unciv/models/skins/SkinStrings.kt b/core/src/com/unciv/models/skins/SkinStrings.kt index 6640320e66322..80702f2e1f331 100644 --- a/core/src/com/unciv/models/skins/SkinStrings.kt +++ b/core/src/com/unciv/models/skins/SkinStrings.kt @@ -23,6 +23,10 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) { val selectBoxPressedShape = "select-box-pressed" val checkboxShape = "checkbox" val checkboxPressedShape = "checkbox-pressed" + val sliderBarShape = "slider-bar" + val layerContainerShape = "layer-container" + val tabShape = "tab" + val tabActiveShape = "tab-active" /** * Gets either a drawable which was defined inside skinConfig for the given path or the drawable @@ -48,26 +52,14 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) { * separate alpha value, it will be applied to a clone of either color. */ fun getUiBackground(path: String, default: String? = null, tintColor: Color? = null): NinePatchDrawable { - val locationForDefault = skinLocation + default - val locationByName = skinLocation + path val skinVariant = skinConfig.skinVariants[path] - val locationByConfigVariant = if (skinVariant?.image != null) skinLocation + skinVariant.image else null + val tint = (skinVariant?.tint ?: skinConfig.defaultVariantTint ?: tintColor)?.run { if (skinVariant?.alpha == null) this else cpy().apply { a = skinVariant.alpha } } - val location = when { - locationByConfigVariant != null && ImageGetter.ninePatchImageExists(locationByConfigVariant) -> - locationByConfigVariant - ImageGetter.ninePatchImageExists(locationByName) -> - locationByName - default != null && ImageGetter.ninePatchImageExists(locationForDefault) -> - locationForDefault - else -> - null - } - + val location = getNinePatchLocation(path, default) if (location != null) { return ImageGetter.getNinePatch(location, tint) } @@ -97,6 +89,33 @@ class SkinStrings(skin: String = UncivGame.Current.settings.skin) { return ImageGetter.getNinePatch(fallbackLocation, fallbackTint) } + /* + * Split-off from getUIBackground() to separately check + * whether a skin variant exists easier + */ + fun getNinePatchLocation(path: String, default: String? = null): String? { + val locationForDefault = skinLocation + default + val locationByName = skinLocation + path + val locationByConfigVariant = + if (skinConfig.skinVariants[path]?.image != null) + skinLocation + skinConfig.skinVariants[path]!!.image + else null + + return when { + locationByConfigVariant != null && ImageGetter.ninePatchImageExists(locationByConfigVariant) -> + locationByConfigVariant + ImageGetter.ninePatchImageExists(locationByName) -> + locationByName + default != null && ImageGetter.ninePatchImageExists(locationForDefault) -> + locationForDefault + else -> + null + } + } + + /* An alias for getNinePatchLocation that only cares for valid or null, and returns a Boolean */ + fun ninePatchExists(path: String): Boolean = (getNinePatchLocation(path) != null) + fun getUIColor(path: String, default: Color? = null) = skinConfig.skinVariants[path]?.tint ?: default diff --git a/core/src/com/unciv/ui/components/SmallButtonStyle.kt b/core/src/com/unciv/ui/components/SmallButtonStyle.kt index d0974e1be304c..fc0de35ad9379 100644 --- a/core/src/com/unciv/ui/components/SmallButtonStyle.kt +++ b/core/src/com/unciv/ui/components/SmallButtonStyle.kt @@ -21,10 +21,10 @@ class SmallButtonStyle : TextButton.TextButtonStyle(BaseScreen.skin[TextButton.T } init { - val upColor = BaseScreen.skin.getColor("color") - val downColor = BaseScreen.skin.getColor("pressed") - val overColor = BaseScreen.skin.getColor("highlight") - val disabledColor = BaseScreen.skin.getColor("disabled") + val upColor = BaseScreen.skin.getColor("base-40") + val downColor = BaseScreen.skin.getColor("base-60") + val overColor = BaseScreen.skin.getColor("base-80") + val disabledColor = BaseScreen.skin.getColor("base-40") // UiElementDocsWriter inspects source, which is why this isn't prettified better val shape = BaseScreen.run { // Let's use _one_ skinnable background lookup but with different tints diff --git a/core/src/com/unciv/ui/components/UncivTooltip.kt b/core/src/com/unciv/ui/components/UncivTooltip.kt index b27ad178d5d07..0054aeaa214e8 100644 --- a/core/src/com/unciv/ui/components/UncivTooltip.kt +++ b/core/src/com/unciv/ui/components/UncivTooltip.kt @@ -243,7 +243,7 @@ class UncivTooltip ( if (!(always || GUI.keyboardAvailable) || text.isEmpty()) return - val labelColor = BaseScreen.skinStrings.skinConfig.baseColor + val labelColor = BaseScreen.skin.getColor("base-40") val label = if (hideIcons) text.toLabel(labelColor, fontSize = 38, hideIcons = true) else ColorMarkupLabel(text, labelColor, fontSize = 38) label.setAlignment(Align.center) diff --git a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt index b496b338a135d..16dfa6f920d0d 100644 --- a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt +++ b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt @@ -45,36 +45,15 @@ import com.unciv.ui.screens.basescreen.BaseScreen * Collection of extension functions mostly for libGdx widgets */ -private class RestorableTextButtonStyle( - baseStyle: TextButtonStyle, - val restoreStyle: ButtonStyle -) : TextButtonStyle(baseStyle) - -//todo ButtonStyle *does* have a `disabled` Drawable, and Button ignores touches in disabled state anyway - all this is a wrong approach /** Disable a [Button] by setting its [touchable][Button.touchable] and [style][Button.style] properties. */ fun Button.disable() { - touchable = Touchable.disabled isDisabled = true - val oldStyle = style - if (oldStyle is RestorableTextButtonStyle) return - val disabledStyle = BaseScreen.skin.get("disabled", TextButtonStyle::class.java) - style = RestorableTextButtonStyle(disabledStyle, oldStyle) } /** Enable a [Button] by setting its [touchable][Button.touchable] and [style][Button.style] properties. */ fun Button.enable() { - val oldStyle = style - if (oldStyle is RestorableTextButtonStyle) { - style = oldStyle.restoreStyle - } isDisabled = false - touchable = Touchable.enabled } -/** Enable or disable a [Button] by setting its [touchable][Button.touchable] and [style][Button.style] properties, - * or returns the corresponding state. - * - * Do not confuse with Gdx' builtin [isDisabled][Button.isDisabled] property, - * which is more appropriate to toggle On/Off buttons, while this one is good for 'click-to-do-something' buttons. - */ + var Button.isEnabled: Boolean get() = touchable == Touchable.enabled set(value) = if (value) enable() else disable() @@ -199,14 +178,14 @@ fun Group.addBorderAllowOpacity(size: Float, color: Color): Group { /** get background Image for a new separator */ private fun getSeparatorImage(color: Color) = Image(ImageGetter.getWhiteDotDrawable().tint( - if (color.a != 0f) color else BaseScreen.skin.getColor("color") //0x334d80 + if (color.a != 0f) color else BaseScreen.skin.getColor("base-40") )) /** * Create a horizontal separator as an empty Container with a colored background. * @param colSpan Optionally override [colspan][Cell.colspan] which defaults to the current column count. */ -fun Table.addSeparator(color: Color = BaseScreen.skin.getColor("color"), colSpan: Int = 0, height: Float = 1f): Cell { +fun Table.addSeparator(color: Color = BaseScreen.skin.getColor("base-40"), colSpan: Int = 0, height: Float = 1f): Cell { if (!cells.isEmpty && !cells.last().isEndRow) row() val separator = getSeparatorImage(color) val cell = add(separator) @@ -225,6 +204,37 @@ fun Table.addSeparatorVertical(color: Color = Color.WHITE, width: Float = 2f): C return add(getSeparatorImage(color)).width(width).fillY() } +/** + * Sets the background Drawable of a Table based on its layer in the hierarchy. + * 0 is the true background and will have no effect if used. + * + * @param layer the layer, where 0 is the 2 is the topmost. + * @param transparent transparent layering, used for world-screen and some other effects. + * @param stacked when multiple transparent layers are used, set this to true to compensate for stacking. + * @param custom allows custom skins to override the layer background + * @return the table, for chaining + */ +fun Table.setLayer( + layer: Int = 1, + transparent: Boolean = false, + stacked: Boolean = false, + custom: String = "" +): Table { + if (!custom.isBlank() && BaseScreen.skinStrings.ninePatchExists(custom)) { + BaseScreen.skinStrings.getUiBackground(custom, tintColor = BaseScreen.skin.getColor("base-20")) + return this + } + setBackground(BaseScreen.skin.getDrawable(when (layer) { + 0 -> if (!transparent) "base-container" else "base-container-transparent" + 1 -> if (!transparent) "layer1-container" + else if (!stacked) "layer1-transparent-container" else "layer1-transparent-stacked-container" + 2 -> if (!transparent) "layer2-container" + else if (!stacked) "layer2-transparent-container" else "layer2-transparent-stacked-container" + else -> "layer1-container" + })) + return this +} + /** Alternative to [Table].[add][Table] that returns the Table instead of the new Cell to allow a different way of chaining */ fun Table.addCell(actor: T): Table { add(actor) @@ -277,7 +287,7 @@ fun String.toImageButton(iconSize: Float, circleSize: Float, circleColor: Color, fun getCloseButton( size: Float = 50f, iconSize: Float = size - 20f, - circleColor: Color = BaseScreen.skinStrings.skinConfig.baseColor, + circleColor: Color = BaseScreen.skin.getColor("base-40"), overColor: Color = Color.RED, action: () -> Unit ): Group { @@ -293,24 +303,36 @@ fun String.toLabel() = Label(this.tr(), BaseScreen.skin) fun Int.toLabel() = this.tr().toLabel() /** Translate a [String] and make a [Label] widget from it with a specified font color and size */ -fun String.toLabel(fontColor: Color = Color.WHITE, +fun String.toLabel(fontColor: Color = BaseScreen.skin.getColor("text-primary"), fontSize: Int = Constants.defaultFontSize, alignment: Int = Align.left, hideIcons: Boolean = false): Label { + // We don't want to use setFontSize and setFontColor because they set the font, - // which means we need to rebuild the font cache which means more memory allocation. + // which means we need to rebuild the font cache which means more memory allocation. var labelStyle = BaseScreen.skin.get(Label.LabelStyle::class.java) - if (fontColor != Color.WHITE || fontSize != Constants.defaultFontSize) { // if we want the default we don't need to create another style + + // if we want the default we don't need to create another style + if ( + fontColor != BaseScreen.skin.getColor("text-primary") + || fontSize != Constants.defaultFontSize + ) { labelStyle = Label.LabelStyle(labelStyle) // clone this to another labelStyle.fontColor = fontColor if (fontSize != Constants.defaultFontSize) labelStyle.font = Fonts.font } + return Label(this.tr(hideIcons), labelStyle).apply { setFontScale(fontSize / Fonts.ORIGINAL_FONT_SIZE) setAlignment(alignment) } } +fun String.toHeadingLabel() = this.toLabel( + BaseScreen.skin.getColor("text-interactive"), + Constants.headingFontSize +) + /** * Translate a [String] and make a [CheckBox] widget from it. * @param changeAction A callback to call on change, with a boolean lambda parameter containing the current [isChecked][CheckBox.isChecked]. diff --git a/core/src/com/unciv/ui/components/fonts/Fonts.kt b/core/src/com/unciv/ui/components/fonts/Fonts.kt index c32b7fd3bc247..be35bbc97df64 100644 --- a/core/src/com/unciv/ui/components/fonts/Fonts.kt +++ b/core/src/com/unciv/ui/components/fonts/Fonts.kt @@ -5,6 +5,7 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont import com.badlogic.gdx.graphics.g2d.TextureRegion import com.unciv.GUI import com.unciv.UncivGame +import com.unciv.Constants import com.unciv.ui.components.MayaCalendar import com.unciv.ui.components.extensions.getReadonlyPixmap import com.unciv.ui.components.fonts.Fonts.extractPixmapFromTextureRegion @@ -74,6 +75,13 @@ object Fonts { return ratio * fontSize.toFloat() + 2.25f } + /** + * Utility for standardised, flexible, and dynamic spacing. + * @param from The desired spacing in rem. + * @return The true spacing to add via pad() or other functions. + */ + fun rem(from: Float): Float = from * Constants.defaultFontSize.toFloat() + /** * Turn a TextureRegion into a Pixmap. * diff --git a/core/src/com/unciv/ui/components/widgets/ExpanderTab.kt b/core/src/com/unciv/ui/components/widgets/ExpanderTab.kt index ef910355ef40f..8b427396e517e 100644 --- a/core/src/com/unciv/ui/components/widgets/ExpanderTab.kt +++ b/core/src/com/unciv/ui/components/widgets/ExpanderTab.kt @@ -79,7 +79,7 @@ class ExpanderTab( header.background( BaseScreen.skinStrings.getUiBackground( "General/ExpanderTab", - tintColor = BaseScreen.skinStrings.skinConfig.baseColor + tintColor = BaseScreen.skin.getColor("base-40") ) ) if (icon != null) header.add(icon) diff --git a/core/src/com/unciv/ui/components/widgets/LanguageTable.kt b/core/src/com/unciv/ui/components/widgets/LanguageTable.kt index 4765ab872f454..753207607b39d 100644 --- a/core/src/com/unciv/ui/components/widgets/LanguageTable.kt +++ b/core/src/com/unciv/ui/components/widgets/LanguageTable.kt @@ -25,8 +25,8 @@ import java.util.Locale * @see addLanguageTables */ internal class LanguageTable(val language: String, val percentComplete: Int) : Table() { - private val baseColor = BaseScreen.skinStrings.skinConfig.baseColor - private val darkBaseColor = baseColor.darken(0.5f) + private val baseColor = BaseScreen.skin.getColor("base-40") + private val darkBaseColor = BaseScreen.skin.getColor("base-40") init{ pad(10f) diff --git a/core/src/com/unciv/ui/components/widgets/TabbedPager.kt b/core/src/com/unciv/ui/components/widgets/TabbedPager.kt index cafcd9bf801bd..32a7fdafac382 100644 --- a/core/src/com/unciv/ui/components/widgets/TabbedPager.kt +++ b/core/src/com/unciv/ui/components/widgets/TabbedPager.kt @@ -19,11 +19,11 @@ import com.unciv.Constants import com.unciv.UncivGame import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.addSeparator -import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.isEnabled import com.unciv.ui.components.extensions.packIfNeeded import com.unciv.ui.components.extensions.pad import com.unciv.ui.components.extensions.scrollTo +import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.onActivation @@ -72,8 +72,7 @@ open class TabbedPager( maximumHeight: Float = Float.MAX_VALUE, private val headerFontSize: Int = Constants.defaultFontSize, private val headerFontColor: Color = Color.WHITE, - private val highlightColor: Color = Color.BLUE, - backgroundColor: Color = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f), + backgroundColor: Color = BaseScreen.skin.getColor("base-40"), private val headerPadding: Float = 10f, separatorColor: Color = Color.CLEAR, private val shortcutScreen: BaseScreen? = null, @@ -145,11 +144,8 @@ open class TabbedPager( val button = IconTextButton(caption, icon, pager.headerFontSize, pager.headerFontColor).apply { name = caption // enable finding pages by untranslated caption without needing our own field - if (icon != null) { - if (iconSize != 0f) - iconCell.size(iconSize) - iconCell.padRight(pager.headerPadding * 0.5f) - } + setStyle(BaseScreen.skin.get("tab", Button.ButtonStyle::class.java)) + if (icon != null && iconSize != 0f) iconCell.size(iconSize) } var buttonX = 0f var buttonW = 0f @@ -307,20 +303,22 @@ open class TabbedPager( dimW = DimensionMeasurement.from(minimumWidth, maximumWidth, screenWidth) dimH = DimensionMeasurement.from(minimumHeight, maximumHeight, screenHeight) - background = BaseScreen.skinStrings.getUiBackground("General/TabbedPager", tintColor = backgroundColor) + background = BaseScreen.skinStrings.getUiBackground( + "General/TabbedPager", tintColor = backgroundColor) - header.defaults().pad(headerPadding, headerPadding * 0.5f) // Measure header height, most likely its final value removePage(addPage("Dummy")) add(headerScroll).growX().minHeight(headerHeight) - headerDecorationRightCell = add().pad(0f) + headerDecorationRightCell = add() row() if (separatorColor != Color.CLEAR) addSeparator(separatorColor) + add(contentScroll).pad(Fonts.rem(1f)).padTop(0f).colspan(2).grow().row() + fixedContentScrollCell = add(fixedContentScroll) - fixedContentScrollCell.colspan(2).growX().row() - add(contentScroll).colspan(2).grow().row() + fixedContentScrollCell.padTop(0f).colspan(2).growX().row() + } //endregion @@ -369,7 +367,7 @@ open class TabbedPager( if (activePage != -1) { val page = pages[activePage] (page.content as? IPageExtensions)?.deactivated(activePage, page.caption, this) - page.button.color = Color.WHITE + page.button.style = BaseScreen.skin.get("tab", Button.ButtonStyle::class.java) fixedContentScroll.actor = null page.scrollX = contentScroll.scrollX page.scrollY = contentScroll.scrollY @@ -380,7 +378,7 @@ open class TabbedPager( if (index != -1) { val page = pages[index] - page.button.color = highlightColor + page.button.style = BaseScreen.skin.get("tab-active", Button.ButtonStyle::class.java) if (page.scrollAlign != 0) { if (Align.isCenterHorizontal(page.scrollAlign)) diff --git a/core/src/com/unciv/ui/components/widgets/UncivSlider.kt b/core/src/com/unciv/ui/components/widgets/UncivSlider.kt index 882ae1a9a16ba..14cdf1e19e14d 100644 --- a/core/src/com/unciv/ui/components/widgets/UncivSlider.kt +++ b/core/src/com/unciv/ui/components/widgets/UncivSlider.kt @@ -25,6 +25,7 @@ import com.unciv.ui.components.extensions.isShiftKeyPressed import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.input.onClick +import com.unciv.ui.components.widgets.TabbedPager import com.unciv.ui.components.widgets.UncivSlider.Companion.formatPercent import com.unciv.ui.images.IconCircleGroup import com.unciv.ui.images.ImageGetter @@ -42,6 +43,7 @@ import kotlin.math.sign * Note: No attempt is made to distinguish sources of value changes, so the initial setting * of the value when a screen is initialized will also trigger the 'tip'. This is intentional. * + * @param label A string describing what the slider controls. * @param min Initializes [Slider.min] * @param max Initializes [Slider.max] * @param step Initializes [Slider.stepSize] @@ -54,12 +56,13 @@ import kotlin.math.sign * @param onChange Optional lambda gets called with the current value on a user change (not when setting value programmatically). */ class UncivSlider ( + text: String, min: Float, max: Float, step: Float, + initial: Float, vertical: Boolean = false, plusMinus: Boolean = true, - initial: Float, sound: UncivSound = UncivSound.Slider, private val tipType: TipType = TipType.Permanent, private val getTipText: ((Float) -> String)? = null, @@ -81,10 +84,8 @@ class UncivSlider ( } // component widgets - private val slider = Slider(min, max, step, vertical, BaseScreen.skin) - private val minusButton: IconCircleGroup? - private val plusButton: IconCircleGroup? - private val tipLabel = "".toLabel(Color.LIGHT_GRAY) + private val label = text.toLabel() + private val tipLabel = "".toLabel() private val tipContainer: Container