mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-19 16:57:38 +07:00
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:
parent
b9a916e081
commit
8a024bf9fe
@ -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)
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
19
core/src/com/unciv/ui/popups/LoadingPopup.kt
Normal file
19
core/src/com/unciv/ui/popups/LoadingPopup.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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!!)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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() {
|
||||||
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user