diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index 2855955575..8f025269bc 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -64,6 +64,9 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { private var backButtonListener : InputListener + // An initialized val always turned out to illegally be null... + lateinit var keyPressDispatcher: HashMap Unit)> + init { topBar.setPosition(0f, stage.height - topBar.height) topBar.width = stage.width @@ -110,7 +113,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { stage.addActor(unitActionsTable) - createNextTurnButton() // needs civ table to be positioned + // still a zombie: createNextTurnButton() // needs civ table to be positioned val tileToCenterOn: Vector2 = when { @@ -142,6 +145,11 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { shouldUpdate = true } + private fun cleanupKeyDispatcher() { + val delKeys = keyPressDispatcher.keys.filter { it!=' ' && it!='n' } + delKeys.forEach { keyPressDispatcher.remove(it) } + } + private fun addKeyboardListener() { stage.addListener( object : InputListener() { @@ -187,6 +195,17 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { } return true } + + override fun keyTyped(event: InputEvent?, character: Char): Boolean { + if (character.toLowerCase() in keyPressDispatcher && !hasOpenPopups()) { + //try-catch mainly for debugging. Breakpoints in the vicinity can make the event fire twice in rapid succession, second time the context can be invalid + try { + keyPressDispatcher[character.toLowerCase()]?.invoke() + } catch (ex: Exception) {} + return true + } + return super.keyTyped(event, character) + } } ) } @@ -244,6 +263,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { } minimapWrapper.update(viewingCiv) + cleanupKeyDispatcher() unitActionsTable.update(bottomUnitTable.selectedUnit) unitActionsTable.y = bottomUnitTable.height @@ -398,7 +418,11 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() { val nextTurnButton = TextButton("", skin) // text is set in update() nextTurnButton.label.setFontSize(30) nextTurnButton.labelCell.pad(10f) - nextTurnButton.onClick { nextTurnAction() } + val nextTurnActionWrapped = { nextTurnAction() } + nextTurnButton.onClick (nextTurnActionWrapped) + if (!::keyPressDispatcher.isInitialized) keyPressDispatcher = hashMapOf() + keyPressDispatcher[' '] = nextTurnActionWrapped + keyPressDispatcher['n'] = nextTurnActionWrapped return nextTurnButton } diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt index 83b235ce9f..0ffd474fca 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt @@ -2,9 +2,12 @@ package com.unciv.ui.worldscreen.unit import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.InputEvent import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.Button +import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.map.MapUnit @@ -12,48 +15,60 @@ import com.unciv.models.UnitAction import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen +private data class UnitIconAndKey (val Icon: Actor, val key: Char = 0.toChar()) +class UnitActionButtonOnHoverListener(private val item: Actor, private val keyLabel: Label) : ClickListener() { + override fun enter(event: InputEvent, x: Float, y: Float, pointer: Int, fromActor: Actor?) { + super.enter(event, x, y, pointer, fromActor) + keyLabel.isVisible = true + } + override fun exit(event: InputEvent, x: Float, y: Float, pointer: Int, toActor: Actor?) { + super.exit(event, x, y, pointer, toActor) + keyLabel.isVisible = false + } +} + class UnitActionsTable(val worldScreen: WorldScreen) : Table(){ init { touchable = Touchable.enabled } - private fun getIconForUnitAction(unitAction:String): Actor { + private fun getIconAnKeyForUnitAction(unitAction:String): UnitIconAndKey { when { unitAction.startsWith("Upgrade to") -> { // Regexplaination: start with a [, take as many non-] chars as you can, until you reach a ]. // What you find between the first [ and the first ] that comes after it, will be group no. 1 val unitToUpgradeTo = Regex("""Upgrade to \[([^\]]*)\]""").find(unitAction)!!.groups[1]!!.value - return ImageGetter.getUnitIcon(unitToUpgradeTo) + return UnitIconAndKey(ImageGetter.getUnitIcon(unitToUpgradeTo), 'u') } - unitAction.startsWith("Sleep") -> return ImageGetter.getImage("OtherIcons/Sleep") - unitAction.startsWith("Fortify") -> return ImageGetter.getImage("OtherIcons/Shield").apply { color= Color.BLACK } + unitAction.startsWith("Sleep") -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Sleep"),'f') + unitAction.startsWith("Fortify") -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Shield").apply { color= Color.BLACK },'f') else -> when(unitAction){ - "Move unit" -> return ImageGetter.getStatIcon("Movement") - "Stop movement"-> return ImageGetter.getStatIcon("Movement").apply { color= Color.RED } - "Promote" -> return ImageGetter.getImage("OtherIcons/Star").apply { color= Color.GOLD } - "Construct improvement" -> return ImageGetter.getUnitIcon(Constants.worker) - "Automate" -> return ImageGetter.getUnitIcon("Great Engineer") - "Stop automation" -> return ImageGetter.getImage("OtherIcons/Stop") - "Found city" -> return ImageGetter.getUnitIcon(Constants.settler) - "Hurry Research" -> return ImageGetter.getUnitIcon("Great Scientist") - "Construct Academy" -> return ImageGetter.getImprovementIcon("Academy") - "Start Golden Age" -> return ImageGetter.getUnitIcon("Great Artist") - "Construct Landmark" -> return ImageGetter.getImprovementIcon("Landmark") - "Construct Citadel" -> return ImageGetter.getImprovementIcon("Citadel") - "Hurry Wonder" -> return ImageGetter.getUnitIcon("Great Engineer") - "Construct Manufactory" -> return ImageGetter.getImprovementIcon("Manufactory") - "Conduct Trade Mission" -> return ImageGetter.getUnitIcon("Great Merchant") - "Construct Customs House" -> return ImageGetter.getImprovementIcon("Customs house") - "Set up" -> return ImageGetter.getUnitIcon("Catapult") - "Disband unit" -> return ImageGetter.getImage("OtherIcons/DisbandUnit") - "Explore" -> return ImageGetter.getUnitIcon("Scout") - "Stop exploration" -> return ImageGetter.getImage("OtherIcons/Stop") - "Create Fishing Boats" -> return ImageGetter.getImprovementIcon("Fishing Boats") - "Create Oil well" -> return ImageGetter.getImprovementIcon("Oil well") - "Pillage" -> return ImageGetter.getImage("OtherIcons/Pillage") - "Construct road" -> return ImageGetter.getImprovementIcon("Road") - else -> return ImageGetter.getImage("OtherIcons/Star") + "Move unit" -> return UnitIconAndKey(ImageGetter.getStatIcon("Movement")) + "Stop movement"-> return UnitIconAndKey(ImageGetter.getStatIcon("Movement").apply { color= Color.RED }, '.') + "Promote" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Star").apply { color= Color.GOLD }, 'o') + "Construct improvement" -> return UnitIconAndKey(ImageGetter.getUnitIcon(Constants.worker),'i') + "Automate" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Engineer"), 'm') + "Stop automation" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), 'm') + "Found city" -> return UnitIconAndKey(ImageGetter.getUnitIcon(Constants.settler),'f') + "Hurry Research" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Scientist"), 'g') + "Construct Academy" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Academy"), 'i') + "Start Golden Age" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Artist"), 'g') + "Construct Landmark" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Landmark"), 'i') + "Construct Citadel" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Citadel"), 'i') + "Hurry Wonder" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Engineer"), 'g') + "Construct Manufactory" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Manufactory"), 'i') + "Conduct Trade Mission" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Merchant"), 'g') + "Construct Customs House" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Customs house"), 'i') + "Set up" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Catapult"), 't') + "Disband unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/DisbandUnit")) + "Explore" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Scout"), 'x') + "Stop exploration" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), 'x') + "Create Fishing Boats" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Fishing Boats"),'i') + "Create Oil well" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Oil well"),'i') + "Pillage" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Pillage"),'p') + "Construct road" -> return UnitIconAndKey(ImageGetter.getImprovementIcon("Road"),'r') + else -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Star")) } } } @@ -69,16 +84,28 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table(){ private fun getUnitActionButton(unitAction: UnitAction): Button { + val iconAndKey = getIconAnKeyForUnitAction(unitAction.title) val actionButton = Button(CameraStageBaseScreen.skin) - actionButton.add(getIconForUnitAction(unitAction.title)).size(20f).pad(5f) + actionButton.add(iconAndKey.Icon).size(20f).pad(5f) val fontColor = if(unitAction.isCurrentAction) Color.YELLOW else Color.WHITE actionButton.add(unitAction.title.toLabel(fontColor)).pad(5f) + if (iconAndKey.key != 0.toChar()) { + val keyLabel = "(${iconAndKey.key.toUpperCase()})".toLabel(Color.WHITE).apply { isVisible = false } + actionButton.add(keyLabel) + actionButton.addListener(UnitActionButtonOnHoverListener(actionButton, keyLabel)) + } actionButton.pack() - actionButton.onClick(unitAction.uncivSound) { + val action = { unitAction.action?.invoke() - UncivGame.Current.worldScreen.shouldUpdate=true + UncivGame.Current.worldScreen.shouldUpdate = true } if (unitAction.action == null) actionButton.disable() + else { + actionButton.onClick(unitAction.uncivSound,action) + if (iconAndKey.key != 0.toChar()) + worldScreen.keyPressDispatcher[iconAndKey.key] = action + } + return actionButton } } \ No newline at end of file