mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-05 23:20:48 +07:00
Changes to moddable UI (#8055)
* Replaced all occurrences of deprecated NinePatch function calls This makes a lot of UI elements already moddable but documentation is still missing * Added "How to create a UI skin for Unciv" to wiki * Added image * Fixed two typos and updated directory image Old image was missing a folder * Added clear color to skin config to support picker screen backgrounds * Removed deprecated functions in ImageGetter * Fixed lowercase ui element names they should always be UpperCamelCase to be consistent * Added UiElementDocsWriter to modify the docs for UI elements automatically * Added default shape to UiElementsDocsWriter.kt * Revert unintended merge errors * Rerun file auto generation
This commit is contained in:
parent
16a7eed4ff
commit
99b6a2254d
@ -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)
|
||||
|
@ -18,17 +18,20 @@ class SkinElement {
|
||||
|
||||
class SkinConfig {
|
||||
var baseColor: Color = Color(0x004085bf)
|
||||
var clearColor: Color = Color(0x000033ff)
|
||||
var skinVariants: HashMap<String, SkinElement> = 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()
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
)
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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() {
|
||||
|
@ -29,6 +29,7 @@ class GameOptionsTable(
|
||||
|
||||
init {
|
||||
getGameOptionsTable()
|
||||
background = BaseScreen.skinStrings.getUiBackground("NewGameScreen/GameOptionsTable", tintColor = BaseScreen.skinStrings.skinConfig.clearColor)
|
||||
}
|
||||
|
||||
fun update() {
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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()
|
||||
|
@ -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() {
|
||||
|
@ -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))
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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")
|
||||
|
@ -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 */
|
||||
|
@ -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 <T: Actor>(
|
||||
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")
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
)
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ internal object DesktopLauncher {
|
||||
|
||||
if (!isRunFromJAR) {
|
||||
UniqueDocsWriter().write()
|
||||
UiElementDocsWriter().write()
|
||||
}
|
||||
|
||||
val platformSpecificHelper = PlatformSpecificHelpersDesktop(config)
|
||||
|
40
desktop/src/com/unciv/app/desktop/UiElementDocsWriter.kt
Normal file
40
desktop/src/com/unciv/app/desktop/UiElementDocsWriter.kt
Normal file
@ -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("<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION -->")
|
||||
val endIndex = lines.indexOf("<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION_END -->")
|
||||
|
||||
val table = mutableListOf(
|
||||
"<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION -->",
|
||||
"| Directory | Name | Default shape | Image |",
|
||||
"|---|:---:|:---:|---|"
|
||||
)
|
||||
|
||||
val elements = mutableListOf<String>()
|
||||
|
||||
File("../../core/src/com/unciv/").walk().forEach { file ->
|
||||
if (file.path.endsWith(".kt")) {
|
||||
val results = Regex("getUiBackground\\((\\X*?)\"(?<path>.*)\"[ ,\n\r]*((BaseScreen\\.)?skinStrings\\.(?<defaultShape>.*)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("<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION_END -->")
|
||||
|
||||
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"))
|
||||
}
|
||||
}
|
@ -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. 
|
||||
|
||||
## 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
|
||||
|
||||
<!--- We should add an image to every identifier so its easier for modders to know which UI elements are which -->
|
||||
<!--- The following table is auto generated and should not be modified manually. If you want to change it see UiElementDocsWriter.kt -->
|
||||
|
||||
<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION -->
|
||||
| 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 | |
|
||||
<!--- DO NOT REMOVE OR MODIFY THIS LINE UI_ELEMENT_TABLE_REGION_END -->
|
||||
|
||||
## 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.
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user