Change EmpireOverviewScreen closing to use the same button and UX as Civilopedia (#11169)

* Centralize a "round X" close button factory with global scope

* Change EmpireOverviewScreen closing to use the same button and UX as Civilopedia
This commit is contained in:
SomeTroglodyte 2024-02-22 16:33:26 +01:00 committed by GitHub
parent 3047c1abad
commit 382d966696
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 75 additions and 42 deletions

View File

@ -31,6 +31,9 @@ import com.unciv.ui.components.extensions.GdxKeyCodeFixes.DEL
import com.unciv.ui.components.extensions.GdxKeyCodeFixes.toString import com.unciv.ui.components.extensions.GdxKeyCodeFixes.toString
import com.unciv.ui.components.extensions.GdxKeyCodeFixes.valueOf import com.unciv.ui.components.extensions.GdxKeyCodeFixes.valueOf
import com.unciv.ui.components.fonts.Fonts 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
import com.unciv.ui.components.input.onChange import com.unciv.ui.components.input.onChange
import com.unciv.ui.images.IconCircleGroup import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
@ -253,6 +256,24 @@ fun String.toImageButton(iconSize: Float, circleSize: Float, circleColor: Color,
return button.surroundWithCircle( circleSize, false, circleColor) return button.surroundWithCircle( circleSize, false, circleColor)
} }
/** Return a "close" button, visually a circle with "x" icon that goes red on mouse-over.
*
* For use e.g. in the top-right corner of screens such as CivilopediaScreen.
* Automatically binds the BACK key to the [action].
*/
fun getCloseButton(
size: Float,
iconSize: Float = size - 20f,
circleColor: Color = BaseScreen.skinStrings.skinConfig.baseColor,
overColor: Color = Color.RED,
action: () -> Unit
): Group {
val closeButton = "OtherIcons/Close".toImageButton(iconSize, size, circleColor, overColor)
closeButton.onActivation(action)
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
return closeButton
}
/** Translate a [String] and make a [Label] widget from it */ /** Translate a [String] and make a [Label] widget from it */
fun String.toLabel() = Label(this.tr(), BaseScreen.skin) fun String.toLabel() = Label(this.tr(), BaseScreen.skin)
/** Make a [Label] widget containing this [Int] as text */ /** Make a [Label] widget containing this [Int] as text */

View File

@ -86,6 +86,7 @@ open class TabbedPager(
private val header = Table(BaseScreen.skin) private val header = Table(BaseScreen.skin)
val headerScroll = LinkedScrollPane(horizontalOnly = true, header) val headerScroll = LinkedScrollPane(horizontalOnly = true, header)
protected var headerHeight = 0f protected var headerHeight = 0f
private val headerDecorationRightCell: Cell<Actor?>
private val fixedContentScroll = LinkedScrollPane(horizontalOnly = true) private val fixedContentScroll = LinkedScrollPane(horizontalOnly = true)
private val fixedContentScrollCell: Cell<ScrollPane> private val fixedContentScrollCell: Cell<ScrollPane>
@ -309,7 +310,9 @@ open class TabbedPager(
header.defaults().pad(headerPadding, headerPadding * 0.5f) header.defaults().pad(headerPadding, headerPadding * 0.5f)
// Measure header height, most likely its final value // Measure header height, most likely its final value
removePage(addPage("Dummy")) removePage(addPage("Dummy"))
add(headerScroll).growX().minHeight(headerHeight).row() add(headerScroll).growX().minHeight(headerHeight)
headerDecorationRightCell = add().pad(0f)
row()
if (separatorColor != Color.CLEAR) if (separatorColor != Color.CLEAR)
addSeparator(separatorColor) addSeparator(separatorColor)
@ -622,6 +625,37 @@ open class TabbedPager(
}).open(true) }).open(true)
} }
/** Gets total width of the header buttons including their padding.
* Header will be scrollable if getHeaderPrefWidth > width. */
fun getHeaderPrefWidth() = header.prefWidth
/** Adds any Actor to the header, e.g. informative labels.
* Must be called _after_ all pages are final, otherwise effects not guaranteed.
*
* Notes:
* * Using [fixed] will make the widths of content and header Scrollpanes different. Synchronized scrolling will look off.
* * [fixed] decorations have predefined cells, thus decorateHeader will replace any previous decoration. Non-[fixed] are cumulative and cannot be removed.
* * [leftSide] and [fixed] both true is not implemented.
*
* @param leftSide If `true` then [actor] is inserted on the left, otherwise on the right of the page buttons.
* @param fixed If `true` [actor] is outside the header ScrollPane and thus always shown.
*/
fun decorateHeader(actor: Actor, leftSide: Boolean, fixed: Boolean = false) {
if (fixed) headerDecorationRightCell.pad(headerPadding).setActor(actor)
else insertHeaderCellAt(if (leftSide) 0 else -1).setActor(actor)
invalidate()
if (!leftSide || fixed) return
val addWidth = actor.width
for (page in pages) {
page.buttonX += addWidth
}
}
/** Alternative selection handler to [IPageExtensions.activated] */
fun onSelection(action: ((index: Int, caption: String, pager: TabbedPager) -> Unit)?) {
onSelectionCallback = action
}
//endregion //endregion
//region Helper routines //region Helper routines
@ -682,26 +716,6 @@ open class TabbedPager(
} }
} }
/** Gets total width of the header buttons including their padding. //endregion
* Header will be scrollable if getHeaderPrefWidth > width. */
fun getHeaderPrefWidth() = header.prefWidth
/** Adds any Actor to the header, e.g. informative labels.
* Must be called _after_ all pages are final, otherwise effects not guaranteed.
* @param leftSide If `true` then [actor] is inserted on the left, otherwise on the right of the page buttons.
*/
fun decorateHeader(actor: Actor, leftSide: Boolean) {
val cell = insertHeaderCellAt(if (leftSide) 0 else -1)
cell.setActor(actor)
if (!leftSide) return
val addWidth = actor.width
for (page in pages) {
page.buttonX += addWidth
}
}
/** Alternative selection handler to [IPageExtensions.activated] */
fun onSelection(action: ((index: Int, caption: String, pager: TabbedPager) -> Unit)?) {
onSelectionCallback = action
}
} }

View File

@ -15,12 +15,11 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.INamed import com.unciv.models.stats.INamed
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.components.extensions.getCloseButton
import com.unciv.ui.components.extensions.toImageButton import com.unciv.ui.components.extensions.toImageButton
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.fonts.Fonts import com.unciv.ui.components.fonts.Fonts
import com.unciv.ui.components.input.KeyCharAndCode
import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.ui.components.input.keyShortcuts
import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onActivation
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
@ -248,9 +247,7 @@ class CivilopediaScreen(
val searchButton = "OtherIcons/Search".toImageButton(imageSize - 16f, imageSize, skinStrings.skinConfig.baseColor, Color.GOLD) val searchButton = "OtherIcons/Search".toImageButton(imageSize - 16f, imageSize, skinStrings.skinConfig.baseColor, Color.GOLD)
searchButton.onActivation(binding = KeyboardBinding.PediaSearch) { searchPopup.open(true) } searchButton.onActivation(binding = KeyboardBinding.PediaSearch) { searchPopup.open(true) }
val closeButton = "OtherIcons/Close".toImageButton(imageSize - 20f, imageSize, skinStrings.skinConfig.baseColor, Color.RED) val closeButton = getCloseButton(imageSize) { game.popScreen() }
closeButton.onActivation { game.popScreen() }
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
val topTable = Table() val topTable = Table()
topTable.add(buttonTableScroll).growX() topTable.add(buttonTableScroll).growX()

View File

@ -17,14 +17,12 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicMood
import com.unciv.ui.audio.MusicTrackChooserFlags import com.unciv.ui.audio.MusicTrackChooserFlags
import com.unciv.ui.components.extensions.getCloseButton
import com.unciv.ui.components.extensions.pad import com.unciv.ui.components.extensions.pad
import com.unciv.ui.components.extensions.toCheckBox import com.unciv.ui.components.extensions.toCheckBox
import com.unciv.ui.components.extensions.toImageButton import com.unciv.ui.components.extensions.toImageButton
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.components.extensions.toTextButton
import com.unciv.ui.components.input.KeyCharAndCode
import com.unciv.ui.components.input.keyShortcuts
import com.unciv.ui.components.input.onActivation
import com.unciv.ui.components.input.onChange import com.unciv.ui.components.input.onChange
import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onClick
import com.unciv.ui.components.widgets.AutoScrollPane import com.unciv.ui.components.widgets.AutoScrollPane
@ -539,9 +537,7 @@ private class RandomNationPickerPopup(
update() update()
pack() pack()
val closeButton = "OtherIcons/Close".toImageButton(Color.FIREBRICK) val closeButton = getCloseButton(buttonsCircleSize, buttonsIconSize, buttonsBackColor, Color.FIREBRICK) { close() }
closeButton.onActivation { close() }
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft) closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft)
innerTable.addActor(closeButton) innerTable.addActor(closeButton)
clickBehindToClose = true clickBehindToClose = true

View File

@ -17,8 +17,8 @@ import com.unciv.models.ruleset.nation.Nation
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.audio.MusicMood import com.unciv.ui.audio.MusicMood
import com.unciv.ui.audio.MusicTrackChooserFlags import com.unciv.ui.audio.MusicTrackChooserFlags
import com.unciv.ui.components.widgets.AutoScrollPane
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
import com.unciv.ui.components.extensions.getCloseButton
import com.unciv.ui.components.extensions.isNarrowerThan4to3 import com.unciv.ui.components.extensions.isNarrowerThan4to3
import com.unciv.ui.components.extensions.toImageButton import com.unciv.ui.components.extensions.toImageButton
import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyCharAndCode
@ -26,6 +26,7 @@ import com.unciv.ui.components.input.keyShortcuts
import com.unciv.ui.components.input.onActivation import com.unciv.ui.components.input.onActivation
import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onClick
import com.unciv.ui.components.input.onDoubleClick import com.unciv.ui.components.input.onDoubleClick
import com.unciv.ui.components.widgets.AutoScrollPane
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.images.Portrait import com.unciv.ui.images.Portrait
import com.unciv.ui.popups.Popup import com.unciv.ui.popups.Popup
@ -116,9 +117,7 @@ internal class NationPickerPopup(
private fun addActionIcons() { private fun addActionIcons() {
// Despite being a Popup we use our own buttons - floating circular ones // Despite being a Popup we use our own buttons - floating circular ones
val closeButton = "OtherIcons/Close".toImageButton(Color.FIREBRICK) val closeButton = getCloseButton(buttonsCircleSize, buttonsIconSize, buttonsBackColor, Color.FIREBRICK) { close() }
closeButton.onActivation { close() }
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft) closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft)
innerTable.addActor(closeButton) innerTable.addActor(closeButton)

View File

@ -5,6 +5,7 @@ import com.unciv.Constants
import com.unciv.GUI import com.unciv.GUI
import com.unciv.logic.civilization.Civilization import com.unciv.logic.civilization.Civilization
import com.unciv.logic.civilization.Notification import com.unciv.logic.civilization.Notification
import com.unciv.ui.components.extensions.getCloseButton
import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyCharAndCode
import com.unciv.ui.components.widgets.TabbedPager import com.unciv.ui.components.widgets.TabbedPager
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
@ -52,8 +53,6 @@ class EmpireOverviewScreen(
separatorColor = Color.WHITE, separatorColor = Color.WHITE,
capacity = EmpireOverviewCategories.values().size) capacity = EmpireOverviewCategories.values().size)
tabbedPager.addClosePage { game.popScreen() }
for (category in EmpireOverviewCategories.values()) { for (category in EmpireOverviewCategories.values()) {
val tabState = category.testState(viewingPlayer) val tabState = category.testState(viewingPlayer)
if (tabState == EmpireOverviewTabState.Hidden) continue if (tabState == EmpireOverviewTabState.Hidden) continue
@ -75,8 +74,14 @@ class EmpireOverviewScreen(
} }
} }
val closeButton = getCloseButton(50f) { game.popScreen() }
tabbedPager.decorateHeader(closeButton, leftSide = false, fixed = true)
tabbedPager.setFillParent(true) tabbedPager.setFillParent(true)
stage.addActor(tabbedPager) stage.addActor(tabbedPager)
// closeButton.setPosition(stage.width - 10f, stage.height - 10f, Align.topRight)
// stage.addActor(closeButton)
} }
override fun recreate(): BaseScreen { override fun recreate(): BaseScreen {

View File

@ -14,9 +14,10 @@ import com.unciv.models.translations.tr
import com.unciv.ui.components.extensions.addSeparator import com.unciv.ui.components.extensions.addSeparator
import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.center
import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.darken
import com.unciv.ui.components.extensions.getCloseButton
import com.unciv.ui.components.extensions.isShiftKeyPressed import com.unciv.ui.components.extensions.isShiftKeyPressed
import com.unciv.ui.components.extensions.toImageButton
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.input.keyShortcuts
import com.unciv.ui.components.input.onClick import com.unciv.ui.components.input.onClick
import com.unciv.ui.components.widgets.UnitGroup import com.unciv.ui.components.widgets.UnitGroup
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
@ -83,12 +84,12 @@ class UnitTable(val worldScreen: WorldScreen) : Table() {
promotionsTable.touchable = Touchable.enabled promotionsTable.touchable = Touchable.enabled
val deselectUnitButton = "OtherIcons/Close".toImageButton(20f, 50f, Color.CLEAR, Color.RED) val deselectUnitButton = getCloseButton(50f, 20f, Color.CLEAR, Color.RED) {
deselectUnitButton.onClick {
selectUnit() selectUnit()
worldScreen.shouldUpdate = true worldScreen.shouldUpdate = true
this@UnitTable.isVisible = false this@UnitTable.isVisible = false
} }
deselectUnitButton.keyShortcuts.clear() // This is the only place we don't want the BACK keyshortcut getCloseButton assigns
add(deselectUnitButton).left() add(deselectUnitButton).left()
add(Table().apply { add(Table().apply {