Popups get the ability to scroll only the content without the buttons (#9513)

* Popups get the ability to scroll only the content without the buttons

* Centralize LoadingPopup

* Split non-WorldScreenMenuPopup classes off from that file

* Linting
This commit is contained in:
SomeTroglodyte 2023-06-04 07:41:58 +02:00 committed by GitHub
parent b9a916e081
commit 8a024bf9fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 213 additions and 92 deletions

View File

@ -47,7 +47,7 @@ open class FileChooser(
title: String?, title: String?,
startFile: FileHandle? = null, startFile: FileHandle? = null,
private val resultListener: ResultListener? = null private val resultListener: ResultListener? = null
) : Popup(stageToShowOn, false) { ) : Popup(stageToShowOn, Scrollability.None) {
// config // config
var filter = FileFilter { true } var filter = FileFilter { true }
set(value) { field = value; resetList() } set(value) { field = value; resetList() }
@ -123,21 +123,20 @@ open class FileChooser(
init { init {
innerTable.top().left() innerTable.top().left()
innerTable.touchable = Touchable.enabled
fileList.selection.setProgrammaticChangeEvents(false) fileList.selection.setProgrammaticChangeEvents(false)
fileNameInput.setTextFieldListener { textField, _ -> result = textField.text } fileNameInput.setTextFieldListener { textField, _ -> result = textField.text }
if (title != null) { if (title != null) {
addGoodSizedLabel(title).colspan(2).center().row() addGoodSizedLabel(title).colspan(2).center().row()
innerTable.addSeparator(height = 1f) addSeparator(height = 1f)
} }
add(pathLabelWrapper).colspan(2).fillX().row() add(pathLabelWrapper).colspan(2).fillX().row()
innerTable.addSeparator(Color.GRAY, height = 1f) addSeparator(Color.GRAY, height = 1f)
add(fileScroll).colspan(2).fill().row() add(fileScroll).colspan(2).fill().row()
innerTable.addSeparator(height = 1f) addSeparator(height = 1f)
fileNameCell = innerTable.add().colspan(2).growX() fileNameCell = add().colspan(2).growX()
innerTable.row() row()
addCloseButton("Cancel", KeyboardBinding.Cancel) { addCloseButton("Cancel", KeyboardBinding.Cancel) {
reportResult(false) reportResult(false)

View File

@ -24,10 +24,10 @@ class AuthPopup(stage: Stage, authSuccessful: ((Boolean) -> Unit)? = null)
authSuccessful?.invoke(true) authSuccessful?.invoke(true)
close() close()
} catch (_: Exception) { } catch (_: Exception) {
innerTable.clear() clear()
addGoodSizedLabel("Authentication failed").colspan(2).row() addGoodSizedLabel("Authentication failed").colspan(2).row()
add(passwordField).colspan(2).growX().pad(16f, 0f, 16f, 0f).row() add(passwordField).colspan(2).growX().pad(16f, 0f, 16f, 0f).row()
addCloseButton(style=negativeButtonStyle) { authSuccessful?.invoke(false) }.growX().padRight(8f) addCloseButton(style = negativeButtonStyle) { authSuccessful?.invoke(false) }.growX().padRight(8f)
add(button).growX().padLeft(8f) add(button).growX().padLeft(8f)
return@onClick return@onClick
} }
@ -35,7 +35,7 @@ class AuthPopup(stage: Stage, authSuccessful: ((Boolean) -> Unit)? = null)
addGoodSizedLabel("Please enter your server password").colspan(2).row() addGoodSizedLabel("Please enter your server password").colspan(2).row()
add(passwordField).colspan(2).growX().pad(16f, 0f, 16f, 0f).row() add(passwordField).colspan(2).growX().pad(16f, 0f, 16f, 0f).row()
addCloseButton(style=negativeButtonStyle) { authSuccessful?.invoke(false) }.growX().padRight(8f) addCloseButton(style = negativeButtonStyle) { authSuccessful?.invoke(false) }.growX().padRight(8f)
add(button).growX().padLeft(8f) add(button).growX().padLeft(8f)
} }
} }

View File

@ -0,0 +1,19 @@
package com.unciv.ui.popups
import com.unciv.Constants
import com.unciv.ui.screens.LoadingScreen
import com.unciv.ui.screens.basescreen.BaseScreen
/**
* Mini popup just displays "Loading..." and opens itself.
*
* Not to be confused with [LoadingScreen], which tries to preserve background as screenshot.
* That screen will use this once the screenshot is on-screen, though.
*/
class LoadingPopup(screen: BaseScreen) : Popup(screen, Scrollability.None) {
init {
addGoodSizedLabel(Constants.loading)
open(true)
}
}

View File

@ -9,10 +9,12 @@ import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Button import com.badlogic.gdx.scenes.scene2d.ui.Button
import com.badlogic.gdx.scenes.scene2d.ui.Cell import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle
import com.badlogic.gdx.scenes.scene2d.ui.TextField import com.badlogic.gdx.scenes.scene2d.ui.TextField
import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
@ -33,27 +35,80 @@ import com.unciv.ui.screens.basescreen.UncivStage
/** /**
* Base class for all Popups, i.e. Tables that get rendered in the middle of a screen and on top of everything else * Base class for all Popups, i.e. Tables that get rendered in the middle of a screen and on top of everything else
*
* @property stageToShowOn The stage that will be used for [open], measurements or finding other instances
* @param scrollable Controls how content can scroll if too large - see [Scrollability]
* @param maxSizePercentage Causes [topTable] to limit its height - useful if `scrollable` is on. Will be multiplied by stageToShowOn.height.
*/ */
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
open class Popup( open class Popup(
val stageToShowOn: Stage, val stageToShowOn: Stage,
scrollable: Boolean = true scrollable: Scrollability = Scrollability.WithoutButtons,
maxSizePercentage: Float = 0.9f
): Table(BaseScreen.skin) { ): Table(BaseScreen.skin) {
constructor(screen: BaseScreen) : this(screen.stage) constructor(
screen: BaseScreen,
scrollable: Scrollability = Scrollability.WithoutButtons,
maxSizePercentage: Float = 0.9f
) : this(screen.stage, scrollable, maxSizePercentage)
// This exists to differentiate the actual popup (the inner table) /** Controls how content may scroll.
// from the 'screen blocking' part of the popup (which covers the entire screen) *
* With scrolling enabled, the ScrollPane can be accessed via [getScrollPane].
* @property None No scrolling
* @property All Entire content wrapped in an [AutoScrollPane] so it can scroll if larger than maximum dimensions
* @property WithoutButtons content separated into scrollable upper part and static lower part containing the buttons
*/
enum class Scrollability { None, All, WithoutButtons }
private val maxPopupWidth = stageToShowOn.width * maxSizePercentage
private val maxPopupHeight = stageToShowOn.height * maxSizePercentage
/** This exists to differentiate the actual popup (this table)
* from the 'screen blocking' part of the popup (which covers the entire screen).
*
* Note you seldom need to interact directly with it, Popup has many Table method proxies
* that pass through, like [add], [row], [defaults], [addSeparator] or [clear].
*/
/* Hierarchy:
Scrollability.None:
* Stage
* this@Popup (fills parent, catches click-behind)
* innerTable (entire Popup content, smaller, limited by maxSizePercentage)
* topTable and bottomTable _reference_ innerTable
Scrollability.All:
* Stage
* this@Popup (fills parent, catches click-behind)
* ScrollPane (anonymous)
* innerTable (entire Popup content, smaller, limited by maxSizePercentage)
* topTable and bottomTable _reference_ innerTable
Scrollability.WithoutButtons:
* Stage
* this@Popup (fills parent, catches click-behind)
* innerTable (entire Popup content, smaller, limited by maxSizePercentage)
* ScrollPane (anonymous)
* topTable
* bottomTable
*/
protected val innerTable = Table(BaseScreen.skin) protected val innerTable = Table(BaseScreen.skin)
/** This contains most of the Popup content (except the closing buttons which go in [bottomTable]) */
private val topTable: Table
private val topTableCell: Cell<WidgetGroup>
/** This contains the bottom row buttons and does not participate in scrolling */
protected val bottomTable: Table
/** Callbacks that will be called whenever this Popup is shown */ /** Callbacks that will be called whenever this Popup is shown */
val showListeners = mutableListOf<() -> Unit>() val showListeners = mutableListOf<() -> Unit>()
/** Callbacks that will be called whenever this Popup is closed, no matter how (e.g. no distinction OK/Cancel) */ /** Callbacks that will be called whenever this Popup is closed, no matter how (e.g. no distinction OK/Cancel) */
val closeListeners = mutableListOf<() -> Unit>() val closeListeners = mutableListOf<() -> Unit>()
/** [EventBus] is used to receive [UncivStage.VisibleAreaChanged] */
protected val events = EventBus.EventReceiver() protected val events = EventBus.EventReceiver()
/** Enables/disables closing by clicking/trapping outside [innerTable]. /** Enables/disables closing by clicking/tapping outside [innerTable].
* *
* Automatically set when [addCloseButton] is called but may be changed back or enabled without such a button. * Automatically set when [addCloseButton] is called but may be changed back or enabled without such a button.
*/ */
@ -69,15 +124,43 @@ open class Popup(
background = BaseScreen.skinStrings.getUiBackground( background = BaseScreen.skinStrings.getUiBackground(
"General/Popup/Background", "General/Popup/Background",
tintColor = Color.GRAY.cpy().apply { a = 0.5f }) tintColor = Color.GRAY.cpy().apply { a = 0.5f })
//todo topTable and bottomTable _could_ be separately skinnable - but would need care so rounded edges work
innerTable.background = BaseScreen.skinStrings.getUiBackground( innerTable.background = BaseScreen.skinStrings.getUiBackground(
"General/Popup/InnerTable", "General/Popup/InnerTable",
tintColor = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f) tintColor = BaseScreen.skinStrings.skinConfig.baseColor.darken(0.5f)
) )
innerTable.touchable = Touchable.enabled
innerTable.pad(20f) fun wrapInScrollPane(table: Table) = AutoScrollPane(table, BaseScreen.skin)
innerTable.defaults().pad(5f) .apply { setOverscroll(false, false) }
when (scrollable) {
Scrollability.None -> {
topTable = innerTable
bottomTable = innerTable
topTableCell = super.add(innerTable)
}
Scrollability.All -> {
topTable = innerTable
bottomTable = innerTable
topTableCell = super.add(wrapInScrollPane(innerTable))
}
Scrollability.WithoutButtons -> {
topTable = Table(BaseScreen.skin)
topTable.pad(20f).padBottom(0f)
topTable.defaults().fillX().pad(5f)
bottomTable = Table(BaseScreen.skin)
topTableCell = innerTable.add(wrapInScrollPane(topTable))
innerTable.defaults().fillX()
innerTable.row()
innerTable.add(bottomTable)
super.add(innerTable)
}
}
super.add(if (scrollable) AutoScrollPane(innerTable, BaseScreen.skin) else innerTable) bottomTable.pad(20f)
bottomTable.defaults().pad(5f)
topTableCell.maxSize(maxPopupWidth, maxPopupHeight)
isVisible = false isVisible = false
touchable = Touchable.enabled touchable = Touchable.enabled
@ -86,12 +169,20 @@ open class Popup(
super.setFillParent(true) super.setFillParent(true)
} }
private fun recalculateInnerTableMaxHeight() {
if (topTable === bottomTable) return
topTableCell.maxHeight(maxPopupHeight - bottomTable.prefHeight)
innerTable.invalidate()
}
/** /**
* Displays the Popup on the screen. If another popup is already open, this one will display after the other has * Displays the Popup on the screen. If another popup is already open, this one will display after the other has
* closed. Use [force] = true if you want to open this popup above the other one anyway. * closed. Use [force] = true if you want to open this popup above the other one anyway.
*/ */
fun open(force: Boolean = false) { fun open(force: Boolean = false) {
stageToShowOn.addActor(this) stageToShowOn.addActor(this)
recalculateInnerTableMaxHeight()
innerTable.pack() innerTable.pack()
pack() pack()
center(stageToShowOn) center(stageToShowOn)
@ -140,13 +231,26 @@ open class Popup(
} }
} }
/* All additions to the popup are to the inner table - we shouldn't care that there's an inner table at all */ /* 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) Note the Kdoc mentions innerTable when under Scrollability.WithoutButtons it's actually topTable,
override fun row(): Cell<Actor> = innerTable.row() but metioning that distinction seems overkill. innerTable has the clearer Kdoc for "where the Actors go".
override fun defaults(): Cell<Actor> = innerTable.defaults() */
fun addSeparator() = innerTable.addSeparator() /** Popup proxy redirects [add][com.badlogic.gdx.scenes.scene2d.ui.Table.add] to [innerTable] */
final override fun <T : Actor?> add(actor: T): Cell<T> = topTable.add(actor)
/** Popup proxy redirects [add][com.badlogic.gdx.scenes.scene2d.ui.Table.add] to [innerTable] */
final override fun add(): Cell<Actor?> = topTable.add()
/** Popup proxy redirects [row][com.badlogic.gdx.scenes.scene2d.ui.Table.row] to [innerTable] */
override fun row(): Cell<Actor> = topTable.row()
/** Popup proxy redirects [defaults][com.badlogic.gdx.scenes.scene2d.ui.Table.defaults] to [innerTable] */
override fun defaults(): Cell<Actor> = topTable.defaults()
/** Popup proxy redirects [addSeparator][com.unciv.ui.components.extensions.addSeparator] to [innerTable] */
fun addSeparator(color: Color = Color.WHITE, colSpan: Int = 0, height: Float = 2f) =
topTable.addSeparator(color, colSpan, height)
/** Proxy redirects [add][com.badlogic.gdx.scenes.scene2d.ui.Table.clear] to clear content:
* [innerTable] or if [Scrollability.WithoutButtons] was used [topTable] and [bottomTable] */
override fun clear() { override fun clear() {
innerTable.clear() topTable.clear()
bottomTable.clear()
clickBehindToClose = false clickBehindToClose = false
onCloseCallback = null onCloseCallback = null
} }
@ -181,7 +285,7 @@ open class Popup(
val button = text.toTextButton(style) val button = text.toTextButton(style)
button.onActivation { action() } button.onActivation { action() }
button.keyShortcuts.add(key) button.keyShortcuts.add(key)
return add(button) return bottomTable.add(button)
} }
fun addButton(text: String, key: Char, style: TextButtonStyle? = null, action: () -> Unit) fun addButton(text: String, key: Char, style: TextButtonStyle? = null, action: () -> Unit)
= addButton(text, KeyCharAndCode(key), style, action).apply { row() } = addButton(text, KeyCharAndCode(key), style, action).apply { row() }
@ -250,10 +354,10 @@ open class Popup(
* Make their width equal by setting minWidth of one cell to actor width of the other. * Make their width equal by setting minWidth of one cell to actor width of the other.
*/ */
fun equalizeLastTwoButtonWidths() { fun equalizeLastTwoButtonWidths() {
val n = innerTable.cells.size val n = bottomTable.cells.size
if (n < 2) throw UnsupportedOperationException() if (n < 2) throw UnsupportedOperationException()
val cell1 = innerTable.cells[n-2] val cell1 = bottomTable.cells[n-2]
val cell2 = innerTable.cells[n-1] val cell2 = bottomTable.cells[n-1]
if (cell1.actor !is Button || cell2.actor !is Button) throw UnsupportedOperationException() if (cell1.actor !is Button || cell2.actor !is Button) throw UnsupportedOperationException()
cell1.minWidth(cell2.actor.width).uniformX() cell1.minWidth(cell2.actor.width).uniformX()
cell2.minWidth(cell1.actor.width).uniformX() cell2.minWidth(cell1.actor.width).uniformX()
@ -268,7 +372,6 @@ open class Popup(
clear() clear()
addGoodSizedLabel(newText) addGoodSizedLabel(newText)
if (withCloseButton) { if (withCloseButton) {
row()
addCloseButton() addCloseButton()
} }
} }
@ -285,6 +388,9 @@ open class Popup(
if (stageToShowOn.setKeyboardFocus(value)) if (stageToShowOn.setKeyboardFocus(value))
(value as? TextField)?.selectAll() (value as? TextField)?.selectAll()
} }
/** Gets the ScrollPane the content is wrapped in (only if Popup was instantiated with scrollable=true) */
fun getScrollPane() = topTable.parent as? ScrollPane
} }

View File

@ -29,7 +29,7 @@ class OptionsPopup(
screen: BaseScreen, screen: BaseScreen,
private val selectPage: Int = defaultPage, private val selectPage: Int = defaultPage,
private val onClose: () -> Unit = {} private val onClose: () -> Unit = {}
) : Popup(screen.stage, /** [TabbedPager] handles scrolling */ scrollable = false ) { ) : Popup(screen.stage, /** [TabbedPager] handles scrolling */ scrollable = Scrollability.None) {
val game = screen.game val game = screen.game
val settings = screen.game.settings val settings = screen.game.settings

View File

@ -5,18 +5,16 @@ import com.badlogic.gdx.graphics.Pixmap
import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.scenes.scene2d.actions.Actions import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.unciv.Constants
import com.unciv.ui.images.ImageWithCustomSize import com.unciv.ui.images.ImageWithCustomSize
import com.unciv.ui.popups.Popup
import com.unciv.ui.popups.popups import com.unciv.ui.popups.popups
import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.popups.LoadingPopup
/** A loading screen that creates a screenshot of the current screen and adds a "Loading..." popup on top of that */ /** A loading screen that creates a screenshot of the current screen and adds a "Loading..." popup on top of that */
class LoadingScreen( class LoadingScreen(
previousScreen: BaseScreen? = null previousScreen: BaseScreen? = null
) : BaseScreen() { ) : BaseScreen() {
val screenshot: Texture private val screenshot: Texture
init { init {
screenshot = takeScreenshot(previousScreen) screenshot = takeScreenshot(previousScreen)
val image = ImageWithCustomSize( val image = ImageWithCustomSize(
@ -34,9 +32,7 @@ class LoadingScreen(
stage.addAction(Actions.sequence( stage.addAction(Actions.sequence(
Actions.delay(1000f), Actions.delay(1000f),
Actions.run { Actions.run {
val popup = Popup(stage) LoadingPopup(this)
popup.add(Constants.loading.toLabel())
popup.open()
} }
)) ))
} }
@ -44,7 +40,7 @@ class LoadingScreen(
private fun takeScreenshot(previousScreen: BaseScreen?): Texture { private fun takeScreenshot(previousScreen: BaseScreen?): Texture {
if (previousScreen != null) { if (previousScreen != null) {
for (popup in previousScreen.popups) popup.isVisible = false for (popup in previousScreen.popups) popup.isVisible = false
previousScreen.render(Gdx.graphics.getDeltaTime()) previousScreen.render(Gdx.graphics.deltaTime)
} }
val pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.backBufferWidth, Gdx.graphics.backBufferHeight) val pixmap = Pixmap.createFromFrameBuffer(0, 0, Gdx.graphics.backBufferWidth, Gdx.graphics.backBufferHeight)
val screenshot = Texture(pixmap) val screenshot = Texture(pixmap)

View File

@ -29,7 +29,7 @@ import kotlin.math.max
class DetailedStatsPopup( class DetailedStatsPopup(
private val cityScreen: CityScreen private val cityScreen: CityScreen
) : Popup(stageToShowOn = cityScreen.stage, scrollable = false) { ) : Popup(cityScreen, Scrollability.None) {
private val headerTable = Table() private val headerTable = Table()
private val totalTable = Table() private val totalTable = Table()

View File

@ -279,7 +279,7 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize {
QuickSave.autoLoadGame(this) QuickSave.autoLoadGame(this)
} else { } else {
GUI.resetToWorldScreen() GUI.resetToWorldScreen()
GUI.getWorldScreen().popups.filterIsInstance(WorldScreenMenuPopup::class.java).forEach(Popup::close) GUI.getWorldScreen().popups.filterIsInstance<WorldScreenMenuPopup>().forEach(Popup::close)
ImageGetter.ruleset = game.gameInfo!!.ruleset ImageGetter.ruleset = game.gameInfo!!.ruleset
} }
} else { } else {

View File

@ -22,6 +22,7 @@ import com.unciv.ui.components.extensions.isEnabled
import com.unciv.ui.components.extensions.keyShortcuts import com.unciv.ui.components.extensions.keyShortcuts
import com.unciv.ui.components.extensions.onActivation import com.unciv.ui.components.extensions.onActivation
import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.components.extensions.toTextButton
import com.unciv.ui.popups.LoadingPopup
import com.unciv.utils.Concurrency import com.unciv.utils.Concurrency
import com.unciv.utils.Log import com.unciv.utils.Log
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -105,10 +106,7 @@ class MapEditorLoadTab(
var needPopup = true // loadMap can fail faster than postRunnable runs var needPopup = true // loadMap can fail faster than postRunnable runs
Concurrency.runOnGLThread { Concurrency.runOnGLThread {
if (!needPopup) return@runOnGLThread if (!needPopup) return@runOnGLThread
popup = Popup(editorScreen).apply { popup = LoadingPopup(editorScreen)
addGoodSizedLabel(Constants.loading)
open()
}
} }
try { try {
val map = MapSaver.loadMap(chosenMap!!) val map = MapSaver.loadMap(chosenMap!!)

View File

@ -51,7 +51,7 @@ class UnitUpgradeMenu(
private val unit: MapUnit, private val unit: MapUnit,
private val unitAction: UpgradeUnitAction, private val unitAction: UpgradeUnitAction,
private val onButtonClicked: () -> Unit private val onButtonClicked: () -> Unit
) : Popup(stage, scrollable = false) { ) : Popup(stage, Scrollability.None) {
private val container: Container<Table> private val container: Container<Table>
private val allUpgradableUnits: Sequence<MapUnit> private val allUpgradableUnits: Sequence<MapUnit>
private val animationDuration = 0.33f private val animationDuration = 0.33f

View File

@ -25,6 +25,7 @@ import com.unciv.ui.components.extensions.onActivation
import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.onClick
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.popups.LoadingPopup
import com.unciv.utils.Log import com.unciv.utils.Log
import com.unciv.utils.Concurrency import com.unciv.utils.Concurrency
import com.unciv.utils.launchOnGLThread import com.unciv.utils.launchOnGLThread
@ -116,9 +117,7 @@ class LoadGameScreen : LoadOrSaveScreen() {
private fun onLoadGame() { private fun onLoadGame() {
if (selectedSave == null) return if (selectedSave == null) return
val loadingPopup = Popup( this) val loadingPopup = LoadingPopup(this)
loadingPopup.addGoodSizedLabel(Constants.loading)
loadingPopup.open()
Concurrency.run(loadGame) { Concurrency.run(loadGame) {
try { try {
// This is what can lead to ANRs - reading the file and setting the transients, that's why this is in another thread // This is what can lead to ANRs - reading the file and setting the transients, that's why this is in another thread

View File

@ -1,11 +1,10 @@
package com.unciv.ui.screens.savescreens package com.unciv.ui.screens.savescreens
import com.unciv.Constants
import com.unciv.ui.screens.mainmenuscreen.MainMenuScreen import com.unciv.ui.screens.mainmenuscreen.MainMenuScreen
import com.unciv.UncivGame import com.unciv.UncivGame
import com.unciv.logic.GameInfo import com.unciv.logic.GameInfo
import com.unciv.logic.UncivShowableException import com.unciv.logic.UncivShowableException
import com.unciv.ui.popups.Popup import com.unciv.ui.popups.LoadingPopup
import com.unciv.ui.popups.ToastPopup import com.unciv.ui.popups.ToastPopup
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.utils.Concurrency import com.unciv.utils.Concurrency
@ -55,9 +54,7 @@ object QuickSave {
} }
fun autoLoadGame(screen: MainMenuScreen) { fun autoLoadGame(screen: MainMenuScreen) {
val loadingPopup = Popup(screen) val loadingPopup = LoadingPopup(screen)
loadingPopup.addGoodSizedLabel(Constants.loading)
loadingPopup.open()
Concurrency.run("autoLoadGame") { Concurrency.run("autoLoadGame") {
// Load game from file to class on separate thread to avoid ANR... // Load game from file to class on separate thread to avoid ANR...
fun outOfMemory() { fun outOfMemory() {

View File

@ -0,0 +1,26 @@
package com.unciv.ui.screens.worldscreen.mainmenu
import com.badlogic.gdx.Gdx
import com.unciv.ui.popups.Popup
import com.unciv.ui.screens.worldscreen.WorldScreen
class WorldScreenCommunityPopup(val worldScreen: WorldScreen) : Popup(worldScreen, scrollable = Scrollability.All) {
init {
addButton("Discord") {
Gdx.net.openURI("https://discord.gg/bjrB4Xw")
close()
}.row()
addButton("Github") {
Gdx.net.openURI("https://github.com/yairm210/Unciv")
close()
}.row()
addButton("Reddit") {
Gdx.net.openURI("https://www.reddit.com/r/Unciv/")
close()
}.row()
addCloseButton()
}
}

View File

@ -1,18 +1,15 @@
package com.unciv.ui.screens.worldscreen.mainmenu package com.unciv.ui.screens.worldscreen.mainmenu
import com.badlogic.gdx.Gdx
import com.unciv.UncivGame
import com.unciv.models.metadata.GameSetupInfo import com.unciv.models.metadata.GameSetupInfo
import com.unciv.ui.popups.Popup
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
import com.unciv.ui.screens.newgamescreen.NewGameScreen import com.unciv.ui.screens.newgamescreen.NewGameScreen
import com.unciv.ui.popups.options.addMusicControls
import com.unciv.ui.popups.Popup
import com.unciv.ui.screens.savescreens.LoadGameScreen import com.unciv.ui.screens.savescreens.LoadGameScreen
import com.unciv.ui.screens.savescreens.SaveGameScreen import com.unciv.ui.screens.savescreens.SaveGameScreen
import com.unciv.ui.screens.victoryscreen.VictoryScreen import com.unciv.ui.screens.victoryscreen.VictoryScreen
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen) { class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen, scrollable = Scrollability.All) {
init { init {
defaults().fillX() defaults().fillX()
@ -54,42 +51,9 @@ class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
}.row() }.row()
addButton("Music") { addButton("Music") {
close() close()
WorldScreenMusicButton(worldScreen).open(force = true) WorldScreenMusicPopup(worldScreen).open(force = true)
}.row() }.row()
addCloseButton() addCloseButton()
pack() pack()
} }
} }
class WorldScreenCommunityPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
init {
defaults().fillX()
addButton("Discord") {
Gdx.net.openURI("https://discord.gg/bjrB4Xw")
close()
}.row()
addButton("Github") {
Gdx.net.openURI("https://github.com/yairm210/Unciv")
close()
}.row()
addButton("Reddit") {
Gdx.net.openURI("https://www.reddit.com/r/Unciv/")
close()
}.row()
addCloseButton()
}
}
class WorldScreenMusicButton(val worldScreen: WorldScreen) : Popup(worldScreen) {
init {
val musicController = UncivGame.Current.musicController
val settings = UncivGame.Current.settings
defaults().fillX()
addMusicControls(this, settings, musicController)
addCloseButton().colspan(2)
}
}

View File

@ -0,0 +1,17 @@
package com.unciv.ui.screens.worldscreen.mainmenu
import com.unciv.UncivGame
import com.unciv.ui.popups.Popup
import com.unciv.ui.popups.options.addMusicControls
import com.unciv.ui.screens.worldscreen.WorldScreen
class WorldScreenMusicPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
init {
val musicController = UncivGame.Current.musicController
val settings = UncivGame.Current.settings
defaults().fillX()
addMusicControls(this, settings, musicController)
addCloseButton().colspan(2)
}
}