From e514df5b82b88e8cdb8e2b7fd6dce3b6a4004478 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Thu, 22 Jul 2021 23:02:20 +0200 Subject: [PATCH] Removed Char-only restriction in keyboard support for unit actions, remap a few keys, key tooltips for non-ascii keys (#4606) --- .../com/unciv/ui/utils/KeyPressDispatcher.kt | 18 +++++++-------- core/src/com/unciv/ui/utils/UncivTooltip.kt | 19 +++++++++++----- .../ui/worldscreen/unit/UnitActionsTable.kt | 22 ++++++++++--------- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/core/src/com/unciv/ui/utils/KeyPressDispatcher.kt b/core/src/com/unciv/ui/utils/KeyPressDispatcher.kt index 70d2e0ccec..8a10be87d5 100644 --- a/core/src/com/unciv/ui/utils/KeyPressDispatcher.kt +++ b/core/src/com/unciv/ui/utils/KeyPressDispatcher.kt @@ -35,9 +35,14 @@ data class KeyCharAndCode(val char: Char, val code: Int) { // From Kotlin 1.5? on the Ctrl- line will need Char(char.code+64) // see https://github.com/Kotlin/KEEP/blob/master/proposals/stdlib/char-int-conversions.md override fun toString(): String { - // debug helper + // debug helper, but also used for tooltips + fun fixedKeysToString(code: Int) = when (code) { + Input.Keys.BACKSPACE -> "Backspace" // Gdx displaying this as "Delete" is Bullshit! + Input.Keys.FORWARD_DEL -> "Del" // Likewise + else -> Input.Keys.toString(code) + } return when { - char == Char.MIN_VALUE -> Input.Keys.toString(code) + char == Char.MIN_VALUE -> fixedKeysToString(code) this == ESC -> "ESC" char < ' ' -> "Ctrl-" + (char.toInt()+64).toChar() else -> "\"$char\"" @@ -51,8 +56,8 @@ data class KeyCharAndCode(val char: Char, val code: Int) { val RETURN = KeyCharAndCode(Input.Keys.ENTER) val NUMPAD_ENTER = KeyCharAndCode(Input.Keys.NUMPAD_ENTER) val SPACE = KeyCharAndCode(Input.Keys.SPACE) - val DEL = KeyCharAndCode(Input.Keys.DEL) - val FORWARD_DEL = KeyCharAndCode(Input.Keys.FORWARD_DEL) // this is what I see for both 'Del' keys + val BACKSPACE= KeyCharAndCode(Input.Keys.BACKSPACE) + val DEL = KeyCharAndCode(Input.Keys.FORWARD_DEL) // Gdx "DEL" is just plain wrong! /** Guaranteed to be ignored by [KeyPressDispatcher.set] and never to be generated for an actual event, used as fallback to ensure no action is taken */ val UNKNOWN = KeyCharAndCode(Input.Keys.UNKNOWN) @@ -116,9 +121,6 @@ class KeyPressDispatcher(val name: String? = null) : HashMap Unit)? { @@ -128,8 +130,6 @@ class KeyPressDispatcher(val name: String? = null) : HashMap( addListener(UncivTooltip(this, labelWithBackground, forceContentSize = Vector2(size * widthHeightRatio, size), - offset = Vector2(size/4, 0f) + offset = Vector2(-size/4, size/4), + tipAlign = Align.top )) } @@ -196,10 +198,17 @@ class UncivTooltip ( addTooltip((if (char in "Ii") 'i' else char.toUpperCase()).toString(), size, always) } -/* unused - template in case we need it - problem: how exactly to handle translation? + /** + * Add a [Label]-based Tooltip for a keyboard binding with a rounded-corner background to a [Table] or other [Group]. + * + * Tip is positioned over top right corner, slightly overshooting the receiver widget. + * + * @param size _Vertical_ size of the entire Tooltip including background + * @param always override requirement: presence of physical keyboard + */ fun Group.addTooltip(key: KeyCharAndCode, size: Float = 26f, always: Boolean = false) { - addTooltip(key.toString(), size, always) + if (key != KeyCharAndCode.UNKNOWN) + addTooltip(key.toString().tr(), size, always) } -*/ } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt index b5a170b766..65611f0fe9 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActionsTable.kt @@ -1,10 +1,10 @@ package com.unciv.ui.worldscreen.unit +import com.badlogic.gdx.Input import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.ui.Button import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.UncivGame import com.unciv.logic.map.MapUnit @@ -17,7 +17,9 @@ import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip import com.unciv.ui.worldscreen.WorldScreen import kotlin.concurrent.thread -private data class UnitIconAndKey(val Icon: Actor, var key: Char = Char.MIN_VALUE) +private data class UnitIconAndKey(val icon: Actor, var key: KeyCharAndCode = KeyCharAndCode.UNKNOWN) { + constructor(icon: Actor, key: Char) : this(icon, KeyCharAndCode(key)) +} class UnitActionsTable(val worldScreen: WorldScreen) : Table() { @@ -47,12 +49,12 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() { "Fortify until healed" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Shield").apply { color = Color.BLACK }, 'h') // Move unit is not actually used anywhere "Move unit" -> return UnitIconAndKey(ImageGetter.getStatIcon("Movement")) - "Stop movement" -> return UnitIconAndKey(ImageGetter.getStatIcon("Movement").apply { color = Color.RED }, '.') + "Stop movement" -> return UnitIconAndKey(ImageGetter.getStatIcon("Movement").apply { color = Color.RED }, KeyCharAndCode(Input.Keys.END)) "Swap units" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Swap"), 'y') "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') + "Stop automation" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), KeyCharAndCode(Input.Keys.END)) "Found city" -> return UnitIconAndKey(ImageGetter.getUnitIcon(Constants.settler), 'c') "Hurry Research" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Scientist"), 'g') "Start Golden Age" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Great Artist"), 'g') @@ -64,10 +66,10 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() { "Explore" -> return UnitIconAndKey(ImageGetter.getUnitIcon("Scout"), 'x') "Stop exploration" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Stop"), 'x') "Pillage" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Pillage"), 'p') - "Disband unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/DisbandUnit")) + "Disband unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/DisbandUnit"), KeyCharAndCode.DEL) "Gift unit" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Present")) - "Show more" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/ArrowRight"), 'm') - "Back" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/ArrowLeft")) + "Show more" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/ArrowRight"), KeyCharAndCode(Input.Keys.PAGE_DOWN)) + "Back" -> return UnitIconAndKey(ImageGetter.getImage("OtherIcons/ArrowLeft"), KeyCharAndCode(Input.Keys.PAGE_UP)) else -> { // If the unit has been fortifying for some turns if (unitAction.startsWith("Fortification")) return UnitIconAndKey(ImageGetter.getImage("OtherIcons/Shield")) @@ -91,10 +93,10 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() { val iconAndKey = getIconAndKeyForUnitAction(unitAction.title) // If peripheral keyboard not detected, hotkeys will not be displayed - if (!keyboardAvailable) { iconAndKey.key = Char.MIN_VALUE } + if (!keyboardAvailable) { iconAndKey.key = KeyCharAndCode.UNKNOWN } val actionButton = Button(CameraStageBaseScreen.skin) - actionButton.add(iconAndKey.Icon).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) actionButton.addTooltip(iconAndKey.key) @@ -106,7 +108,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() { if (unitAction.action == null) actionButton.disable() else { actionButton.onClick(unitAction.uncivSound, action) - if (iconAndKey.key != Char.MIN_VALUE) + if (iconAndKey.key != KeyCharAndCode.UNKNOWN) worldScreen.keyPressDispatcher[iconAndKey.key] = { thread(name = "Sound") { Sounds.play(unitAction.uncivSound) } action()