mirror of
https://github.com/yairm210/Unciv.git
synced 2025-03-03 22:22:51 +07:00
Allow closing a Popup by clicking outside its area (#9306)
* Allow closing a Popup by clicking outside its area * Allow closing a Popup by clicking outside its area - upd1
This commit is contained in:
parent
817764ec38
commit
43b044740c
@ -621,6 +621,8 @@ open class TabbedPager(
|
||||
addOKButton {
|
||||
if (passEntry.text.hashCode() == secretHashCode) unlockAction() else lockAction()
|
||||
}
|
||||
clickBehindToClose = true
|
||||
onCloseCallback = lockAction
|
||||
this.keyboardFocus = passEntry
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.unciv.ui.popups
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.math.Rectangle
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import com.badlogic.gdx.scenes.scene2d.Stage
|
||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Button
|
||||
@ -12,6 +13,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextField
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.Constants
|
||||
import com.unciv.logic.event.EventBus
|
||||
@ -42,12 +44,23 @@ open class Popup(
|
||||
|
||||
// This exists to differentiate the actual popup (the inner table)
|
||||
// from the 'screen blocking' part of the popup (which covers the entire screen)
|
||||
val innerTable = Table(BaseScreen.skin)
|
||||
protected val innerTable = Table(BaseScreen.skin)
|
||||
|
||||
/** Callbacks that will be called whenever this Popup is shown */
|
||||
val showListeners = mutableListOf<() -> Unit>()
|
||||
/** Callbacks that will be called whenever this Popup is closed, no matter how (e.g. no distinction OK/Cancel) */
|
||||
val closeListeners = mutableListOf<() -> Unit>()
|
||||
|
||||
val events = EventBus.EventReceiver()
|
||||
protected val events = EventBus.EventReceiver()
|
||||
|
||||
/** Enables/disables closing by clicking/trapping outside [innerTable].
|
||||
*
|
||||
* Automatically set when [addCloseButton] is called but may be changed back or enabled without such a button.
|
||||
*/
|
||||
protected var clickBehindToClose = false
|
||||
|
||||
/** Unlike [closeListeners] this is only fired on "click-behind" closing */
|
||||
protected var onCloseCallback: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
// Set actor name for debugging
|
||||
@ -55,7 +68,7 @@ open class Popup(
|
||||
|
||||
background = BaseScreen.skinStrings.getUiBackground(
|
||||
"General/Popup/Background",
|
||||
tintColor = Color.GRAY.cpy().apply { a=.5f })
|
||||
tintColor = Color.GRAY.cpy().apply { a = 0.5f })
|
||||
innerTable.background = BaseScreen.skinStrings.getUiBackground(
|
||||
"General/Popup/InnerTable",
|
||||
tintColor = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f)
|
||||
@ -66,9 +79,11 @@ open class Popup(
|
||||
|
||||
super.add(if (scrollable) AutoScrollPane(innerTable, BaseScreen.skin) else innerTable)
|
||||
|
||||
this.isVisible = false
|
||||
touchable = Touchable.enabled // don't allow clicking behind
|
||||
this.setFillParent(true)
|
||||
isVisible = false
|
||||
touchable = Touchable.enabled
|
||||
// clicking behind gets special treatment
|
||||
super.addListener(getBehindClickListener())
|
||||
super.setFillParent(true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,11 +129,28 @@ open class Popup(
|
||||
if (nextPopup != null) (nextPopup as Popup).show()
|
||||
}
|
||||
|
||||
/** Allow closing a popup by clicking 'outside', Android-style, but only if a Close button exists */
|
||||
private fun getBehindClickListener() = object : ClickListener() {
|
||||
override fun clicked(event: InputEvent?, x: Float, y: Float) {
|
||||
if (!clickBehindToClose) return
|
||||
// Since Gdx doesn't limit events to the actually `hit` actors...
|
||||
if (event?.target != this@Popup) return
|
||||
close()
|
||||
onCloseCallback?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
/* All additions to the popup are to the inner table - we shouldn't care that there's an inner table at all */
|
||||
final override fun <T : Actor?> add(actor: T): Cell<T> = innerTable.add(actor)
|
||||
override fun row(): Cell<Actor> = innerTable.row()
|
||||
override fun defaults(): Cell<Actor> = innerTable.defaults()
|
||||
fun addSeparator() = innerTable.addSeparator()
|
||||
override fun clear() {
|
||||
innerTable.clear()
|
||||
clickBehindToClose = false
|
||||
onCloseCallback = null
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a [caption][text] label: A label with word wrap enabled over half the stage width.
|
||||
@ -126,7 +158,7 @@ open class Popup(
|
||||
* @param text The caption text.
|
||||
* @param size The font size for the label.
|
||||
*/
|
||||
fun addGoodSizedLabel(text: String, size:Int=Constants.defaultFontSize): Cell<Label> {
|
||||
fun addGoodSizedLabel(text: String, size: Int = Constants.defaultFontSize): Cell<Label> {
|
||||
val label = text.toLabel(fontSize = size)
|
||||
label.wrap = true
|
||||
label.setAlignment(Align.center)
|
||||
@ -140,7 +172,12 @@ open class Popup(
|
||||
* @param action A lambda to be executed when the button is clicked.
|
||||
* @return The new [Cell]
|
||||
*/
|
||||
fun addButton(text: String, key: KeyCharAndCode? = null, style: TextButtonStyle? = null, action: () -> Unit): Cell<TextButton> {
|
||||
fun addButton(
|
||||
text: String,
|
||||
key: KeyCharAndCode? = null,
|
||||
style: TextButtonStyle? = null,
|
||||
action: () -> Unit
|
||||
): Cell<TextButton> {
|
||||
val button = text.toTextButton(style)
|
||||
button.onActivation { action() }
|
||||
button.keyShortcuts.add(key)
|
||||
@ -148,6 +185,7 @@ open class Popup(
|
||||
}
|
||||
fun addButton(text: String, key: Char, style: TextButtonStyle? = null, action: () -> Unit)
|
||||
= addButton(text, KeyCharAndCode(key), style, action).apply { row() }
|
||||
@Suppress("unused") // Keep the offer to pass an Input.keys value
|
||||
fun addButton(text: String, key: Int, style: TextButtonStyle? = null, action: () -> Unit)
|
||||
= addButton(text, KeyCharAndCode(key), style, action).apply { row() }
|
||||
|
||||
@ -164,7 +202,12 @@ open class Popup(
|
||||
style: TextButtonStyle? = null,
|
||||
action: (()->Unit)? = null
|
||||
): Cell<TextButton> {
|
||||
val cell = addButton(text, additionalKey, style) { close(); if(action!=null) action() }
|
||||
clickBehindToClose = true
|
||||
onCloseCallback = action
|
||||
val cell = addButton(text, additionalKey, style) {
|
||||
close()
|
||||
action?.invoke()
|
||||
}
|
||||
cell.actor.keyShortcuts.add(KeyCharAndCode.BACK)
|
||||
return cell
|
||||
}
|
||||
@ -224,7 +267,7 @@ open class Popup(
|
||||
* and a close button if requested
|
||||
*/
|
||||
fun reuseWith(newText: String, withCloseButton: Boolean = false) {
|
||||
innerTable.clear()
|
||||
clear()
|
||||
addGoodSizedLabel(newText)
|
||||
if (withCloseButton) {
|
||||
row()
|
||||
@ -264,12 +307,5 @@ val BaseScreen.activePopup: Popup?
|
||||
fun BaseScreen.hasOpenPopups(): Boolean = stage.hasOpenPopups()
|
||||
private fun Stage.hasOpenPopups(): Boolean = actors.any { it is Popup && it.isVisible }
|
||||
|
||||
/**
|
||||
* Counts number of visible[Popup]s.
|
||||
*
|
||||
* Used for key dispatcher precedence.
|
||||
*/
|
||||
private fun Stage.countOpenPopups() = actors.count { it is Popup && it.isVisible }
|
||||
|
||||
/** Closes all [Popup]s. */
|
||||
fun BaseScreen.closeAllPopups() = popups.forEach { it.close() }
|
||||
|
@ -547,6 +547,7 @@ private class RandomNationPickerPopup(
|
||||
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
|
||||
closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft)
|
||||
innerTable.addActor(closeButton)
|
||||
clickBehindToClose = true
|
||||
|
||||
val okButton = "OtherIcons/Checkmark".toImageButton(Color.LIME)
|
||||
okButton.onClick { returnSelected() }
|
||||
|
@ -460,6 +460,7 @@ private class NationPickerPopup(
|
||||
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
|
||||
closeButton.setPosition(buttonsOffsetFromEdge, buttonsOffsetFromEdge, Align.bottomLeft)
|
||||
innerTable.addActor(closeButton)
|
||||
clickBehindToClose = true
|
||||
|
||||
val okButton = "OtherIcons/Checkmark".toImageButton(Color.LIME)
|
||||
okButton.onClick { returnSelected() }
|
||||
|
@ -302,7 +302,7 @@ class WorldScreen(
|
||||
} catch (ex: Throwable) {
|
||||
launchOnGLThread {
|
||||
val (message) = LoadGameScreen.getLoadExceptionMessage(ex, "Couldn't download the latest game state!")
|
||||
loadingGamePopup.innerTable.clear()
|
||||
loadingGamePopup.clear()
|
||||
loadingGamePopup.addGoodSizedLabel(message).colspan(2).row()
|
||||
loadingGamePopup.addButton("Retry") {
|
||||
launchOnThreadPool("Load latest multiplayer state after error") {
|
||||
|
Loading…
Reference in New Issue
Block a user