WASD listener out of WorldScreen and add to map editor (#8947)

This commit is contained in:
SomeTroglodyte
2023-03-18 18:27:25 +01:00
committed by GitHub
parent 9b9620b681
commit 88d329a51d
4 changed files with 94 additions and 79 deletions

View File

@ -0,0 +1,74 @@
package com.unciv.ui.components
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction
import com.badlogic.gdx.scenes.scene2d.ui.TextField
class KeyboardPanningListener(
private val mapHolder: ZoomableScrollPane,
allowWASD: Boolean,
) : InputListener() {
private val pressedKeys = mutableSetOf<Int>()
private var infiniteAction: RepeatAction? = null
private val amountToMove = 6 / mapHolder.scaleX
private val allowedKeys =
setOf(Input.Keys.UP, Input.Keys.DOWN, Input.Keys.LEFT, Input.Keys.RIGHT) + (
if (allowWASD) setOf(Input.Keys.W, Input.Keys.S, Input.Keys.A, Input.Keys.D)
else setOf()
)
override fun keyDown(event: InputEvent, keycode: Int): Boolean {
if (event.target is TextField) return false
if (keycode !in allowedKeys) return false
// Without the following Ctrl-S would leave WASD map scrolling stuck
// Might be obsolete with keyboard shortcut refactoring
if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT)) return false
if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT)) return false
pressedKeys.add(keycode)
startLoop()
return true
}
override fun keyUp(event: InputEvent?, keycode: Int): Boolean {
if (keycode !in allowedKeys) return false
pressedKeys.remove(keycode)
if (pressedKeys.isEmpty()) stopLoop()
return true
}
private fun startLoop() {
if (infiniteAction != null) return
// create a copy of the action, because removeAction() will destroy this instance
infiniteAction = Actions.forever(
Actions.delay(
0.01f,
Actions.run { whileKeyPressedLoop() })
)
mapHolder.addAction(infiniteAction)
}
private fun stopLoop() {
if (infiniteAction == null) return
// stop the loop otherwise it keeps going even after removal
infiniteAction?.finish()
// remove and nil the action
mapHolder.removeAction(infiniteAction)
infiniteAction = null
}
private fun whileKeyPressedLoop() {
for (keycode in pressedKeys) {
when (keycode) {
Input.Keys.W, Input.Keys.UP -> mapHolder.scrollY = mapHolder.restrictY(-amountToMove)
Input.Keys.S, Input.Keys.DOWN -> mapHolder.scrollY = mapHolder.restrictY(amountToMove)
Input.Keys.A, Input.Keys.LEFT -> mapHolder.scrollX = mapHolder.restrictX(amountToMove)
Input.Keys.D, Input.Keys.RIGHT -> mapHolder.scrollX = mapHolder.restrictX(-amountToMove)
}
}
mapHolder.updateVisualScroll()
}
}

View File

@ -22,9 +22,7 @@ import com.unciv.models.metadata.GameSetupInfo
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.RulesetCache import com.unciv.models.ruleset.RulesetCache
import com.unciv.ui.components.AutoScrollPane import com.unciv.ui.components.AutoScrollPane
import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.KeyCharAndCode
import com.unciv.ui.screens.basescreen.RecreateOnResize
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.center
import com.unciv.ui.components.extensions.keyShortcuts import com.unciv.ui.components.extensions.keyShortcuts
@ -33,21 +31,24 @@ import com.unciv.ui.components.extensions.surroundWithCircle
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
import com.unciv.ui.components.tilegroups.TileGroupMap import com.unciv.ui.components.tilegroups.TileGroupMap
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen
import com.unciv.ui.screens.multiplayerscreens.MultiplayerScreen
import com.unciv.ui.popups.Popup import com.unciv.ui.popups.Popup
import com.unciv.ui.popups.ToastPopup import com.unciv.ui.popups.ToastPopup
import com.unciv.ui.popups.closeAllPopups import com.unciv.ui.popups.closeAllPopups
import com.unciv.ui.popups.hasOpenPopups import com.unciv.ui.popups.hasOpenPopups
import com.unciv.ui.popups.popups import com.unciv.ui.popups.popups
import com.unciv.ui.screens.savescreens.LoadGameScreen import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.screens.savescreens.QuickSave import com.unciv.ui.screens.basescreen.RecreateOnResize
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen
import com.unciv.ui.screens.mainmenuscreen.EasterEggRulesets.modifyForEasterEgg
import com.unciv.ui.screens.mapeditorscreen.EditorMapHolder
import com.unciv.ui.screens.mapeditorscreen.MapEditorScreen
import com.unciv.ui.screens.multiplayerscreens.MultiplayerScreen
import com.unciv.ui.screens.newgamescreen.NewGameScreen import com.unciv.ui.screens.newgamescreen.NewGameScreen
import com.unciv.ui.screens.pickerscreens.ModManagementScreen import com.unciv.ui.screens.pickerscreens.ModManagementScreen
import com.unciv.ui.screens.worldscreen.mainmenu.WorldScreenMenuPopup import com.unciv.ui.screens.savescreens.LoadGameScreen
import com.unciv.ui.screens.mainmenuscreen.EasterEggRulesets.modifyForEasterEgg import com.unciv.ui.screens.savescreens.QuickSave
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.ui.screens.worldscreen.mainmenu.WorldScreenMenuPopup
import com.unciv.utils.concurrency.Concurrency import com.unciv.utils.concurrency.Concurrency
import com.unciv.utils.concurrency.launchOnGLThread import com.unciv.utils.concurrency.launchOnGLThread
import kotlin.math.min import kotlin.math.min
@ -132,7 +133,7 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize {
launchOnGLThread { // for GL context launchOnGLThread { // for GL context
ImageGetter.setNewRuleset(mapRuleset) ImageGetter.setNewRuleset(mapRuleset)
val mapHolder = com.unciv.ui.screens.mapeditorscreen.EditorMapHolder( val mapHolder = EditorMapHolder(
this@MainMenuScreen, this@MainMenuScreen,
newMap newMap
) {} ) {}

View File

@ -18,6 +18,7 @@ import com.unciv.ui.popups.ConfirmPopup
import com.unciv.ui.components.tilegroups.TileGroup import com.unciv.ui.components.tilegroups.TileGroup
import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.KeyCharAndCode
import com.unciv.ui.components.KeyboardPanningListener
import com.unciv.ui.screens.basescreen.RecreateOnResize import com.unciv.ui.screens.basescreen.RecreateOnResize
import com.unciv.ui.screens.worldscreen.ZoomButtonPair import com.unciv.ui.screens.worldscreen.ZoomButtonPair
@ -64,7 +65,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
var tileMatchFuzziness = MapEditorOptionsTab.TileMatchFuzziness.CompleteMatch var tileMatchFuzziness = MapEditorOptionsTab.TileMatchFuzziness.CompleteMatch
// UI // UI
var mapHolder: com.unciv.ui.screens.mapeditorscreen.EditorMapHolder var mapHolder: EditorMapHolder
val tabs: MapEditorMainTabs val tabs: MapEditorMainTabs
var tileClickHandler: ((tile: Tile)->Unit)? = null var tileClickHandler: ((tile: Tile)->Unit)? = null
private var zoomController: ZoomButtonPair? = null private var zoomController: ZoomButtonPair? = null
@ -117,7 +118,7 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
fun getToolsWidth() = stage.width * 0.4f fun getToolsWidth() = stage.width * 0.4f
private fun newMapHolder(): com.unciv.ui.screens.mapeditorscreen.EditorMapHolder { private fun newMapHolder(): EditorMapHolder {
ImageGetter.setNewRuleset(ruleset) ImageGetter.setNewRuleset(ruleset)
// setNewRuleset is missing some graphics - those "EmojiIcons"&co already rendered as font characters // setNewRuleset is missing some graphics - those "EmojiIcons"&co already rendered as font characters
// so to get the "Water" vs "Gold" icons when switching between Deciv and Vanilla to render properly, // so to get the "Water" vs "Gold" icons when switching between Deciv and Vanilla to render properly,
@ -130,9 +131,12 @@ class MapEditorScreen(map: TileMap? = null): BaseScreen(), RecreateOnResize {
tileMap.setStartingLocationsTransients() tileMap.setStartingLocationsTransients()
UncivGame.Current.translations.translationActiveMods = ruleset.mods UncivGame.Current.translations.translationActiveMods = ruleset.mods
val result = com.unciv.ui.screens.mapeditorscreen.EditorMapHolder(this, tileMap) { val result = EditorMapHolder(this, tileMap) {
tileClickHandler?.invoke(it) tileClickHandler?.invoke(it)
} }
for (oldPanningListener in stage.root.listeners.filterIsInstance<KeyboardPanningListener>())
stage.removeListener(oldPanningListener) // otherwise they accumulate
stage.addListener(KeyboardPanningListener(result, allowWASD = false))
stage.root.addActorAt(0, result) stage.root.addActorAt(0, result)
stage.scrollFocus = result stage.scrollFocus = result

View File

@ -4,13 +4,8 @@ import com.badlogic.gdx.Application
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction
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.TextField
import com.badlogic.gdx.utils.Align import com.badlogic.gdx.utils.Align
import com.unciv.Constants import com.unciv.Constants
import com.unciv.UncivGame import com.unciv.UncivGame
@ -27,8 +22,9 @@ import com.unciv.logic.trade.TradeEvaluation
import com.unciv.models.TutorialTrigger import com.unciv.models.TutorialTrigger
import com.unciv.models.ruleset.tile.ResourceType import com.unciv.models.ruleset.tile.ResourceType
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.components.KeyboardBinding
import com.unciv.ui.components.KeyCharAndCode import com.unciv.ui.components.KeyCharAndCode
import com.unciv.ui.components.KeyboardBinding
import com.unciv.ui.components.KeyboardPanningListener
import com.unciv.ui.components.extensions.centerX import com.unciv.ui.components.extensions.centerX
import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.darken
import com.unciv.ui.components.extensions.isEnabled import com.unciv.ui.components.extensions.isEnabled
@ -277,67 +273,7 @@ class WorldScreen(
} }
private fun addKeyboardListener() { private fun addKeyboardListener() {
stage.addListener( stage.addListener(KeyboardPanningListener(mapHolder, allowWASD = true))
object : InputListener() {
private val pressedKeys = mutableSetOf<Int>()
private var infiniteAction: RepeatAction? = null
private val amountToMove = 6 / mapHolder.scaleX
private val ALLOWED_KEYS = setOf(Input.Keys.W, Input.Keys.S, Input.Keys.A, Input.Keys.D,
Input.Keys.UP, Input.Keys.DOWN, Input.Keys.LEFT, Input.Keys.RIGHT)
override fun keyDown(event: InputEvent, keycode: Int): Boolean {
if (event.target !is TextField) {
if (keycode !in ALLOWED_KEYS) return false
// Without the following Ctrl-S would leave WASD map scrolling stuck
// Might be obsolete with keyboard shortcut refactoring
if (Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT) || Gdx.input.isKeyPressed(
Input.Keys.CONTROL_RIGHT
)
) return false
pressedKeys.add(keycode)
if (infiniteAction == null) {
// create a copy of the action, because removeAction() will destroy this instance
infiniteAction = Actions.forever(
Actions.delay(
0.01f,
Actions.run { whileKeyPressedLoop() })
)
mapHolder.addAction(infiniteAction)
}
}
return true
}
fun whileKeyPressedLoop() {
for (keycode in pressedKeys) {
when (keycode) {
Input.Keys.W, Input.Keys.UP -> mapHolder.scrollY = mapHolder.restrictY(-amountToMove)
Input.Keys.S, Input.Keys.DOWN -> mapHolder.scrollY = mapHolder.restrictY(amountToMove)
Input.Keys.A, Input.Keys.LEFT -> mapHolder.scrollX = mapHolder.restrictX(amountToMove)
Input.Keys.D, Input.Keys.RIGHT -> mapHolder.scrollX = mapHolder.restrictX(-amountToMove)
}
}
mapHolder.updateVisualScroll()
}
override fun keyUp(event: InputEvent?, keycode: Int): Boolean {
if (keycode !in ALLOWED_KEYS) return false
pressedKeys.remove(keycode)
if (infiniteAction != null && pressedKeys.isEmpty()) {
// stop the loop otherwise it keeps going even after removal
infiniteAction?.finish()
// remove and nil the action
mapHolder.removeAction(infiniteAction)
infiniteAction = null
}
return true
}
}
)
} }
private suspend fun loadLatestMultiplayerState(): Unit = coroutineScope { private suspend fun loadLatestMultiplayerState(): Unit = coroutineScope {