From 43b044740ca75986949bcc5571e4b2ef3ca6735d Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Thu, 4 May 2023 08:25:14 +0200 Subject: [PATCH] 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 --- .../com/unciv/ui/components/TabbedPager.kt | 2 + core/src/com/unciv/ui/popups/Popup.kt | 70 ++++++++++++++----- .../screens/newgamescreen/GameOptionsTable.kt | 1 + .../newgamescreen/PlayerPickerTable.kt | 1 + .../ui/screens/worldscreen/WorldScreen.kt | 2 +- 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/core/src/com/unciv/ui/components/TabbedPager.kt b/core/src/com/unciv/ui/components/TabbedPager.kt index b475dee52b..de365a83fe 100644 --- a/core/src/com/unciv/ui/components/TabbedPager.kt +++ b/core/src/com/unciv/ui/components/TabbedPager.kt @@ -621,6 +621,8 @@ open class TabbedPager( addOKButton { if (passEntry.text.hashCode() == secretHashCode) unlockAction() else lockAction() } + clickBehindToClose = true + onCloseCallback = lockAction this.keyboardFocus = passEntry } } diff --git a/core/src/com/unciv/ui/popups/Popup.kt b/core/src/com/unciv/ui/popups/Popup.kt index 4355964af7..ae48e067b0 100644 --- a/core/src/com/unciv/ui/popups/Popup.kt +++ b/core/src/com/unciv/ui/popups/Popup.kt @@ -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 add(actor: T): Cell = innerTable.add(actor) override fun row(): Cell = innerTable.row() override fun defaults(): Cell = 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