Revert "Make ExpanderTab "expand" properly (#9522)"

This reverts commit ae74dca0748f84db8e70b20fae8f914663f0a56f.
This commit is contained in:
Yair Morgenstern 2023-06-12 22:54:37 +03:00
parent dc030bfbad
commit c27bb5d74d
11 changed files with 136 additions and 244 deletions

View File

@ -1,41 +1,31 @@
package com.unciv.ui.components package com.unciv.ui.components
import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Interpolation
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup
import com.badlogic.gdx.scenes.scene2d.utils.Layout
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.models.metadata.GameSettings
import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.input.onClick
import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.components.input.onClick
import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.basescreen.BaseScreen
import kotlin.math.abs
/** /**
* A widget with a header that when clicked shows/hides a sub-Table. * A widget with a header that when clicked shows/hides a sub-Table.
* *
* @param title The header text, automatically translated. * @param title The header text, automatically translated.
* @param fontSize Size applied to header text (only) * @param fontSize Size applied to header text (only)
* @param icon Optional icon - please use [Image] or [IconCircleGroup] and make sure size is set * @param icon Optional icon - please use [Image][com.badlogic.gdx.scenes.scene2d.ui.Image] or [IconCircleGroup]
* @param startsOutOpened Default initial "open" state if no [persistenceID] set or no persistes state found
* @param defaultPad Padding between content and wrapper. * @param defaultPad Padding between content and wrapper.
* @param headerPad Default padding for the header Table. * @param headerPad Default padding for the header Table.
* @param headerAlign How the header content aligns - use [Align] constants. * @param expanderWidth If set initializes header width
* @param expanderWidth If set initializes cell minWidth and wrapper width
* @param persistenceID If specified, the ExpanderTab will remember its open/closed state for the duration of one app run * @param persistenceID If specified, the ExpanderTab will remember its open/closed state for the duration of one app run
* @param animated Controls whether opening/closing is animated, defaults to the [continuousRendering][GameSettings.continuousRendering] setting. * @param onChange If specified, this will be called after the visual change for a change in [isOpen] completes (e.g. to react to changed size)
* @param content An [Actor] supporting [Layout] with the content to display in expanded state. Will be `pack()`ed! * @param initContent Optional lambda with [innerTable] as parameter, to help initialize content.
* @param onChange If specified, this will be called on any visual change: repeatedly during animation if enabled, otherwise once after each change to [isOpen]. (e.g. to react to changed size)
*/ */
class ExpanderTab( class ExpanderTab(
title: String, title: String,
@ -44,64 +34,27 @@ class ExpanderTab(
startsOutOpened: Boolean = true, startsOutOpened: Boolean = true,
defaultPad: Float = 10f, defaultPad: Float = 10f,
headerPad: Float = 10f, headerPad: Float = 10f,
headerAlign: Int = Align.center, expanderWidth: Float = 0f,
private val expanderWidth: Float = 0f,
private val persistenceID: String? = null, private val persistenceID: String? = null,
animated: Boolean? = null, private val onChange: (() -> Unit)? = null,
private val content: WidgetGroup, initContent: ((Table) -> Unit)? = null
private val onChange: (() -> Unit)? = null ): Table(BaseScreen.skin) {
) : Table(BaseScreen.skin) { private companion object {
/** Alternate builder-style constructor for an [ExpanderTab] const val arrowSize = 18f
* const val arrowImage = "OtherIcons/BackArrow"
* @param initContent A lambda with the future [content] as parameter, to help initialize. Will be `pack()`ed when done! val arrowColor = Color(1f,0.96f,0.75f,1f)
*/ const val animationDuration = 0.2f
constructor(
title: String,
fontSize: Int = Constants.headingFontSize,
icon: Actor? = null,
startsOutOpened: Boolean = true,
defaultPad: Float = 10f,
headerPad: Float = 10f,
headerAlign: Int = Align.center,
expanderWidth: Float = 0f,
persistenceID: String? = null,
animated: Boolean? = null,
onChange: (() -> Unit)? = null,
initContent: ((Table) -> Unit)
) : this (
title, fontSize, icon, startsOutOpened, defaultPad,
headerPad, headerAlign, expanderWidth, persistenceID, animated,
Table(BaseScreen.skin).apply {
defaults().growX()
initContent(this)
},
onChange
)
companion object { val persistedStates = HashMap<String, Boolean>()
private const val arrowSize = 18f
private const val arrowImage = "OtherIcons/BackArrow"
private val arrowColor = Color(1f,0.96f,0.75f,1f)
private const val animationDurationForStageHeight = 0.5f // also serves as maximum
private val persistedStates = HashMap<String, Boolean>()
} }
// _Please_ don't make header, wrapper or content public. Makes tweaking this widget harder. val header = Table(skin) // Header with label and icon, touchable to show/hide
// If more control is needed and the parameter count gets too high, consider using a Style class
// or open class / protected fun createHeader() or dedicated setters instead.
private val header = Table(skin) // Header with label and icon, touchable to show/hide
private val headerLabel = title.toLabel(fontSize = fontSize) private val headerLabel = title.toLabel(fontSize = fontSize)
private val arrowIcon = ImageGetter.getImage(arrowImage) private val headerIcon = ImageGetter.getImage(arrowImage)
private val headerCell: Cell<Table> private val contentWrapper = Table() // Wrapper for innerTable, this is what will be shown/hidden
private val wrapper: Container<WidgetGroup> /** The container where the client should add the content to toggle */
private val wrapperCell: Cell<Container<WidgetGroup>> val innerTable = Table()
private var wrapperWidth: Float = 0f
private var wrapperHeight: Float = 0f
private var currentPercent = 0f
private val noAnimation = !(animated ?: UncivGame.Current.settings.continuousRendering)
/** Indicates whether the contents are currently shown, changing this will animate the widget */ /** Indicates whether the contents are currently shown, changing this will animate the widget */
// This works because a HashMap _could_ store an entry for the null key but we cannot actually store one when declaring as HashMap<String, Boolean> // This works because a HashMap _could_ store an entry for the null key but we cannot actually store one when declaring as HashMap<String, Boolean>
@ -113,14 +66,11 @@ class ExpanderTab(
} }
init { init {
setLayoutEnabled(false)
header.align(headerAlign)
header.defaults().pad(headerPad) header.defaults().pad(headerPad)
arrowIcon.setSize(arrowSize, arrowSize) headerIcon.setSize(arrowSize, arrowSize)
arrowIcon.setOrigin(Align.center) headerIcon.setOrigin(Align.center)
arrowIcon.rotation = 180f headerIcon.rotation = 180f
arrowIcon.color = arrowColor headerIcon.color = arrowColor
header.background( header.background(
BaseScreen.skinStrings.getUiBackground( BaseScreen.skinStrings.getUiBackground(
"General/ExpanderTab", "General/ExpanderTab",
@ -129,78 +79,48 @@ class ExpanderTab(
) )
if (icon != null) header.add(icon) if (icon != null) header.add(icon)
header.add(headerLabel) header.add(headerLabel)
header.add(arrowIcon).size(arrowSize).align(Align.center) header.add(headerIcon).size(arrowSize).align(Align.center)
header.touchable= Touchable.enabled header.touchable= Touchable.enabled
header.onClick { toggle() } header.onClick { toggle() }
if (expanderWidth != 0f)
content.pack() defaults().minWidth(expanderWidth)
measureContent()
wrapper = Container(content).apply {
setRound(false)
bottom() // controls what is seen first on opening!
setSize(wrapperWidth, 0f)
}
defaults().growX() defaults().growX()
headerCell = add(header).minWidth(wrapperWidth) contentWrapper.defaults().growX().pad(defaultPad)
row() innerTable.defaults().growX()
wrapperCell = add(wrapper).size(wrapperWidth, 0f).pad(defaultPad) add(header).fillY().row()
add(contentWrapper)
setLayoutEnabled(true) contentWrapper.add(innerTable) // update will revert this
update(fromInit = true) initContent?.invoke(innerTable)
if (expanderWidth == 0f) {
// Measure content width incl. pad, set header to same width
if (innerTable.needsLayout()) contentWrapper.pack()
getCell(header).minWidth(contentWrapper.width)
}
update(noAnimation = true)
} }
override fun getPrefHeight() = header.prefHeight + wrapperHeight * currentPercent private fun update(noAnimation: Boolean = false) {
override fun layout() {
// Critical magic here! Key to allow dynamic content.
// However, I can't explain why an invalidated header also needs to trigger it. Without, the
// WorldScreenMusicPopup's expanders, which are width-controlled by their outer cell's fillX/expandX,
// start aligned and same width, but will slightly misalign by some 10f on opening/closing some of them.
if (content.needsLayout() || header.needsLayout())
contentHasChanged()
super.layout()
}
private fun contentHasChanged() {
val oldWidth = wrapperWidth
val oldHeight = wrapperHeight
content.pack()
measureContent()
if (wrapperWidth == oldWidth && wrapperHeight == oldHeight) return
headerCell.minWidth(wrapperWidth)
currentPercent *= oldHeight / wrapperHeight // to animate smoothly to new height, >1f should work too
update()
}
private fun measureContent() {
wrapperWidth = if (expanderWidth > 0f) expanderWidth else content.width
wrapperHeight = content.height
}
private fun update(fromInit: Boolean = false) {
if (persistenceID != null) if (persistenceID != null)
persistedStates[persistenceID] = isOpen persistedStates[persistenceID] = isOpen
if (noAnimation || !UncivGame.Current.settings.continuousRendering) {
if (noAnimation || fromInit) { contentWrapper.clear()
updateContentVisibility(if (isOpen) 1f else 0f) if (isOpen) contentWrapper.add(innerTable)
wrapper.isVisible = isOpen headerIcon.rotation = if (isOpen) 90f else 180f
if (!fromInit) onChange?.invoke() if (!noAnimation) onChange?.invoke()
return return
} }
val action = object: FloatAction ( 90f, 180f, animationDuration, Interpolation.linear) {
clearActions() override fun update(percent: Float) {
addAction(ExpandAction()) super.update(percent)
} headerIcon.rotation = this.value
if (this.isComplete) {
private fun updateContentVisibility(percent: Float) { contentWrapper.clear()
currentPercent = percent if (isOpen) contentWrapper.add(innerTable)
val height = percent * wrapperHeight onChange?.invoke()
wrapperCell.size(wrapperWidth, height) // needed for layout }
wrapper.setSize(wrapperWidth, height) // needed for clipping }
arrowIcon.rotation = 90f * (2f - percent) }.apply { isReverse = isOpen }
invalidateHierarchy() addAction(action)
} }
/** Toggle [isOpen], animated */ /** Toggle [isOpen], animated */
@ -208,38 +128,8 @@ class ExpanderTab(
isOpen = !isOpen isOpen = !isOpen
} }
/** Change header label text after initialization - **no** auto-translation! */ /** Change header label text after initialization */
fun setText(text: String) { fun setText(text: String) {
headerLabel.setText(text) headerLabel.setText(text)
} }
private inner class ExpandAction : FloatAction() {
init {
start = currentPercent // start from wherever we were if turned around midway
end = if (isOpen) 1f else 0f
// Duration: shorter if less content height...
val heightFactor = stage?.run { wrapperHeight.coerceAtMost(height) / height } ?: 0.5f
// ... and shorter if turned around midway
val distanceFactor = abs(end - currentPercent)
duration = (animationDurationForStageHeight * heightFactor)
.coerceAtLeast(0.15f) * distanceFactor
}
override fun begin() {
super.begin()
wrapper.clip(true)
wrapper.isVisible = true
}
override fun update(percent: Float) {
super.update(percent)
updateContentVisibility(value)
onChange?.invoke()
}
override fun end() {
wrapper.clip(false)
wrapper.isVisible = isOpen // allows turning clip off in closed state
}
}
} }

View File

@ -123,7 +123,7 @@ class ModCheckTab(
.apply { color = Color.BLACK } .apply { color = Color.BLACK }
.surroundWithCircle(30f, color = iconColor) .surroundWithCircle(30f, color = iconColor)
val expanderTab = ExpanderTab(mod.name, icon = icon, startsOutOpened = false, headerAlign = Align.left) { val expanderTab = ExpanderTab(mod.name, icon = icon, startsOutOpened = false) {
it.defaults().align(Align.left) it.defaults().align(Align.left)
if (!noProblem && mod.folderLocation != null) { if (!noProblem && mod.folderLocation != null) {
val replaceableUniques = getDeprecatedReplaceableUniques(mod) val replaceableUniques = getDeprecatedReplaceableUniques(mod)
@ -143,6 +143,7 @@ class ModCheckTab(
.joinToString("\n") { line -> line.text } .joinToString("\n") { line -> line.text }
}).row() }).row()
} }
expanderTab.header.left()
val loadingLabel = modCheckResultTable.children.last() val loadingLabel = modCheckResultTable.children.last()
modCheckResultTable.removeActor(loadingLabel) modCheckResultTable.removeActor(loadingLabel)

View File

@ -83,15 +83,16 @@ class CitizenManagementTable(val cityScreen: CityScreen) : Table(BaseScreen.skin
} }
fun asExpander(onChange: (() -> Unit)?): ExpanderTab { fun asExpander(onChange: (() -> Unit)?): ExpanderTab {
update()
return ExpanderTab( return ExpanderTab(
title = "{Citizen Management}", title = "{Citizen Management}",
fontSize = Constants.defaultFontSize, fontSize = Constants.defaultFontSize,
persistenceID = "CityStatsTable.CitizenManagement", persistenceID = "CityStatsTable.CitizenManagement",
startsOutOpened = false, startsOutOpened = false,
content = this,
onChange = onChange onChange = onChange
) ) {
it.add(this)
update()
}
} }
} }

View File

@ -96,7 +96,6 @@ class CityReligionInfoTable(
fun asExpander(onChange: (()->Unit)?): ExpanderTab { fun asExpander(onChange: (()->Unit)?): ExpanderTab {
val (icon, label) = getIconAndLabel(religionManager.getMajorityReligion()) val (icon, label) = getIconAndLabel(religionManager.getMajorityReligion())
defaults().center().pad(5f)
return ExpanderTab( return ExpanderTab(
title = "Majority Religion: [$label]", title = "Majority Religion: [$label]",
fontSize = Constants.defaultFontSize, fontSize = Constants.defaultFontSize,
@ -104,8 +103,10 @@ class CityReligionInfoTable(
defaultPad = 0f, defaultPad = 0f,
persistenceID = "CityStatsTable.Religion", persistenceID = "CityStatsTable.Religion",
startsOutOpened = false, startsOutOpened = false,
content = this,
onChange = onChange onChange = onChange
) ) {
defaults().center().pad(5f)
it.add(this)
}
} }
} }

View File

@ -232,6 +232,7 @@ class CityStatsTable(private val cityScreen: CityScreen): Table() {
otherBuildings.sortBy { it.name } otherBuildings.sortBy { it.name }
val totalTable = Table() val totalTable = Table()
lowerTable.addCategory("Buildings", totalTable, false)
if (specialistBuildings.isNotEmpty()) { if (specialistBuildings.isNotEmpty()) {
val specialistBuildingsTable = Table() val specialistBuildingsTable = Table()
@ -260,8 +261,6 @@ class CityStatsTable(private val cityScreen: CityScreen): Table() {
for (building in otherBuildings) addBuildingButton(building, regularBuildingsTable) for (building in otherBuildings) addBuildingButton(building, regularBuildingsTable)
totalTable.add(regularBuildingsTable).growX().right().row() totalTable.add(regularBuildingsTable).growX().right().row()
} }
lowerTable.addCategory("Buildings", totalTable, false)
} }
private fun addBuildingButton(building: Building, destinationTable: Table) { private fun addBuildingButton(building: Building, destinationTable: Table) {
@ -313,15 +312,17 @@ class CityStatsTable(private val cityScreen: CityScreen): Table() {
destinationTable.add(button).pad(1f).padBottom(2f).padTop(2f).expandX().right().row() destinationTable.add(button).pad(1f).padBottom(2f).padTop(2f).expandX().right().row()
} }
private fun Table.addCategory(category: String, showHideTable: Table, startsOpened: Boolean = true) : ExpanderTab { private fun Table.addCategory(category: String, showHideTable: Table, startsOpened: Boolean = true, innerPadding: Float = 10f) : ExpanderTab {
val expanderTab = ExpanderTab( val expanderTab = ExpanderTab(
title = category, title = category,
fontSize = Constants.defaultFontSize, fontSize = Constants.defaultFontSize,
persistenceID = "CityInfo.$category", persistenceID = "CityInfo.$category",
startsOutOpened = startsOpened, startsOutOpened = startsOpened,
content = showHideTable, defaultPad = innerPadding,
onChange = { onContentResize() } onChange = { onContentResize() }
) ) {
it.add(showHideTable).fillX().right()
}
add(expanderTab).growX().row() add(expanderTab).growX().row()
return expanderTab return expanderTab
} }

View File

@ -136,15 +136,16 @@ class SpecialistAllocationTable(private val cityScreen: CityScreen) : Table(Base
fun asExpander(onChange: (() -> Unit)?): ExpanderTab { fun asExpander(onChange: (() -> Unit)?): ExpanderTab {
update()
return ExpanderTab( return ExpanderTab(
title = "{Specialists}:", title = "{Specialists}:",
fontSize = Constants.defaultFontSize, fontSize = Constants.defaultFontSize,
persistenceID = "CityStatsTable.Specialists", persistenceID = "CityStatsTable.Specialists",
startsOutOpened = true, startsOutOpened = true,
content = this,
onChange = onChange onChange = onChange
) ) {
it.add(this)
update()
}
} }
} }

View File

@ -23,7 +23,6 @@ import com.unciv.models.ruleset.tile.ResourceSupplyList
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.components.ExpanderTab import com.unciv.ui.components.ExpanderTab
import com.unciv.ui.components.extensions.disable import com.unciv.ui.components.extensions.disable
import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onClick
import com.unciv.ui.images.IconTextButton import com.unciv.ui.images.IconTextButton
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
@ -42,11 +41,8 @@ class OffersListScroll(
) : ScrollPane(null) { ) : ScrollPane(null) {
val table = Table(BaseScreen.skin).apply { defaults().pad(5f) } val table = Table(BaseScreen.skin).apply { defaults().pad(5f) }
private data class ExpanderData(
val label: String, private val expanderTabs = HashMap<TradeType, ExpanderTab>()
val content: Table = Table().apply { defaults().pad(5f) }
)
private val expanderContents = HashMap<TradeType, ExpanderData>()
/** /**
* @param offersToDisplay The offers which should be displayed as buttons * @param offersToDisplay The offers which should be displayed as buttons
@ -59,10 +55,10 @@ class OffersListScroll(
untradableOffers: ResourceSupplyList = ResourceSupplyList.emptyList untradableOffers: ResourceSupplyList = ResourceSupplyList.emptyList
) { ) {
table.clear() table.clear()
expanderContents.clear() expanderTabs.clear()
for (offerType in values()) { for (offerType in values()) {
val labelName = when(offerType) { val labelName = when(offerType){
Gold, Gold_Per_Turn, Treaty, Agreement, Introduction -> "" Gold, Gold_Per_Turn, Treaty, Agreement, Introduction -> ""
Luxury_Resource -> "Luxury resources" Luxury_Resource -> "Luxury resources"
Strategic_Resource -> "Strategic resources" Strategic_Resource -> "Strategic resources"
@ -72,12 +68,11 @@ class OffersListScroll(
} }
val offersOfType = offersToDisplay.filter { it.type == offerType } val offersOfType = offersToDisplay.filter { it.type == offerType }
if (labelName.isNotEmpty() && offersOfType.any()) { if (labelName.isNotEmpty() && offersOfType.any()) {
expanderContents[offerType] = ExpanderData(labelName) expanderTabs[offerType] = ExpanderTab(labelName, persistenceID = "Trade.$persistenceID.$offerType") {
it.defaults().pad(5f)
}
} }
} }
val expanderWidth = (expanderContents.values.maxByOrNull { it.label.length }
?.run { label.toLabel(fontSize = Constants.headingFontSize).prefWidth }
?: 0f) + 50f // 50 for Expander header pad and arrow
for (offerType in values()) { for (offerType in values()) {
val offersOfType = offersToDisplay.filter { it.type == offerType } val offersOfType = offersToDisplay.filter { it.type == offerType }
@ -86,6 +81,11 @@ class OffersListScroll(
{ if (it.type==City) it.getOfferText() else it.name.tr() } { if (it.type==City) it.getOfferText() else it.name.tr() }
)) ))
if (expanderTabs.containsKey(offerType)) {
expanderTabs[offerType]!!.innerTable.clear()
table.add(expanderTabs[offerType]!!).row()
}
for (offer in offersOfType) { for (offer in offersOfType) {
val tradeLabel = offer.getOfferText(untradableOffers.sumBy(offer.name)) val tradeLabel = offer.getOfferText(untradableOffers.sumBy(offer.name))
val tradeIcon = when (offer.type) { val tradeIcon = when (offer.type) {
@ -122,18 +122,11 @@ class OffersListScroll(
else tradeButton.disable() // for instance we have negative gold else tradeButton.disable() // for instance we have negative gold
if (expanderContents.containsKey(offerType)) if (expanderTabs.containsKey(offerType))
expanderContents[offerType]!!.content.add(tradeButton).row() expanderTabs[offerType]!!.innerTable.add(tradeButton).row()
else else
table.add(tradeButton).row() table.add(tradeButton).row()
} }
expanderContents[offerType]?.run {
table.add(
ExpanderTab(label, expanderWidth = expanderWidth,
persistenceID = "Trade.$persistenceID.$offerType", content = content)
).row()
}
} }
actor = table actor = table
} }

View File

@ -120,11 +120,12 @@ class MapEditorViewTab(
"{Natural Wonders} (${naturalWonders.size})", "{Natural Wonders} (${naturalWonders.size})",
fontSize = 21, fontSize = 21,
startsOutOpened = false, startsOutOpened = false,
headerPad = 5f, headerPad = 5f
content = MarkupRenderer.render(lines, iconDisplay = IconDisplay.NoLink) { ) {
scrollToWonder(it) it.add(MarkupRenderer.render(lines, iconDisplay = IconDisplay.NoLink) { name->
} scrollToWonder(name)
)).row() })
}).row()
} }
// Starting locations not cached like natural wonders - storage is already compact // Starting locations not cached like natural wonders - storage is already compact
@ -135,11 +136,12 @@ class MapEditorViewTab(
"{Starting locations} (${tileMap.startingLocationsByNation.size})", "{Starting locations} (${tileMap.startingLocationsByNation.size})",
fontSize = 21, fontSize = 21,
startsOutOpened = false, startsOutOpened = false,
headerPad = 5f, headerPad = 5f
content = MarkupRenderer.render(lines.asIterable(), iconDisplay = IconDisplay.NoLink) { ) {
scrollToStartOfNation(it) it.add(MarkupRenderer.render(lines.asIterable(), iconDisplay = IconDisplay.NoLink) { name ->
} scrollToStartOfNation(name)
)).row() })
}).row()
} }
addSeparator() addSeparator()

View File

@ -244,20 +244,23 @@ class NewGameScreen(
private fun initPortrait() { private fun initPortrait() {
scrollPane.setScrollingDisabled(false,false) scrollPane.setScrollingDisabled(false,false)
topTable.add(ExpanderTab("Game Options", content = newGameOptionsTable)) topTable.add(ExpanderTab("Game Options") {
.expandX().fillX().row() it.add(newGameOptionsTable).row()
}).expandX().fillX().row()
topTable.addSeparator(Color.DARK_GRAY, height = 1f) topTable.addSeparator(Color.DARK_GRAY, height = 1f)
topTable.add(newGameOptionsTable.modCheckboxes).expandX().fillX().row() topTable.add(newGameOptionsTable.modCheckboxes).expandX().fillX().row()
topTable.addSeparator(Color.DARK_GRAY, height = 1f) topTable.addSeparator(Color.DARK_GRAY, height = 1f)
topTable.add(ExpanderTab("Map Options", content = mapOptionsTable)) topTable.add(ExpanderTab("Map Options") {
.expandX().fillX().row() it.add(mapOptionsTable).row()
}).expandX().fillX().row()
topTable.addSeparator(Color.DARK_GRAY, height = 1f) topTable.addSeparator(Color.DARK_GRAY, height = 1f)
(playerPickerTable.playerListTable.parent as ScrollPane).setScrollingDisabled(true,true) (playerPickerTable.playerListTable.parent as ScrollPane).setScrollingDisabled(true,true)
topTable.add(ExpanderTab("Civilizations", content = playerPickerTable)) topTable.add(ExpanderTab("Civilizations") {
.expandX().fillX().row() it.add(playerPickerTable).row()
}).expandX().fillX().row()
} }
private fun checkConnectionToMultiplayerServer(): Boolean { private fun checkConnectionToMultiplayerServer(): Boolean {

View File

@ -158,16 +158,21 @@ class ModManagementScreen(
topTable.add(optionsManager.expander).top().growX().row() topTable.add(optionsManager.expander).top().growX().row()
installedExpanderTab = ExpanderTab(optionsManager.getInstalledHeader(), expanderWidth = stage.width, content = scrollInstalledMods) installedExpanderTab = ExpanderTab(optionsManager.getInstalledHeader(), expanderWidth = stage.width) {
it.add(scrollInstalledMods).growX()
}
topTable.add(installedExpanderTab).top().growX().row() topTable.add(installedExpanderTab).top().growX().row()
onlineExpanderTab = ExpanderTab(optionsManager.getOnlineHeader(), expanderWidth = stage.width, content = scrollOnlineMods) onlineExpanderTab = ExpanderTab(optionsManager.getOnlineHeader(), expanderWidth = stage.width) {
it.add(scrollOnlineMods).growX()
}
topTable.add(onlineExpanderTab).top().padTop(10f).growX().row() topTable.add(onlineExpanderTab).top().padTop(10f).growX().row()
topTable.add().expandY().row() // helps with top() being ignored topTable.add().expandY().row() // helps with top() being ignored
topTable.add(ExpanderTab("Mod info and options", expanderWidth = stage.width, content = modActionTable)) topTable.add(ExpanderTab("Mod info and options", expanderWidth = stage.width) {
.bottom().padTop(10f).growX().row() it.add(modActionTable).growX()
}).bottom().padTop(10f).growX().row()
} }
private fun initLandscape() { private fun initLandscape() {

View File

@ -34,7 +34,7 @@ class WorldScreenMusicPopup(
private val musicController = UncivGame.Current.musicController private val musicController = UncivGame.Current.musicController
private val trackStyle: TextButton.TextButtonStyle private val trackStyle: TextButton.TextButtonStyle
private val historyTable = Table() private val historyExpander: ExpanderTab
private val visualMods = worldScreen.game.settings.visualMods private val visualMods = worldScreen.game.settings.visualMods
private val mods = worldScreen.gameInfo.gameParameters.mods private val mods = worldScreen.gameInfo.gameParameters.mods
@ -58,19 +58,13 @@ class WorldScreenMusicPopup(
trackStyle.disabledFontColor = Color.LIGHT_GRAY trackStyle.disabledFontColor = Color.LIGHT_GRAY
addMusicMods(settings) addMusicMods(settings)
addHistory() historyExpander = addHistory()
addMusicControls(bottomTable, settings, musicController) addMusicControls(bottomTable, settings, musicController)
addCloseButton().padTop(10f).padBottom(0f).colspan(2) addCloseButton().colspan(2)
getScrollPane()?.run {
fadeScrollBars = false
if (bottomTable.prefWidth < prefWidth)
bottomTable.width = prefWidth
}
musicController.onChange { musicController.onChange {
historyTable.clear() historyExpander.innerTable.clear()
historyTable.updateTrackList(musicController.getHistory()) historyExpander.innerTable.updateTrackList(musicController.getHistory())
} }
} }
@ -94,24 +88,24 @@ class WorldScreenMusicPopup(
} }
} }
private fun addHistory() = addTrackList("—History—", musicController.getHistory(), historyTable) private fun addHistory() = addTrackList("—History—", musicController.getHistory())
private fun addTrackList(title: String, tracks: Sequence<MusicController.MusicTrackInfo>, table: Table? = null) { private fun addTrackList(title: String, tracks: Sequence<MusicController.MusicTrackInfo>): ExpanderTab {
// Note title is either a mod name or something that cannot be a mod name (thanks to the em-dashes) // Note title is either a mod name or something that cannot be a mod name (thanks to the em-dashes)
val icon = when (title) { val icon = when (title) {
in mods -> "OtherIcons/Mods" in mods -> "OtherIcons/Mods"
in visualMods -> "UnitPromotionIcons/Scouting" in visualMods -> "UnitPromotionIcons/Scouting"
else -> null else -> null
}?.let { ImageGetter.getImage(it).apply { setSize(18f) } } }?.let { ImageGetter.getImage(it).apply { setSize(18f) } }
val content = table ?: Table()
content.defaults().growX()
content.updateTrackList(tracks)
val expander = ExpanderTab(title, Constants.defaultFontSize, icon, val expander = ExpanderTab(title, Constants.defaultFontSize, icon,
startsOutOpened = false, defaultPad = 0f, headerPad = 5f, startsOutOpened = false, defaultPad = 0f, headerPad = 5f,
persistenceID = "MusicPopup.$title", persistenceID = "MusicPopup.$title",
content = content ) {
) it.updateTrackList(tracks)
}
add(expander).colspan(2).growX().row() add(expander).colspan(2).growX().row()
return expander
} }
private fun Table.updateTrackList(tracks: Sequence<MusicController.MusicTrackInfo>) { private fun Table.updateTrackList(tracks: Sequence<MusicController.MusicTrackInfo>) {