Resolved #3470 - popups now make the rest of the screen unclickable to avoid exploits

Resolved #3468 the same way
This commit is contained in:
Yair Morgenstern 2020-12-28 17:37:29 +02:00
parent e07fd6d0bc
commit ca04093321
3 changed files with 81 additions and 90 deletions

View File

@ -1,6 +1,8 @@
package com.unciv.ui.utils
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Colors
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.Label
@ -13,13 +15,18 @@ import com.unciv.Constants
* Base class for all Popups, i.e. Tables that get rendered in the middle of a screen and on top of everything else
*/
open class Popup(val screen: CameraStageBaseScreen): Table(CameraStageBaseScreen.skin) {
val innerTable = Table(CameraStageBaseScreen.skin)
init {
background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
background = ImageGetter.getBackground(Color.GRAY.cpy().apply { a=.5f })
innerTable.background = ImageGetter.getBackground(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
this.pad(20f)
this.defaults().pad(5f)
innerTable.pad(20f)
innerTable.defaults().pad(5f)
super.add(innerTable)
this.isVisible = false
touchable = Touchable.enabled // don't allow clicking behind
setFillParent(true)
}
/**
@ -32,6 +39,7 @@ open class Popup(val screen: CameraStageBaseScreen): Table(CameraStageBaseScreen
}
screen.stage.addActor(this)
innerTable.pack()
pack()
center(screen.stage)
}
@ -42,6 +50,11 @@ open class Popup(val screen: CameraStageBaseScreen): Table(CameraStageBaseScreen
if (nextPopup != null) nextPopup.isVisible = true
}
/** All additions to the popup are to the inner table - we shouldn't care that there's an inner table at all */
override fun <T : Actor?> add(actor: T) = innerTable.add(actor)
override fun row() = innerTable.row()
fun addSeparator() = innerTable.addSeparator()
fun addGoodSizedLabel(text: String, size:Int=18): Cell<Label> {
val label = text.toLabel(fontSize = size)
label.setWrap(true)
@ -55,13 +68,6 @@ open class Popup(val screen: CameraStageBaseScreen): Table(CameraStageBaseScreen
return add(button).apply { row() }
}
fun addSquareButton(text: String, action: () -> Unit): Cell<Table> {
val button = Table()
button.add(text.toLabel())
button.onClick(action)
button.touchable = Touchable.enabled
return add(button).apply { row() }
}
fun addCloseButton(action: (()->Unit)? = null): Cell<TextButton> {
return if (action==null)

View File

@ -28,14 +28,14 @@ class Language(val language:String, val percentComplete:Int){
class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScreen) {
var selectedLanguage: String = "English"
private val settings = previousScreen.game.settings
private val innerTable = Table(CameraStageBaseScreen.skin)
val innerTable2 = Table(CameraStageBaseScreen.skin)
init {
settings.addCompletedTutorialTask("Open the options table")
rebuildInnerTable()
val scrollPane = ScrollPane(innerTable, skin)
val scrollPane = ScrollPane(innerTable2, skin)
scrollPane.setOverscroll(false, false)
scrollPane.fadeScrollBars = false
scrollPane.setScrollingDisabled(true, false)
@ -51,18 +51,18 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
private fun addHeader (text: String) {
innerTable.add(text.toLabel(fontSize = 24)).colspan(2).padTop(if (innerTable.cells.isEmpty) 0f else 20f).row()
innerTable2.add(text.toLabel(fontSize = 24)).colspan(2).padTop(if (innerTable2.cells.isEmpty) 0f else 20f).row()
}
private fun addYesNoRow (text: String, initialValue: Boolean, updateWorld: Boolean = false, action: ((Boolean) -> Unit)) {
innerTable.add(text.toLabel())
val button = YesNoButton(initialValue, skin) {
innerTable2.add(text.toLabel())
val button = YesNoButton(initialValue, CameraStageBaseScreen.skin) {
action(it)
settings.save()
if (updateWorld && previousScreen is WorldScreen)
previousScreen.shouldUpdate = true
}
innerTable.add(button).row()
innerTable2.add(button).row()
}
private fun reloadWorldAndOptions() {
@ -78,7 +78,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
private fun rebuildInnerTable() {
settings.save()
innerTable.clear()
innerTable2.clear()
addHeader("Display options")
@ -102,7 +102,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
val continuousRenderingDescription = "When disabled, saves battery life but certain animations will be suspended"
innerTable.add(continuousRenderingDescription.toLabel(fontSize = 14)).colspan(2).padTop(20f).row()
innerTable2.add(continuousRenderingDescription.toLabel(fontSize = 14)).colspan(2).padTop(20f).row()
addHeader("Gameplay options")
@ -136,8 +136,8 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
addModPopup()
addSetUserId()
innerTable.add("Version".toLabel()).pad(10f)
innerTable.add(previousScreen.game.version.toLabel()).pad(10f).row()
innerTable2.add("Version".toLabel()).pad(10f)
innerTable2.add(previousScreen.game.version.toLabel()).pad(10f).row()
}
private fun addSetUserId() {
@ -159,8 +159,8 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
idSetLabel.setFontColor(Color.RED).setText("Invalid ID!".tr())
}
}
innerTable.add(takeUserIdFromClipboardButton).pad(5f).colspan(2).row()
innerTable.add(idSetLabel).colspan(2).row()
innerTable2.add(takeUserIdFromClipboardButton).pad(5f).colspan(2).row()
innerTable2.add(idSetLabel).colspan(2).row()
}
private fun addNotificationOptions() {
@ -190,7 +190,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
generateTranslationsButton.setText("Translation files are generated successfully.".tr())
generateTranslationsButton.disable()
}
innerTable.add(generateTranslationsButton).colspan(2).row()
innerTable2.add(generateTranslationsButton).colspan(2).row()
}
}
@ -209,11 +209,11 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
popup.addCloseButton()
popup.open(true)
}
innerTable.add(generateTranslationsButton).colspan(2).row()
innerTable2.add(generateTranslationsButton).colspan(2).row()
}
private fun addSoundEffectsVolumeSlider() {
innerTable.add("Sound effects volume".tr())
innerTable2.add("Sound effects volume".tr())
val soundEffectsVolumeSlider = Slider(0f, 1.0f, 0.1f, false, skin)
soundEffectsVolumeSlider.value = settings.soundEffectsVolume
@ -222,13 +222,13 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
settings.save()
Sounds.play(UncivSound.Click)
}
innerTable.add(soundEffectsVolumeSlider).pad(10f).row()
innerTable2.add(soundEffectsVolumeSlider).pad(10f).row()
}
private fun addMusicVolumeSlider() {
val musicLocation = Gdx.files.local(previousScreen.game.musicLocation)
if (musicLocation.exists()) {
innerTable.add("Music volume".tr())
innerTable2.add("Music volume".tr())
val musicVolumeSlider = Slider(0f, 1.0f, 0.1f, false, skin)
musicVolumeSlider.value = settings.musicVolume
@ -242,12 +242,12 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
music?.volume = 0.4f * musicVolumeSlider.value
}
innerTable.add(musicVolumeSlider).pad(10f).row()
innerTable2.add(musicVolumeSlider).pad(10f).row()
} else {
val downloadMusicButton = "Download music".toTextButton()
innerTable.add(downloadMusicButton).colspan(2).row()
innerTable2.add(downloadMusicButton).colspan(2).row()
val errorTable = Table()
innerTable.add(errorTable).colspan(2).row()
innerTable2.add(errorTable).colspan(2).row()
downloadMusicButton.onClick {
downloadMusicButton.disable()
@ -275,14 +275,14 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
private fun addResolutionSelectBox() {
innerTable.add("Resolution".toLabel())
innerTable2.add("Resolution".toLabel())
val resolutionSelectBox = SelectBox<String>(skin)
val resolutionArray = Array<String>()
resolutionArray.addAll("750x500", "900x600", "1050x700", "1200x800", "1500x1000")
resolutionSelectBox.items = resolutionArray
resolutionSelectBox.selected = settings.resolution
innerTable.add(resolutionSelectBox).minWidth(240f).pad(10f).row()
innerTable2.add(resolutionSelectBox).minWidth(240f).pad(10f).row()
resolutionSelectBox.onChange {
settings.resolution = resolutionSelectBox.selected
@ -291,7 +291,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
private fun addTileSetSelectBox() {
innerTable.add("Tileset".toLabel())
innerTable2.add("Tileset".toLabel())
val tileSetSelectBox = SelectBox<String>(skin)
val tileSetArray = Array<String>()
@ -300,7 +300,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
for (tileset in tileSets) tileSetArray.add(tileset)
tileSetSelectBox.items = tileSetArray
tileSetSelectBox.selected = settings.tileSet
innerTable.add(tileSetSelectBox).minWidth(240f).pad(10f).row()
innerTable2.add(tileSetSelectBox).minWidth(240f).pad(10f).row()
tileSetSelectBox.onChange {
settings.tileSet = tileSetSelectBox.selected
@ -309,7 +309,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
private fun addAutosaveTurnsSelectBox() {
innerTable.add("Turns between autosaves".toLabel())
innerTable2.add("Turns between autosaves".toLabel())
val autosaveTurnsSelectBox = SelectBox<Int>(skin)
val autosaveTurnsArray = Array<Int>()
@ -317,7 +317,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
autosaveTurnsSelectBox.items = autosaveTurnsArray
autosaveTurnsSelectBox.selected = settings.turnsBetweenAutosaves
innerTable.add(autosaveTurnsSelectBox).pad(10f).row()
innerTable2.add(autosaveTurnsSelectBox).pad(10f).row()
autosaveTurnsSelectBox.onChange {
settings.turnsBetweenAutosaves = autosaveTurnsSelectBox.selected
@ -326,7 +326,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
}
private fun addMultiplayerTurnCheckerDelayBox() {
innerTable.add("Time between turn checks out-of-game (in minutes)".toLabel())
innerTable2.add("Time between turn checks out-of-game (in minutes)".toLabel())
val checkDelaySelectBox = SelectBox<Int>(skin)
val possibleDelaysArray = Array<Int>()
@ -334,7 +334,7 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
checkDelaySelectBox.items = possibleDelaysArray
checkDelaySelectBox.selected = settings.multiplayerTurnCheckerDelayInMinutes
innerTable.add(checkDelaySelectBox).pad(10f).row()
innerTable2.add(checkDelaySelectBox).pad(10f).row()
checkDelaySelectBox.onChange {
settings.multiplayerTurnCheckerDelayInMinutes = checkDelaySelectBox.selected
@ -351,11 +351,11 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
.forEach { languageArray.add(it) }
if (languageArray.size == 0) return
innerTable.add("Language".toLabel())
innerTable2.add("Language".toLabel())
languageSelectBox.items = languageArray
val matchingLanguage = languageArray.firstOrNull { it.language == settings.language }
languageSelectBox.selected = if (matchingLanguage != null) matchingLanguage else languageArray.first()
innerTable.add(languageSelectBox).minWidth(240f).pad(10f).row()
innerTable2.add(languageSelectBox).minWidth(240f).pad(10f).row()
languageSelectBox.onChange {
// Sometimes the "changed" is triggered even when we didn't choose something

View File

@ -1,9 +1,11 @@
package com.unciv.ui.worldscreen.mainmenu
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Cell
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants
import com.unciv.MainMenuScreen
import com.unciv.models.translations.tr
import com.unciv.ui.CivilopediaScreen
import com.unciv.ui.newgamescreen.GameSetupInfo
import com.unciv.ui.newgamescreen.NewGameScreen
@ -11,69 +13,52 @@ import com.unciv.ui.saves.LoadGameScreen
import com.unciv.ui.saves.SaveGameScreen
import com.unciv.ui.utils.Popup
import com.unciv.ui.utils.addSeparator
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.toLabel
import com.unciv.ui.victoryscreen.VictoryScreen
import com.unciv.ui.worldscreen.WorldScreen
class WorldScreenMenuPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
val buttonWidth = 200f
val buttonHeight = 30f
init {
val width = 200f
val height = 30f
addSquareButton("Main menu".tr()){
worldScreen.game.setScreen(MainMenuScreen())
close()
}.size(width,height)
addSeparator()
addMenuButton("Main menu") { worldScreen.game.setScreen(MainMenuScreen()) }
addMenuButton("Civilopedia") { worldScreen.game.setScreen(CivilopediaScreen(worldScreen.gameInfo.ruleSet)) }
addMenuButton("Save game") { worldScreen.game.setScreen(SaveGameScreen()) }
addMenuButton("Load game") { worldScreen.game.setScreen(LoadGameScreen(worldScreen)) }
addSquareButton("Civilopedia".tr()){
worldScreen.game.setScreen(CivilopediaScreen(worldScreen.gameInfo.ruleSet))
close()
}.size(width,height)
addSeparator()
addMenuButton("Start new game") {
val newGameScreen = NewGameScreen(worldScreen, GameSetupInfo(worldScreen.gameInfo))
worldScreen.game.setScreen(newGameScreen)
}
addSquareButton("Save game".tr()){
worldScreen.game.setScreen(SaveGameScreen())
close()
}.size(width,height)
addSeparator()
addMenuButton("Victory status") { worldScreen.game.setScreen(VictoryScreen(worldScreen)) }
addMenuButton("Options") { OptionsPopup(worldScreen).open(force = true) }
addMenuButton("Community") { WorldScreenCommunityPopup(worldScreen).open(force = true) }
addSquareButton("Load game".tr()){
worldScreen.game.setScreen(LoadGameScreen(worldScreen))
addSquareButton(Constants.close) {
close()
}.size(width,height)
addSeparator()
}.size(buttonWidth, buttonHeight)
}
addSquareButton("Start new game".tr()){
worldScreen.game.setScreen(NewGameScreen(worldScreen, GameSetupInfo(worldScreen.gameInfo)))
fun addMenuButton(text: String, action: () -> Unit) {
addSquareButton(text) {
action()
close()
}.size(width,height)
addSeparator()
addSquareButton("Victory status".tr()){
worldScreen.game.setScreen(VictoryScreen(worldScreen))
close()
}.size(width,height)
addSeparator()
addSquareButton("Options".tr()){
OptionsPopup(worldScreen).open(force = true)
close()
}.size(width,height)
addSeparator()
addSquareButton("Community"){
WorldScreenCommunityPopup(worldScreen).open(force = true)
close()
}.size(width,height)
addSeparator()
addSquareButton(Constants.close){
close()
}.size(width,height)
}.size(buttonWidth, buttonHeight)
innerTable.addSeparator()
}
fun addSquareButton(text: String, action: () -> Unit): Cell<Table> {
val button = Table()
button.add(text.toLabel())
button.onClick(action)
button.touchable = Touchable.enabled
return add(button).apply { row() }
}
}
class WorldScreenCommunityPopup(val worldScreen: WorldScreen) : Popup(worldScreen) {
@ -95,4 +80,4 @@ class WorldScreenCommunityPopup(val worldScreen: WorldScreen) : Popup(worldScree
addCloseButton()
}
}
}