diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/WorldScreenOptionsPopup.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/WorldScreenOptionsPopup.kt index 8f8b757b91..6be9c4ea29 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/WorldScreenOptionsPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/WorldScreenOptionsPopup.kt @@ -24,133 +24,125 @@ class Language(val language:String, val percentComplete:Int){ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) { var selectedLanguage: String = "English" + private val settings = UncivGame.Current.settings + private val innerTable = Table(CameraStageBaseScreen.skin) init { - UncivGame.Current.settings.addCompletedTutorialTask("Open the options table") - update() + settings.addCompletedTutorialTask("Open the options table") + + rebuildInnerTable() + + val scrollPane = ScrollPane(innerTable, skin) + scrollPane.setOverscroll(false, false) + scrollPane.fadeScrollBars = false + scrollPane.setScrollingDisabled(true, false) + add(scrollPane).maxHeight(screen.stage.height * 0.6f).row() + + addCloseButton() + + pack() // Needed to show the background. + center(UncivGame.Current.worldScreen.stage) } + private fun addHeader (text: String) { + innerTable.add(text.toLabel(fontSize = 24)).colspan(2).padTop(if (innerTable.cells.isEmpty) 0f else 20f).row() + } - fun update() { - val settings = UncivGame.Current.settings + private fun addYesNoRow (text: String, initialValue: Boolean, updateWorld: Boolean = false, action: ((Boolean) -> Unit)) { + innerTable.add(text.toLabel()) + val button = YesNoButton(initialValue, skin) { + action(it) + settings.save() + if (updateWorld) + UncivGame.Current.worldScreen.shouldUpdate = true + } + innerTable.add(button).row() + } + + private fun reloadWorldAndOptions() { settings.save() - clear() + UncivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) + UncivGame.Current.setWorldScreen() + WorldScreenOptionsPopup(UncivGame.Current.worldScreen).open() + } - val innerTable = Table(CameraStageBaseScreen.skin) + private fun rebuildInnerTable() { + settings.save() + innerTable.clear() - innerTable.add("Display options".toLabel(fontSize = 24)).colspan(2).row() + addHeader("Display options") - innerTable.add("Show worked tiles".toLabel()) - addButton(innerTable, if (settings.showWorkedTiles) "Yes" else "No") { - settings.showWorkedTiles = !settings.showWorkedTiles - update() + addYesNoRow ("Show worked tiles", settings.showWorkedTiles, true) { + settings.showWorkedTiles = it + } + addYesNoRow ("Show resources and improvements", settings.showResourcesAndImprovements, true) { + settings.showResourcesAndImprovements = it + } + addYesNoRow ("Show tutorials", settings.showTutorials, true) { + settings.showTutorials = it + } + addYesNoRow ("Show minimap", settings.showMinimap, true) { + settings.showMinimap = it + } + addYesNoRow ("Show pixel units", settings.showPixelUnits, true) { + settings.showPixelUnits = it + } + addYesNoRow ("Show pixel improvements", settings.showPixelImprovements, true) { + settings.showPixelImprovements = it } - innerTable.add("Show resources and improvements".toLabel()) - addButton(innerTable, if (settings.showResourcesAndImprovements) "Yes" else "No") { - settings.showResourcesAndImprovements = !settings.showResourcesAndImprovements - update() + addLanguageSelectBox() + + addResolutionSelectBox() + + addTileSetSelectBox() + + addYesNoRow ("Continuous rendering", settings.continuousRendering) { + settings.continuousRendering = it + Gdx.graphics.isContinuousRendering = it } + addHeader("Gameplay options") - innerTable.add("Show tutorials".toLabel()) - addButton(innerTable, if (settings.showTutorials) "Yes" else "No") { - settings.showTutorials = !settings.showTutorials - update() + addYesNoRow ("Check for idle units", settings.checkForDueUnits) { + settings.checkForDueUnits = it + } + addYesNoRow ("Move units with a single tap", settings.singleTapMove) { + settings.singleTapMove = it + } + addYesNoRow ("Auto-assign city production", settings.autoAssignCityProduction) { + settings.autoAssignCityProduction = it + } + addYesNoRow ("Auto-build roads", settings.autoBuildingRoads) { + settings.autoBuildingRoads = it + } + addYesNoRow ("Order trade offers by amount", settings.orderTradeOffersByAmount) { + settings.orderTradeOffersByAmount = it } - innerTable.add("Show minimap".toLabel()) - addButton(innerTable, if (settings.showMinimap) "Yes" else "No") { - settings.showMinimap = !settings.showMinimap - update() - } - - innerTable.add("Show pixel units".toLabel()) - addButton(innerTable, if (settings.showPixelUnits) "Yes" else "No") { - settings.showPixelUnits = !settings.showPixelUnits - update() - } - - innerTable.add("Show pixel improvements".toLabel()) - addButton(innerTable, if (settings.showPixelImprovements) "Yes" else "No") { - settings.showPixelImprovements = !settings.showPixelImprovements - update() - } - - innerTable.add("Order trade offers by amount".toLabel()) - addButton(innerTable, if (settings.orderTradeOffersByAmount) "Yes" else "No") { - settings.orderTradeOffersByAmount = !settings.orderTradeOffersByAmount - update() - } - - addLanguageSelectBox(innerTable) - - addResolutionSelectBox(innerTable) - - addTileSetSelectBox(innerTable) - - innerTable.add("Continuous rendering".toLabel()) - addButton(innerTable, if (settings.continuousRendering) "Yes" else "No") { - settings.continuousRendering = !settings.continuousRendering - Gdx.graphics.isContinuousRendering = settings.continuousRendering - update() - } - - innerTable.add("Gameplay options".toLabel(fontSize = 24)).colspan(2).padTop(20f).row() - - - innerTable.add("Check for idle units".toLabel()) - addButton(innerTable, if (settings.checkForDueUnits) "Yes" else "No") { - settings.checkForDueUnits = !settings.checkForDueUnits - update() - } - - innerTable.add("Move units with a single tap".toLabel()) - addButton(innerTable, if (settings.singleTapMove) "Yes" else "No") { - settings.singleTapMove = !settings.singleTapMove - update() - } - - innerTable.add("Auto-assign city production".toLabel()) - addButton(innerTable, if (settings.autoAssignCityProduction) "Yes" else "No") { - settings.autoAssignCityProduction = !settings.autoAssignCityProduction - update() - } - - innerTable.add("Auto-build roads".toLabel()) - addButton(innerTable, if (settings.autoBuildingRoads) "Yes" else "No") { - settings.autoBuildingRoads = !settings.autoBuildingRoads - update() - } - - addAutosaveTurnsSelectBox(innerTable) + addAutosaveTurnsSelectBox() // at the moment the notification service only exists on Android if (Gdx.app.type == Application.ApplicationType.Android) { - innerTable.add("Multiplayer options".toLabel(fontSize = 24)).colspan(2).padTop(20f).row() + addHeader("Multiplayer options") - innerTable.add("Enable out-of-game turn notifications".toLabel()) - addButton(innerTable, if (settings.multiplayerTurnCheckerEnabled) "Yes" else "No") { - settings.multiplayerTurnCheckerEnabled = !settings.multiplayerTurnCheckerEnabled - update() + addYesNoRow ("Enable out-of-game turn notifications", settings.multiplayerTurnCheckerEnabled) { + settings.multiplayerTurnCheckerEnabled = it } - if (settings.multiplayerTurnCheckerEnabled) { - addMultiplayerTurnCheckerDelayBox(innerTable) - innerTable.add("Show persistent notification for turn notifier service".toLabel()) - addButton(innerTable, if (settings.multiplayerTurnCheckerPersistentNotificationEnabled) "Yes" else "No") { - settings.multiplayerTurnCheckerPersistentNotificationEnabled = !settings.multiplayerTurnCheckerPersistentNotificationEnabled - update() + if (settings.multiplayerTurnCheckerEnabled) { + addMultiplayerTurnCheckerDelayBox() + + addYesNoRow ("Show persistent notification for turn notifier service", settings.multiplayerTurnCheckerPersistentNotificationEnabled) { + settings.multiplayerTurnCheckerPersistentNotificationEnabled = it } } } - innerTable.add("Other options".toLabel(fontSize = 24)).colspan(2).padTop(20f).row() - - - addSoundEffectsVolumeSlider(innerTable) - addMusicVolumeSlider(innerTable) + addHeader("Other options") + addSoundEffectsVolumeSlider() + addMusicVolumeSlider() if(Gdx.app.type==Application.ApplicationType.Desktop) { val generateTranslationsButton = TextButton("Generate translation files".tr(), CameraStageBaseScreen.skin) @@ -167,51 +159,31 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) innerTable.add("Version".toLabel()).pad(10f) innerTable.add(UncivGame.Current.version.toLabel()).pad(10f).row() - - - val scrollPane = ScrollPane(innerTable, skin) - scrollPane.setOverscroll(false, false) - scrollPane.fadeScrollBars = false - scrollPane.setScrollingDisabled(true, false) - add(scrollPane).maxHeight(screen.stage.height * 0.6f).row() - - addCloseButton() - - pack() // Needed to show the background. - center(UncivGame.Current.worldScreen.stage) - UncivGame.Current.worldScreen.shouldUpdate = true } - private fun addButton(table: Table, text: String, action: () -> Unit): Cell { - val button = TextButton(text.tr(), skin).apply { color = ImageGetter.getBlue() } - button.onClick(action) - return table.add(button).apply { row() } - } - - - private fun addSoundEffectsVolumeSlider(innerTable: Table) { + private fun addSoundEffectsVolumeSlider() { innerTable.add("Sound effects volume".tr()) val soundEffectsVolumeSlider = Slider(0f, 1.0f, 0.1f, false, skin) - soundEffectsVolumeSlider.value = UncivGame.Current.settings.soundEffectsVolume + soundEffectsVolumeSlider.value = settings.soundEffectsVolume soundEffectsVolumeSlider.onChange { - UncivGame.Current.settings.soundEffectsVolume = soundEffectsVolumeSlider.value - UncivGame.Current.settings.save() + settings.soundEffectsVolume = soundEffectsVolumeSlider.value + settings.save() Sounds.play(UncivSound.Click) } innerTable.add(soundEffectsVolumeSlider).pad(10f).row() } - private fun addMusicVolumeSlider(innerTable: Table) { + private fun addMusicVolumeSlider() { val musicLocation = Gdx.files.local(UncivGame.Current.musicLocation) if (musicLocation.exists()) { innerTable.add("Music volume".tr()) val musicVolumeSlider = Slider(0f, 1.0f, 0.1f, false, skin) - musicVolumeSlider.value = UncivGame.Current.settings.musicVolume + musicVolumeSlider.value = settings.musicVolume musicVolumeSlider.onChange { - UncivGame.Current.settings.musicVolume = musicVolumeSlider.value - UncivGame.Current.settings.save() + settings.musicVolume = musicVolumeSlider.value + settings.save() val music = UncivGame.Current.music if (music == null) // restart music, if it was off at the app start @@ -235,7 +207,7 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) errorTable.add("Downloading...".toLabel()) val file = DropBox.downloadFile("/Music/thatched-villagers.mp3") musicLocation.write(file, false) - update() + rebuildInnerTable() UncivGame.Current.startMusic() } catch (ex: Exception) { errorTable.clear() @@ -246,26 +218,23 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) } } - private fun addResolutionSelectBox(innerTable: Table) { + private fun addResolutionSelectBox() { innerTable.add("Resolution".toLabel()) val resolutionSelectBox = SelectBox(skin) val resolutionArray = Array() resolutionArray.addAll("750x500", "900x600", "1050x700", "1200x800", "1500x1000") resolutionSelectBox.items = resolutionArray - resolutionSelectBox.selected = UncivGame.Current.settings.resolution + resolutionSelectBox.selected = settings.resolution innerTable.add(resolutionSelectBox).minWidth(240f).pad(10f).row() resolutionSelectBox.onChange { - UncivGame.Current.settings.resolution = resolutionSelectBox.selected - UncivGame.Current.settings.save() - UncivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) - UncivGame.Current.setWorldScreen() - WorldScreenOptionsPopup(UncivGame.Current.worldScreen).open() + settings.resolution = resolutionSelectBox.selected + reloadWorldAndOptions() } } - private fun addTileSetSelectBox(innerTable: Table) { + private fun addTileSetSelectBox() { innerTable.add("Tileset".toLabel()) val tileSetSelectBox = SelectBox(skin) @@ -274,55 +243,50 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) .map { it.name.split("/")[1] }.distinct() for (tileset in tileSets) tileSetArray.add(tileset) tileSetSelectBox.items = tileSetArray - tileSetSelectBox.selected = UncivGame.Current.settings.tileSet + tileSetSelectBox.selected = settings.tileSet innerTable.add(tileSetSelectBox).minWidth(240f).pad(10f).row() tileSetSelectBox.onChange { - UncivGame.Current.settings.tileSet = tileSetSelectBox.selected - UncivGame.Current.settings.save() - UncivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) - UncivGame.Current.setWorldScreen() - WorldScreenOptionsPopup(UncivGame.Current.worldScreen).open() + settings.tileSet = tileSetSelectBox.selected + reloadWorldAndOptions() } } - private fun addAutosaveTurnsSelectBox(innerTable: Table) { + private fun addAutosaveTurnsSelectBox() { innerTable.add("Turns between autosaves".toLabel()) val autosaveTurnsSelectBox = SelectBox(skin) val autosaveTurnsArray = Array() autosaveTurnsArray.addAll(1, 2, 5, 10) autosaveTurnsSelectBox.items = autosaveTurnsArray - autosaveTurnsSelectBox.selected = UncivGame.Current.settings.turnsBetweenAutosaves + autosaveTurnsSelectBox.selected = settings.turnsBetweenAutosaves innerTable.add(autosaveTurnsSelectBox).pad(10f).row() autosaveTurnsSelectBox.onChange { - UncivGame.Current.settings.turnsBetweenAutosaves = autosaveTurnsSelectBox.selected - UncivGame.Current.settings.save() - update() + settings.turnsBetweenAutosaves = autosaveTurnsSelectBox.selected + settings.save() } } - private fun addMultiplayerTurnCheckerDelayBox(innerTable: Table) { + private fun addMultiplayerTurnCheckerDelayBox() { innerTable.add("Time between turn checks out-of-game (in minutes)".toLabel()) val checkDelaySelectBox = SelectBox(skin) val possibleDelaysArray = Array() possibleDelaysArray.addAll(1, 2, 5, 15) checkDelaySelectBox.items = possibleDelaysArray - checkDelaySelectBox.selected = UncivGame.Current.settings.multiplayerTurnCheckerDelayInMinutes + checkDelaySelectBox.selected = settings.multiplayerTurnCheckerDelayInMinutes innerTable.add(checkDelaySelectBox).pad(10f).row() checkDelaySelectBox.onChange { - UncivGame.Current.settings.multiplayerTurnCheckerDelayInMinutes = checkDelaySelectBox.selected - UncivGame.Current.settings.save() - update() + settings.multiplayerTurnCheckerDelayInMinutes = checkDelaySelectBox.selected + settings.save() } } - private fun addLanguageSelectBox(innerTable: Table) { + private fun addLanguageSelectBox() { val languageSelectBox = SelectBox(skin) val languageArray = Array() UncivGame.Current.translations.percentCompleteOfLanguages @@ -333,27 +297,49 @@ class WorldScreenOptionsPopup(val worldScreen:WorldScreen) : Popup(worldScreen) innerTable.add("Language".toLabel()) languageSelectBox.items = languageArray - val matchingLanguage = languageArray.firstOrNull { it.language == UncivGame.Current.settings.language } + 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() languageSelectBox.onChange { - // Sometimes the "changed" is triggered even when we didn't choose something that isn't the + // Sometimes the "changed" is triggered even when we didn't choose something selectedLanguage = languageSelectBox.selected.language - if (selectedLanguage != UncivGame.Current.settings.language) + if (selectedLanguage != settings.language) selectLanguage() } } - fun selectLanguage() { - UncivGame.Current.settings.language = selectedLanguage - UncivGame.Current.settings.save() - + private fun selectLanguage() { + settings.language = selectedLanguage UncivGame.Current.translations.tryReadTranslationForCurrentLanguage() CameraStageBaseScreen.resetFonts() // to load chinese characters if necessary - UncivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) - UncivGame.Current.setWorldScreen() - WorldScreenOptionsPopup(UncivGame.Current.worldScreen).open() + reloadWorldAndOptions() } -} \ No newline at end of file + +} + +/* + This TextButton subclass helps to keep looks and behaviour of our Yes/No + in one place, but it also helps keeping context for those action lambdas. + + Usage: YesNoButton(someSetting: Boolean, skin) { someSetting = it; sideEffects() } + */ +private fun Boolean.toYesNo(): String = (if (this) "Yes" else "No").tr() +private class YesNoButton(initialValue: Boolean, skin: Skin, action: (Boolean) -> Unit) + : TextButton (initialValue.toYesNo(), skin ) { + + var value = initialValue + private set(value) { + field = value + setText(value.toYesNo()) + } + + init { + color = ImageGetter.getBlue() + onClick { + value = !value + action.invoke(value) + } + } +}