mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-05 13:08:48 +07:00
Improve handling of Religion PickerScreen (#6287)
* Improve handling of Religion PickerScreen with long lists * Fix mouseover graying Labels bug
This commit is contained in:
parent
12428835b3
commit
e97c95b7aa
@ -1,7 +1,9 @@
|
||||
package com.unciv.ui.pickerscreens
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
@ -18,59 +20,73 @@ import com.unciv.ui.utils.*
|
||||
class ReligiousBeliefsPickerScreen (
|
||||
private val choosingCiv: CivilizationInfo,
|
||||
private val gameInfo: GameInfo,
|
||||
private val beliefsToChoose: Counter<BeliefType>,
|
||||
newBeliefsToChoose: Counter<BeliefType>,
|
||||
private val pickIconAndName: Boolean
|
||||
): PickerScreen(disableScroll = true) {
|
||||
|
||||
// Roughly follows the layout of the original (although I am not very good at UI designing, so please improve this)
|
||||
|
||||
private val topReligionIcons = Table() // Top of the layout, contains icons for religions
|
||||
private val leftChosenBeliefs = Table() // Left middle part, contains buttons to select the types of beliefs to choose
|
||||
private val leftScrollPane = AutoScrollPane(leftChosenBeliefs)
|
||||
private val rightBeliefsToChoose = Table() // Right middle part, contains the beliefs to choose
|
||||
|
||||
private val rightScrollPane = AutoScrollPane(rightBeliefsToChoose)
|
||||
|
||||
private val middlePanes = Table()
|
||||
|
||||
|
||||
private var previouslySelectedIcon: Button? = null
|
||||
private var displayName: String? = null
|
||||
private var religionName: String? = null
|
||||
|
||||
private val chosenBeliefs: Array<Belief?> = Array(beliefsToChoose.values.sum()) { null }
|
||||
|
||||
// One entry per new Belief to choose - the left side will offer these below the choices from earlier in the game
|
||||
class BeliefToChoose(val type: BeliefType, var belief: Belief? = null)
|
||||
private val beliefsToChoose: Array<BeliefToChoose> =
|
||||
newBeliefsToChoose.flatMap { entry -> (0 until entry.value).map { BeliefToChoose(entry.key) } }.toTypedArray()
|
||||
|
||||
private var leftSelectedButton: Button? = null
|
||||
private var leftSelectedIndex = -1
|
||||
private var rightSelectedButton: Button? = null
|
||||
|
||||
init {
|
||||
leftChosenBeliefs.defaults().right().pad(10f).fillX()
|
||||
rightBeliefsToChoose.defaults().left().pad(10f).fillX()
|
||||
|
||||
closeButton.isVisible = true
|
||||
setDefaultCloseAction()
|
||||
|
||||
|
||||
if (pickIconAndName) setupChoosableReligionIcons()
|
||||
else setupVisibleReligionIcons()
|
||||
|
||||
|
||||
updateLeftTable()
|
||||
|
||||
middlePanes.add(ScrollPane(leftChosenBeliefs))
|
||||
|
||||
middlePanes.add(leftScrollPane)
|
||||
middlePanes.addSeparatorVertical()
|
||||
middlePanes.add(ScrollPane(rightBeliefsToChoose))
|
||||
|
||||
topTable.add(topReligionIcons).row()
|
||||
middlePanes.add(rightScrollPane)
|
||||
|
||||
topTable.add(topReligionIcons).minHeight(topReligionIcons.prefHeight).row()
|
||||
topTable.addSeparator()
|
||||
topTable.add(middlePanes)
|
||||
|
||||
if (pickIconAndName) rightSideButton.label = "Choose a Religion".toLabel()
|
||||
else rightSideButton.label = "Enhance [${choosingCiv.religionManager.religion!!.getReligionDisplayName()}]".toLabel()
|
||||
|
||||
val rightSideButtonText = if (pickIconAndName)
|
||||
"Choose a Religion"
|
||||
else "Enhance [${choosingCiv.religionManager.religion!!.getReligionDisplayName()}]"
|
||||
// This forces this label to use an own clone of the default style. If not, hovering over the button
|
||||
// will gray out all the default-styled Labels on the screen - exact cause and why this does not affect other buttons unknown
|
||||
rightSideButton.label = Label(rightSideButtonText.tr(), LabelStyle(skin[LabelStyle::class.java]))
|
||||
|
||||
rightSideButton.onClick(UncivSound.Choir) {
|
||||
choosingCiv.religionManager.chooseBeliefs(displayName, religionName, chosenBeliefs.map { it!! })
|
||||
choosingCiv.religionManager.chooseBeliefs(displayName, religionName, beliefsToChoose.map { it.belief!! })
|
||||
UncivGame.Current.setWorldScreen()
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkAndEnableRightSideButton() {
|
||||
if (pickIconAndName && (religionName == null || displayName == null)) return
|
||||
if (chosenBeliefs.any { it == null }) return
|
||||
if (beliefsToChoose.any { it.belief == null }) return
|
||||
rightSideButton.enable()
|
||||
}
|
||||
|
||||
|
||||
private fun setupChoosableReligionIcons() {
|
||||
topReligionIcons.clear()
|
||||
|
||||
// This should later be replaced with a user-modifiable text field, but not in this PR
|
||||
// Note that this would require replacing 'religion.name' with 'religion.iconName' at many spots
|
||||
val descriptionLabel = "Choose an Icon and name for your Religion".toLabel()
|
||||
|
||||
fun changeDisplayedReligionName(newReligionName: String) {
|
||||
@ -83,38 +99,26 @@ class ReligiousBeliefsPickerScreen (
|
||||
ImageGetter.getImage("OtherIcons/Pencil").apply { this.color = Color.BLACK }.surroundWithCircle(30f),
|
||||
skin
|
||||
)
|
||||
|
||||
val iconsTable = Table()
|
||||
iconsTable.align(Align.center)
|
||||
for (religionName in gameInfo.ruleSet.religions) {
|
||||
val button = Button(
|
||||
ImageGetter.getCircledReligionIcon(religionName, 60f),
|
||||
skin
|
||||
)
|
||||
|
||||
addIconsScroll { button, religionName ->
|
||||
button.onClick {
|
||||
if (previouslySelectedIcon != null) {
|
||||
previouslySelectedIcon!!.enable()
|
||||
}
|
||||
previouslySelectedIcon?.enable()
|
||||
previouslySelectedIcon = button
|
||||
button.disable()
|
||||
|
||||
|
||||
changeDisplayedReligionName(religionName)
|
||||
this.religionName = religionName
|
||||
changeReligionNameButton.enable()
|
||||
|
||||
|
||||
checkAndEnableRightSideButton()
|
||||
}
|
||||
if (religionName == this.religionName || gameInfo.religions.keys.any { it == religionName }) button.disable()
|
||||
iconsTable.add(button).pad(5f)
|
||||
}
|
||||
iconsTable.row()
|
||||
topReligionIcons.add(iconsTable).pad(5f).row()
|
||||
|
||||
val labelTable = Table()
|
||||
labelTable.add(descriptionLabel).pad(5f)
|
||||
labelTable.add(changeReligionNameButton).pad(5f).row()
|
||||
topReligionIcons.add(labelTable).center().pad(5f).row()
|
||||
|
||||
|
||||
|
||||
changeReligionNameButton.onClick {
|
||||
AskTextPopup(
|
||||
this,
|
||||
@ -134,108 +138,154 @@ class ReligiousBeliefsPickerScreen (
|
||||
|
||||
private fun setupVisibleReligionIcons() {
|
||||
topReligionIcons.clear()
|
||||
religionName = choosingCiv.religionManager.religion!!.name
|
||||
val descriptionLabel = choosingCiv.religionManager.religion!!.getReligionDisplayName().toLabel()
|
||||
|
||||
val iconsTable = Table()
|
||||
|
||||
for (religionName in gameInfo.ruleSet.religions) {
|
||||
val button = Button(
|
||||
ImageGetter.getCircledReligionIcon(religionName, 60f),
|
||||
skin
|
||||
)
|
||||
addIconsScroll { button, _ ->
|
||||
button.disable()
|
||||
iconsTable.add(button).pad(5f)
|
||||
}
|
||||
topReligionIcons.add(iconsTable).padBottom(10f).row()
|
||||
topReligionIcons.add(descriptionLabel).center().padBottom(5f)
|
||||
topReligionIcons.add(descriptionLabel).center().padBottom(15f)
|
||||
}
|
||||
|
||||
private fun addIconsScroll(buttonSetup: (Button, String)->Unit) {
|
||||
var scrollTo = 0f
|
||||
val iconsTable = Table()
|
||||
iconsTable.align(Align.center)
|
||||
|
||||
for (religionName in gameInfo.ruleSet.religions) {
|
||||
if (religionName == this.religionName)
|
||||
scrollTo = iconsTable.packIfNeeded().prefWidth
|
||||
val button = Button(ImageGetter.getCircledReligionIcon(religionName, 60f), skin)
|
||||
buttonSetup(button, religionName)
|
||||
if (religionName == this.religionName) button.disable(Color(0x007f00ff))
|
||||
else if (gameInfo.religions.keys.any { it == religionName }) button.disable(Color(0x7f0000ff))
|
||||
iconsTable.add(button).pad(5f)
|
||||
}
|
||||
iconsTable.row()
|
||||
|
||||
AutoScrollPane(iconsTable, skin).apply {
|
||||
setScrollingDisabled(false, true)
|
||||
setupFadeScrollBars(0f, 0f) // only way to "remove" scrollbar
|
||||
setScrollbarsOnTop(true) // don't waste space on scrollbar
|
||||
topReligionIcons.add(this).padBottom(10f).row()
|
||||
layout()
|
||||
scrollX = scrollTo - (width - 70f) / 2 // 70 = button width incl pad
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateLeftTable() {
|
||||
leftChosenBeliefs.clear()
|
||||
leftSelectedButton = null
|
||||
val currentReligion = choosingCiv.religionManager.religion ?: Religion("None", gameInfo, choosingCiv.civName)
|
||||
|
||||
|
||||
for (belief in currentReligion.getAllBeliefsOrdered()) {
|
||||
val beliefButton = convertBeliefToButton(belief)
|
||||
leftChosenBeliefs.add(beliefButton).pad(10f).row()
|
||||
beliefButton.disable()
|
||||
val beliefButton = getBeliefButton(belief)
|
||||
leftChosenBeliefs.add(beliefButton).row()
|
||||
beliefButton.disable(Color.GREEN)
|
||||
}
|
||||
|
||||
for (newBelief in chosenBeliefs.withIndex()) {
|
||||
addChoosableBeliefButton(newBelief, getBeliefTypeFromIndex(newBelief.index))
|
||||
|
||||
for ((index, entry) in beliefsToChoose.withIndex()) {
|
||||
addChoosableBeliefButton(entry.belief, entry.type, index)
|
||||
}
|
||||
|
||||
|
||||
equalizeAllButtons(leftChosenBeliefs)
|
||||
}
|
||||
|
||||
|
||||
private fun loadRightTable(beliefType: BeliefType, leftButtonIndex: Int) {
|
||||
var selectedButtonY = 0f
|
||||
var selectedButtonHeight = 0f
|
||||
rightBeliefsToChoose.clear()
|
||||
rightSelectedButton = null
|
||||
val availableBeliefs = gameInfo.ruleSet.beliefs.values
|
||||
.filter {
|
||||
(it.type == beliefType || beliefType == BeliefType.Any)
|
||||
&& gameInfo.religions.values.none {
|
||||
religion -> religion.hasBelief(it.name)
|
||||
}
|
||||
&& (it !in chosenBeliefs)
|
||||
}
|
||||
.filter { (it.type == beliefType || beliefType == BeliefType.Any) }
|
||||
for (belief in availableBeliefs) {
|
||||
val beliefButton = convertBeliefToButton(belief)
|
||||
val beliefButton = getBeliefButton(belief)
|
||||
beliefButton.onClick {
|
||||
chosenBeliefs[leftButtonIndex] = belief
|
||||
rightSelectedButton?.enable()
|
||||
rightSelectedButton = beliefButton
|
||||
beliefButton.disable()
|
||||
beliefsToChoose[leftButtonIndex].belief = belief
|
||||
updateLeftTable()
|
||||
checkAndEnableRightSideButton()
|
||||
}
|
||||
rightBeliefsToChoose.add(beliefButton).left().pad(10f).row()
|
||||
when {
|
||||
beliefsToChoose[leftButtonIndex].belief == belief -> {
|
||||
selectedButtonY = rightBeliefsToChoose.packIfNeeded().prefHeight
|
||||
selectedButtonHeight = beliefButton.packIfNeeded().prefHeight + 20f
|
||||
rightSelectedButton = beliefButton
|
||||
beliefButton.disable()
|
||||
}
|
||||
beliefsToChoose.any { it.belief == belief } ||
|
||||
choosingCiv.religionManager.religion!!.hasBelief(belief.name) -> {
|
||||
// The Belief button should be disabled because you already have it selected
|
||||
beliefButton.disable(Color(0x007f00ff))
|
||||
}
|
||||
gameInfo.religions.values.any { it.hasBelief(belief.name) } -> {
|
||||
// The Belief is not available because someone already has it
|
||||
beliefButton.disable(Color(0x7f0000ff))
|
||||
}
|
||||
}
|
||||
rightBeliefsToChoose.add(beliefButton).row()
|
||||
}
|
||||
equalizeAllButtons(rightBeliefsToChoose)
|
||||
}
|
||||
|
||||
private fun equalizeAllButtons(table: Table) {
|
||||
val minWidth = table.cells
|
||||
.filter { it.actor is Button }
|
||||
.maxOfOrNull { it.actor.width }
|
||||
?: return
|
||||
|
||||
for (button in table.cells) {
|
||||
if (button.actor is Button)
|
||||
button.minWidth(minWidth)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addChoosableBeliefButton(belief: IndexedValue<Belief?>, beliefType: BeliefType) {
|
||||
val newBeliefButton =
|
||||
if (belief.value == null) emptyBeliefButton(beliefType)
|
||||
else convertBeliefToButton(belief.value!!)
|
||||
|
||||
leftChosenBeliefs.add(newBeliefButton).pad(10f).row()
|
||||
if (rightSelectedButton == null) return
|
||||
rightScrollPane.layout()
|
||||
rightScrollPane.scrollY = selectedButtonY - (rightScrollPane.height - selectedButtonHeight) / 2
|
||||
}
|
||||
|
||||
private fun equalizeAllButtons(table: Table) {
|
||||
val minWidth = table.cells.maxOfOrNull { it.prefWidth }
|
||||
?: return
|
||||
|
||||
for (buttonCell in table.cells) {
|
||||
if (buttonCell.actor is Button)
|
||||
buttonCell.minWidth(minWidth)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addChoosableBeliefButton(belief: Belief?, beliefType: BeliefType, index: Int) {
|
||||
val newBeliefButton = getBeliefButton(belief, beliefType)
|
||||
|
||||
if (index == leftSelectedIndex) {
|
||||
newBeliefButton.disable()
|
||||
leftSelectedButton = newBeliefButton
|
||||
leftScrollPane.scrollY = leftChosenBeliefs.packIfNeeded().prefHeight -
|
||||
(leftScrollPane.height - (newBeliefButton.prefHeight + 20f)) / 2
|
||||
leftScrollPane.updateVisualScroll()
|
||||
}
|
||||
leftChosenBeliefs.add(newBeliefButton).row()
|
||||
|
||||
newBeliefButton.onClick {
|
||||
loadRightTable(beliefType, belief.index)
|
||||
leftSelectedButton?.enable()
|
||||
leftSelectedButton = newBeliefButton
|
||||
leftSelectedIndex = index
|
||||
newBeliefButton.disable()
|
||||
loadRightTable(beliefType, index)
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertBeliefToButton(belief: Belief): Button {
|
||||
val contentsTable = Table()
|
||||
contentsTable.add(belief.type.name.toLabel(fontColor = Color.valueOf(belief.type.color))).row()
|
||||
contentsTable.add(belief.name.toLabel(fontSize = Constants.headingFontSize)).row()
|
||||
contentsTable.add(belief.uniques.joinToString("\n") { it.tr() }.toLabel())
|
||||
return Button(contentsTable, skin)
|
||||
}
|
||||
|
||||
private fun emptyBeliefButton(beliefType: BeliefType): Button {
|
||||
val contentsTable = Table()
|
||||
if (beliefType != BeliefType.Any)
|
||||
contentsTable.add("Choose a [${beliefType.name}] belief!".toLabel())
|
||||
else
|
||||
contentsTable.add("Choose any belief!".toLabel())
|
||||
return Button(contentsTable, skin)
|
||||
}
|
||||
|
||||
private fun getBeliefTypeFromIndex(index: Int): BeliefType {
|
||||
return when {
|
||||
index < beliefsToChoose.filter { it.key <= BeliefType.Pantheon }.values.sum() -> BeliefType.Pantheon
|
||||
index < beliefsToChoose.filter { it.key <= BeliefType.Founder }.values.sum() -> BeliefType.Founder
|
||||
index < beliefsToChoose.filter { it.key <= BeliefType.Follower }.values.sum() -> BeliefType.Follower
|
||||
index < beliefsToChoose.filter { it.key <= BeliefType.Enhancer }.values.sum() -> BeliefType.Enhancer
|
||||
else -> BeliefType.Any
|
||||
|
||||
private fun getBeliefButton(belief: Belief? = null, beliefType: BeliefType? = null): Button {
|
||||
val labelWidth = stage.width * 0.5f - 52f // 32f empirically measured padding inside button, 20f outside padding
|
||||
return Button(skin).apply {
|
||||
when {
|
||||
belief != null -> {
|
||||
add(belief.type.name.toLabel(fontColor = Color.valueOf(belief.type.color))).row()
|
||||
val nameLabel = WrappableLabel(belief.name, labelWidth, fontSize = Constants.headingFontSize)
|
||||
add(nameLabel.apply { wrap = true }).row()
|
||||
val effectLabel = WrappableLabel(belief.uniques.joinToString("\n") { it.tr() }, labelWidth)
|
||||
add(effectLabel.apply { wrap = true })
|
||||
}
|
||||
beliefType == BeliefType.Any ->
|
||||
add("Choose any belief!".toLabel())
|
||||
beliefType != null ->
|
||||
add("Choose a [${beliefType.name}] belief!".toLabel())
|
||||
else -> throw(IllegalArgumentException("getBeliefButton must have one non-null parameter"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Button.disable(color: Color) {
|
||||
touchable = Touchable.disabled
|
||||
this.color = color
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user