mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-07 14:02:48 +07:00
Key bindings - unit actions, world screen and grouped UI (#8986)
* Keyboard Bindings: Simpler Widget * Keyboard Bindings: Reset binding * Keyboard Bindings: Simpler Widget - revert opening feature * Keyboard Bindings Step 6: Unit Actions * Keyboard Bindings Step 7: Grouped UI * Keyboard Bindings Step 7: Grouped UI-TFW * Keyboard Bindings Step 6: Unit Actions - patch * Keyboard Bindings Step 9: World Screen * Keyboard Bindings - German * Keyboard Bindings: Fix merge errors * Keyboard Bindings: Tiny forgotten things * Merge fixes
This commit is contained in:
parent
e109848e28
commit
404a148cfb
@ -816,6 +816,7 @@ Enable display cutout (requires restart) = Aktiviere Bildschirmausschnitt (Neust
|
||||
## Keys tab
|
||||
Keys = Tastenzuordnung
|
||||
Please see the Tutorial. = Bitte schau dir das Tutorial an.
|
||||
Hit the desired key now = Drücke die gewünschte Taste
|
||||
|
||||
## Locate mod errors tab
|
||||
Locate mod errors = Mod-Probleme
|
||||
@ -2411,9 +2412,34 @@ You returned captured units to us = Ihr habt uns gefangene Einheiten zurückgege
|
||||
|
||||
#################### Lines from key bindings #######################
|
||||
|
||||
Unit Actions = Einheiten-Aktionen
|
||||
Popups = Dialoge
|
||||
Next Turn = Nächste Runde
|
||||
Next Turn Alternate = Nächste Runde Alternativ
|
||||
Empire Overview = Reichsübersicht
|
||||
Empire Overview Trades = Handels-Übersicht
|
||||
Empire Overview Units = Einheiten-Übersicht
|
||||
Empire Overview Politics = Politiken-Übersicht
|
||||
Social Policies = Sozialpolitiken
|
||||
Technology Tree = Technologie-Baum
|
||||
Empire Overview Notifications = Benachrichtigungen Historie
|
||||
Empire Overview Stats = Statistiken-Übersicht
|
||||
Empire Overview Resources = Ressourcen-Übersicht
|
||||
Quick Save = Schnellspeichern
|
||||
Quick Load = Schnellladen
|
||||
View Capital City = Hauptstadt zeigen
|
||||
Save Game = Spiel speichern
|
||||
Load Game = Spiel laden
|
||||
Quit Game = Spiel beenden
|
||||
Toggle UI = Oberfläche verstecken an/aus
|
||||
Toggle Resource Display = Ressourcen-Anzeige an/aus
|
||||
Toggle Yield Display = Ertrags-Anzeige an/aus
|
||||
Toggle Worked Tiles Display = Bewirtschaftet-Anzeige an/aus
|
||||
Toggle Movement Display = Bewegungspfeile an/aus
|
||||
Zoom In = Reinzoomen
|
||||
Zoom Out = Rauszoomen
|
||||
Transform = Transformieren
|
||||
Repair = Reparieren
|
||||
Confirm Dialog = Dialog bestätigen
|
||||
Cancel Dialog = Dialog ablehnen
|
||||
|
||||
@ -6399,11 +6425,11 @@ This is a work in progress. = Dies ist noch in Arbeit.
|
||||
For technical reasons, only direct keys or Ctrl-Letter combinations can be used. = Aus technischen Gründen können nur Direkttasten oder Strg-Buchstaben-Kombinationen verwendet werden.
|
||||
The Escape key is intentionally excluded from being reassigned. = Die Escape-Taste wird absichtlich von einer Neuzuweisung ausgeschlossen.
|
||||
Currently, there are no checks to prevent conflicting assignments. = Derzeit gibt es keine Prüfungen, um widersprüchliche Zuweisungen zu verhindern.
|
||||
Using the Keys page = Verwendung der Tasten-Seite
|
||||
Using the Keys page = Verwendung der Seite für Tastatur-Zuweisungen
|
||||
Each binding has a button with an image looking like this: = Jede Verknüpfung hat eine Schaltfläche mit einem Bild, das wie folgt aussieht:
|
||||
While hovering the mouse over the key button, you can press a desired key directly to assign it. = Wenn du mit der Maus über die Taste fährst, kannst du die gewünschte Taste direkt drücken, um sie zu belegen.
|
||||
Double-click the image to reset the binding to default. = Mit einem Doppelklick auf das Bild setzt du die Verknüpfung auf die Standardeinstellungen zurück.
|
||||
Bindings mapped to their default keys are displayed in gray, those reassigned by you in white. = Verknüpfungen, die den Standardtasten zugeordnet sind, werden grau angezeigt, die von dir neu zugewiesenen in weiß.
|
||||
While hovering the mouse over the key button, you can press a desired key directly to assign it. = Wenn du mit der Maus über die Schaltfläche fährst, kannst du die gewünschte Taste direkt drücken, um sie zuzuweisen.
|
||||
Double-click the image to reset the binding to default. = Mit einem Doppelklick auf das Bild setzt du die Zuweisung auf die Standardeinstellungen zurück.
|
||||
Bindings mapped to their default keys are displayed in gray, those reassigned by you in white. = Zuweisungen, die den Standardtasten zugeordnet sind, werden grau angezeigt, die von dir neu zugewiesenen in weiß.
|
||||
For discussion about missing entries, see the linked github issue. = Für Diskussionen über fehlende Einträge, siehe das verlinkte GitHub-Issue.
|
||||
|
||||
Welcome to the Civilopedia! = Willkommen in der Zivilopädie
|
||||
@ -6419,4 +6445,3 @@ However, it will reflect the mods you are playing! The combination of base rules
|
||||
If you opened the Civilopedia from the main menu, the "Ruleset" will be that of the last game you started. = Wenn du die Zivilopädie vom Hauptmenü öffnest, wird das "Regelwerk" des letzten gestarteten Spiels ausschlaggebend sein.
|
||||
Letters can select categories, and when there are multiple categories matching the same letter, you can press that repeatedly to cycle between these. = Buchstaben können Kategorien auswählen. Wenn mehrere Kategorien mit dem gleichen Buchstaben anfangen, kannst du den Buchstaben wiederholt drücken, um durch diese durchzuwechseln. (Aktuell werden die Buchstaben aus der englischen Version verwendet.)
|
||||
The arrow keys allow navigation as well - left/right for categories, up/down for entries. = Die Pfeiltasten können auch zur Navigation verwendet werden. - Links/rechts für Kategorien, hoch/runter für Einträge.
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
package com.unciv.models
|
||||
|
||||
import com.badlogic.gdx.Input
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.unciv.Constants
|
||||
import com.unciv.models.ruleset.unit.BaseUnit
|
||||
import com.unciv.models.translations.getPlaceholderParameters
|
||||
import com.unciv.ui.components.Fonts
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.input.KeyboardBinding
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
|
||||
|
||||
@ -81,7 +80,8 @@ class UpgradeUnitAction(
|
||||
*
|
||||
* @param value _default_ label to display, can be overridden in UnitAction instantiation
|
||||
* @param imageGetter optional lambda to get an Icon - `null` if icon is dependent on outside factors and needs special handling
|
||||
* @param key keyboard binding - can be a [KeyCharAndCode], a [Char], or omitted.
|
||||
* @param binding keyboard binding - omitting it will look up the KeyboardBinding of the same name (recommended)
|
||||
* @param isSkippingToNextUnit if "Auto Unit Cycle" setting and this bit are on, this action will skip to the next unit
|
||||
* @param uncivSound _default_ sound, can be overridden in UnitAction instantiation
|
||||
*/
|
||||
|
||||
@ -91,95 +91,94 @@ class UpgradeUnitAction(
|
||||
enum class UnitActionType(
|
||||
val value: String,
|
||||
val imageGetter: (()-> Actor)?,
|
||||
val key: KeyCharAndCode,
|
||||
binding: KeyboardBinding? = null,
|
||||
val isSkippingToNextUnit: Boolean = true,
|
||||
val uncivSound: UncivSound = UncivSound.Click
|
||||
) {
|
||||
SwapUnits("Swap units",
|
||||
{ ImageGetter.getUnitActionPortrait("Swap") }, 'y', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Swap") }, false),
|
||||
Automate("Automate",
|
||||
{ ImageGetter.getUnitActionPortrait("Automate") }, 'm'),
|
||||
{ ImageGetter.getUnitActionPortrait("Automate") }),
|
||||
StopAutomation("Stop automation",
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, 'm', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, false),
|
||||
StopMovement("Stop movement",
|
||||
{ ImageGetter.getUnitActionPortrait("StopMove") }, '.', false),
|
||||
{ ImageGetter.getUnitActionPortrait("StopMove") }, false),
|
||||
Sleep("Sleep",
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }, 'f'),
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }),
|
||||
SleepUntilHealed("Sleep until healed",
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }, 'h'),
|
||||
{ ImageGetter.getUnitActionPortrait("Sleep") }),
|
||||
Fortify("Fortify",
|
||||
{ ImageGetter.getUnitActionPortrait("Fortify") }, 'f', UncivSound.Fortify),
|
||||
{ ImageGetter.getUnitActionPortrait("Fortify") }, UncivSound.Fortify),
|
||||
FortifyUntilHealed("Fortify until healed",
|
||||
{ ImageGetter.getUnitActionPortrait("FortifyUntilHealed") }, 'h', UncivSound.Fortify),
|
||||
{ ImageGetter.getUnitActionPortrait("FortifyUntilHealed") }, UncivSound.Fortify),
|
||||
Explore("Explore",
|
||||
{ ImageGetter.getUnitActionPortrait("Explore") }, 'x'),
|
||||
{ ImageGetter.getUnitActionPortrait("Explore") }),
|
||||
StopExploration("Stop exploration",
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, 'x', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Stop") }, false),
|
||||
Promote("Promote",
|
||||
{ ImageGetter.getUnitActionPortrait("Promote") }, 'o', false, UncivSound.Promote),
|
||||
{ ImageGetter.getUnitActionPortrait("Promote") }, false, UncivSound.Promote),
|
||||
Upgrade("Upgrade",
|
||||
{ ImageGetter.getUnitActionPortrait("Upgrade") }, 'u', UncivSound.Upgrade),
|
||||
{ ImageGetter.getUnitActionPortrait("Upgrade") }, UncivSound.Upgrade),
|
||||
Transform("Transform",
|
||||
{ ImageGetter.getUnitActionPortrait("Transform") }, 'k', UncivSound.Upgrade),
|
||||
{ ImageGetter.getUnitActionPortrait("Transform") }, UncivSound.Upgrade),
|
||||
Pillage("Pillage",
|
||||
{ ImageGetter.getUnitActionPortrait("Pillage") }, 'p', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Pillage") }, false),
|
||||
Paradrop("Paradrop",
|
||||
{ ImageGetter.getUnitActionPortrait("Paradrop") }, 'p', false),
|
||||
{ ImageGetter.getUnitActionPortrait("Paradrop") }, false),
|
||||
AirSweep("Air Sweep",
|
||||
{ ImageGetter.getUnitActionPortrait("AirSweep") }, 'a', false),
|
||||
{ ImageGetter.getUnitActionPortrait("AirSweep") }, false),
|
||||
SetUp("Set up",
|
||||
{ ImageGetter.getUnitActionPortrait("SetUp") }, 't', false, UncivSound.Setup),
|
||||
{ ImageGetter.getUnitActionPortrait("SetUp") }, false, UncivSound.Setup),
|
||||
FoundCity("Found city",
|
||||
{ ImageGetter.getUnitActionPortrait("FoundCity") }, 'c', UncivSound.Silent),
|
||||
{ ImageGetter.getUnitActionPortrait("FoundCity") }, UncivSound.Silent),
|
||||
ConstructImprovement("Construct improvement",
|
||||
{ ImageGetter.getUnitActionPortrait("ConstructImprovement") }, 'i', false),
|
||||
{ ImageGetter.getUnitActionPortrait("ConstructImprovement") }, false),
|
||||
Repair(Constants.repair,
|
||||
{ ImageGetter.getUnitActionPortrait("Repair") }, 'r', UncivSound.Construction),
|
||||
{ ImageGetter.getUnitActionPortrait("Repair") }, UncivSound.Construction),
|
||||
Create("Create",
|
||||
null, 'i', false, UncivSound.Chimes),
|
||||
null, false, UncivSound.Chimes),
|
||||
HurryResearch("{Hurry Research} (${Fonts.death})",
|
||||
{ ImageGetter.getUnitActionPortrait("HurryResearch") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryResearch") }, UncivSound.Chimes),
|
||||
StartGoldenAge("Start Golden Age",
|
||||
{ ImageGetter.getUnitActionPortrait("StartGoldenAge") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("StartGoldenAge") }, UncivSound.Chimes),
|
||||
HurryWonder("{Hurry Wonder} (${Fonts.death})",
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, UncivSound.Chimes),
|
||||
HurryBuilding("{Hurry Construction} (${Fonts.death})",
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("HurryConstruction") }, UncivSound.Chimes),
|
||||
ConductTradeMission("{Conduct Trade Mission} (${Fonts.death})",
|
||||
{ ImageGetter.getUnitActionPortrait("ConductTradeMission") }, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("ConductTradeMission") }, UncivSound.Chimes),
|
||||
FoundReligion("Found a Religion",
|
||||
{ ImageGetter.getUnitActionPortrait("FoundReligion") }, 'g', UncivSound.Choir),
|
||||
{ ImageGetter.getUnitActionPortrait("FoundReligion") }, UncivSound.Choir),
|
||||
TriggerUnique("Trigger unique",
|
||||
{ ImageGetter.getUnitActionPortrait("Star") }, 'g', false, UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("Star") }, false, UncivSound.Chimes),
|
||||
SpreadReligion("Spread Religion",
|
||||
null, 'g', UncivSound.Choir),
|
||||
null, UncivSound.Choir),
|
||||
RemoveHeresy("Remove Heresy",
|
||||
{ ImageGetter.getUnitActionPortrait("RemoveHeresy") }, 'h', UncivSound.Fire),
|
||||
{ ImageGetter.getUnitActionPortrait("RemoveHeresy") }, UncivSound.Fire),
|
||||
EnhanceReligion("Enhance a Religion",
|
||||
{ ImageGetter.getUnitActionPortrait("EnhanceReligion") }, 'g', UncivSound.Choir),
|
||||
{ ImageGetter.getUnitActionPortrait("EnhanceReligion") }, UncivSound.Choir),
|
||||
DisbandUnit("Disband unit",
|
||||
{ ImageGetter.getUnitActionPortrait("DisbandUnit") }, KeyCharAndCode.DEL, false),
|
||||
{ ImageGetter.getUnitActionPortrait("DisbandUnit") }, false),
|
||||
GiftUnit("Gift unit",
|
||||
{ ImageGetter.getUnitActionPortrait("Present") }, UncivSound.Silent),
|
||||
Wait("Wait",
|
||||
{ ImageGetter.getUnitActionPortrait("Wait") }, 'z', UncivSound.Silent),
|
||||
{ ImageGetter.getUnitActionPortrait("Wait") }, UncivSound.Silent),
|
||||
ShowAdditionalActions("Show more",
|
||||
{ ImageGetter.getUnitActionPortrait("ShowMore") }, KeyCharAndCode(Input.Keys.PAGE_DOWN), false),
|
||||
{ ImageGetter.getUnitActionPortrait("ShowMore") }, false),
|
||||
HideAdditionalActions("Back",
|
||||
{ ImageGetter.getUnitActionPortrait("HideMore") }, KeyCharAndCode(Input.Keys.PAGE_UP), false),
|
||||
{ ImageGetter.getUnitActionPortrait("HideMore") }, false),
|
||||
AddInCapital( "Add in capital",
|
||||
{ ImageGetter.getUnitActionPortrait("AddInCapital")}, 'g', UncivSound.Chimes),
|
||||
{ ImageGetter.getUnitActionPortrait("AddInCapital")}, UncivSound.Chimes),
|
||||
;
|
||||
|
||||
// Allow shorter initializations
|
||||
constructor(value: String, imageGetter: (() -> Actor)?, key: Char, uncivSound: UncivSound = UncivSound.Click)
|
||||
: this(value, imageGetter, KeyCharAndCode(key), true, uncivSound)
|
||||
constructor(value: String, imageGetter: (() -> Actor)?, uncivSound: UncivSound = UncivSound.Click)
|
||||
: this(value, imageGetter, KeyCharAndCode.UNKNOWN, true,uncivSound)
|
||||
constructor(value: String, imageGetter: (() -> Actor)?, key: Char, isSkippingToNextUnit: Boolean = true, uncivSound: UncivSound = UncivSound.Click)
|
||||
: this(value, imageGetter, KeyCharAndCode(key), isSkippingToNextUnit, uncivSound)
|
||||
: this(value, imageGetter, null, true, uncivSound)
|
||||
constructor(value: String, imageGetter: (() -> Actor)?, isSkippingToNextUnit: Boolean = true, uncivSound: UncivSound = UncivSound.Click)
|
||||
: this(value, imageGetter, KeyCharAndCode.UNKNOWN, isSkippingToNextUnit, uncivSound)
|
||||
|
||||
: this(value, imageGetter, null, isSkippingToNextUnit, uncivSound)
|
||||
|
||||
val binding: KeyboardBinding =
|
||||
binding ?:
|
||||
KeyboardBinding.values().firstOrNull { it.name == name } ?:
|
||||
KeyboardBinding.None
|
||||
}
|
||||
|
@ -135,6 +135,9 @@ object TranslationFileWriter {
|
||||
linesToTranslate += "${diplomaticModifier.text} = "
|
||||
|
||||
linesToTranslate += "\n\n#################### Lines from key bindings #######################\n"
|
||||
for (category in KeyboardBinding.Category.values()) {
|
||||
linesToTranslate += "${category.label} = "
|
||||
}
|
||||
for (binding in KeyboardBinding.values()) {
|
||||
linesToTranslate += "${binding.label} = "
|
||||
}
|
||||
|
@ -330,23 +330,33 @@ fun Group.addToCenter(actor: Actor) {
|
||||
* | FORWARD_DEL | 112 | Del | Forward Delete | -1 | 112 |
|
||||
*
|
||||
* This acts as proxy, you replace [Input.Keys] by [GdxKeyCodeFixes] and get sensible [DEL], [toString] and [valueOf].
|
||||
* Differences in behaviour: toString will return an empty string for un-mapped keycodes and UNKNOWN
|
||||
* instead of `null` or "Unknown" respectively,
|
||||
* valueOf will return UNKNOWN for un-mapped names or "" instead of -1.
|
||||
*/
|
||||
@Suppress("GDX_KEYS_BUG", "MemberVisibilityCanBePrivate")
|
||||
object GdxKeyCodeFixes {
|
||||
|
||||
const val DEL = Input.Keys.FORWARD_DEL
|
||||
const val BACKSPACE = Input.Keys.BACKSPACE
|
||||
const val UNKNOWN = Input.Keys.UNKNOWN
|
||||
|
||||
fun toString(keyCode: Int): String = when(keyCode) {
|
||||
UNKNOWN -> ""
|
||||
DEL -> "Del"
|
||||
BACKSPACE -> "Backspace"
|
||||
else -> Input.Keys.toString(keyCode)
|
||||
?: ""
|
||||
}
|
||||
|
||||
fun valueOf(name: String): Int = when (name) {
|
||||
"" -> UNKNOWN
|
||||
"Del" -> DEL
|
||||
"Backspace" -> BACKSPACE
|
||||
else -> Input.Keys.valueOf(name)
|
||||
else -> {
|
||||
val code = Input.Keys.valueOf(name)
|
||||
if (code == -1) UNKNOWN else code
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.unciv.ui.components.input
|
||||
|
||||
import com.badlogic.gdx.Input
|
||||
import com.unciv.Constants
|
||||
|
||||
|
||||
private val unCamelCaseRegex = Regex("([A-Z])([A-Z])([a-z])|([a-z])([A-Z])")
|
||||
@ -11,21 +12,87 @@ enum class KeyboardBinding(
|
||||
label: String? = null,
|
||||
key: KeyCharAndCode? = null
|
||||
) {
|
||||
// Used by [KeyShortcutDispatcher.KeyShortcut] to mark an old-style shortcut with a hardcoded key
|
||||
/** Used by [KeyShortcutDispatcher.KeyShortcut] to mark an old-style shortcut with a hardcoded key */
|
||||
None(Category.None, KeyCharAndCode.UNKNOWN),
|
||||
|
||||
// Worldscreen
|
||||
NextTurn(Category.WorldScreen),
|
||||
NextTurnAlternate(Category.WorldScreen, KeyCharAndCode.SPACE),
|
||||
Civilopedia(Category.WorldScreen, Input.Keys.F1),
|
||||
EmpireOverview(Category.WorldScreen),
|
||||
Wait(Category.None, 'z'), // Used but excluded from UI because UnitActionType.Wait needs to be done too
|
||||
EmpireOverviewTrades(Category.WorldScreen, Input.Keys.F2),
|
||||
EmpireOverviewUnits(Category.WorldScreen, Input.Keys.F3),
|
||||
EmpireOverviewPolitics(Category.WorldScreen, Input.Keys.F4),
|
||||
SocialPolicies(Category.WorldScreen, Input.Keys.F5),
|
||||
TechnologyTree(Category.WorldScreen, Input.Keys.F6),
|
||||
EmpireOverviewNotifications(Category.WorldScreen, Input.Keys.F7),
|
||||
VictoryScreen(Category.WorldScreen, "Victory status", Input.Keys.F8),
|
||||
EmpireOverviewStats(Category.WorldScreen, Input.Keys.F9),
|
||||
EmpireOverviewResources(Category.WorldScreen, Input.Keys.F10),
|
||||
QuickSave(Category.WorldScreen, Input.Keys.F11),
|
||||
QuickLoad(Category.WorldScreen, Input.Keys.F12),
|
||||
ViewCapitalCity(Category.WorldScreen, Input.Keys.HOME),
|
||||
Options(Category.WorldScreen, KeyCharAndCode.ctrl('o')),
|
||||
SaveGame(Category.WorldScreen, KeyCharAndCode.ctrl('s')),
|
||||
LoadGame(Category.WorldScreen, KeyCharAndCode.ctrl('l')),
|
||||
QuitGame(Category.WorldScreen, KeyCharAndCode.ctrl('q')),
|
||||
ToggleUI(Category.WorldScreen, "Toggle UI", KeyCharAndCode.ctrl('u')),
|
||||
ToggleResourceDisplay(Category.WorldScreen, KeyCharAndCode.ctrl('r')),
|
||||
ToggleYieldDisplay(Category.WorldScreen, KeyCharAndCode.ctrl('y')),
|
||||
ToggleWorkedTilesDisplay(Category.WorldScreen, KeyCharAndCode.UNKNOWN),
|
||||
ToggleMovementDisplay(Category.WorldScreen, KeyCharAndCode.UNKNOWN),
|
||||
ZoomIn(Category.WorldScreen, Input.Keys.NUMPAD_ADD),
|
||||
ZoomOut(Category.WorldScreen, Input.Keys.NUMPAD_SUBTRACT),
|
||||
|
||||
// Unit actions - name MUST correspond to UnitActionType.name because the shorthand constructor
|
||||
// there looks up bindings here by name - which also means we must not use UnitActionType
|
||||
// here as it will not be guaranteed to already be fully initialized.
|
||||
SwapUnits(Category.UnitActions,"Swap units", 'y'),
|
||||
Automate(Category.UnitActions, 'm'),
|
||||
StopAutomation(Category.UnitActions,"Stop automation", 'm'),
|
||||
StopMovement(Category.UnitActions,"Stop movement", '.'),
|
||||
Sleep(Category.UnitActions, 'f'),
|
||||
SleepUntilHealed(Category.UnitActions,"Sleep until healed", 'h'),
|
||||
Fortify(Category.UnitActions, 'f'),
|
||||
FortifyUntilHealed(Category.UnitActions,"Fortify until healed", 'h'),
|
||||
Explore(Category.UnitActions, 'x'),
|
||||
StopExploration(Category.UnitActions,"Stop exploration", 'x'),
|
||||
Promote(Category.UnitActions, 'o'),
|
||||
Upgrade(Category.UnitActions, 'u'),
|
||||
Transform(Category.UnitActions, 'k'),
|
||||
Pillage(Category.UnitActions, 'p'),
|
||||
Paradrop(Category.UnitActions, 'p'),
|
||||
AirSweep(Category.UnitActions, 'a'),
|
||||
SetUp(Category.UnitActions,"Set up", 't'),
|
||||
FoundCity(Category.UnitActions,"Found city", 'c'),
|
||||
ConstructImprovement(Category.UnitActions,"Construct improvement", 'i'),
|
||||
Repair(Category.UnitActions, Constants.repair, 'r'),
|
||||
Create(Category.UnitActions, 'i'),
|
||||
HurryResearch(Category.UnitActions, 'g'),
|
||||
StartGoldenAge(Category.UnitActions, 'g'),
|
||||
HurryWonder(Category.UnitActions, 'g'),
|
||||
HurryBuilding(Category.UnitActions,"Hurry Construction", 'g'),
|
||||
ConductTradeMission(Category.UnitActions, 'g'),
|
||||
FoundReligion(Category.UnitActions,"Found a Religion", 'g'),
|
||||
TriggerUnique(Category.UnitActions,"Trigger unique", 'g'),
|
||||
SpreadReligion(Category.UnitActions, 'g'),
|
||||
RemoveHeresy(Category.UnitActions, 'h'),
|
||||
EnhanceReligion(Category.UnitActions,"Enhance a Religion", 'g'),
|
||||
DisbandUnit(Category.UnitActions,"Disband unit", KeyCharAndCode.DEL),
|
||||
GiftUnit(Category.UnitActions,"Gift unit", KeyCharAndCode.UNKNOWN),
|
||||
Wait(Category.UnitActions, 'z'),
|
||||
ShowAdditionalActions(Category.UnitActions,"Show more", Input.Keys.PAGE_DOWN),
|
||||
HideAdditionalActions(Category.UnitActions,"Back", Input.Keys.PAGE_UP),
|
||||
AddInCapital(Category.UnitActions, "Add in capital", 'g'),
|
||||
|
||||
// Popups
|
||||
Confirm(Category.Popups, "Confirm Dialog", 'y'),
|
||||
Cancel(Category.Popups, "Cancel Dialog", 'n'),
|
||||
;
|
||||
|
||||
enum class Category {
|
||||
None, WorldScreen, Popups
|
||||
None, WorldScreen, UnitActions, Popups;
|
||||
val label = unCamelCase(name)
|
||||
}
|
||||
|
||||
val label: String
|
||||
@ -41,8 +108,8 @@ enum class KeyboardBinding(
|
||||
constructor(category: Category, label: String, key: Char) : this(category, label, KeyCharAndCode(key))
|
||||
constructor(category: Category, label: String, key: Int) : this(category, label, KeyCharAndCode(key))
|
||||
constructor(category: Category, key: KeyCharAndCode) : this(category, null, key)
|
||||
constructor(category: Category, key: Char) : this(category, null, KeyCharAndCode(key))
|
||||
constructor(category: Category, key: Int) : this(category, null, KeyCharAndCode(key))
|
||||
constructor(category: Category, key: Char) : this(category, KeyCharAndCode(key))
|
||||
constructor(category: Category, key: Int) : this(category, KeyCharAndCode(key))
|
||||
|
||||
/** Debug helper */
|
||||
override fun toString() = "$category.$name($defaultKey)"
|
||||
|
@ -2,7 +2,10 @@ package com.unciv.ui.popups.options
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.GUI
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.ExpanderTab
|
||||
import com.unciv.ui.components.KeyCapturingButton
|
||||
import com.unciv.ui.components.input.KeyboardBinding
|
||||
import com.unciv.ui.components.TabbedPager
|
||||
@ -15,10 +18,10 @@ import com.unciv.ui.screens.civilopediascreen.MarkupRenderer
|
||||
|
||||
class KeyBindingsTab(
|
||||
optionsPopup: OptionsPopup,
|
||||
labelWidth: Float
|
||||
private val labelWidth: Float
|
||||
) : Table(BaseScreen.skin), TabbedPager.IPageExtensions {
|
||||
private val keyBindings = optionsPopup.settings.keyBindings
|
||||
private val keyFields = HashMap<KeyboardBinding, KeyCapturingButton>(KeyboardBinding.values().size)
|
||||
private val groupedWidgets: LinkedHashMap<KeyboardBinding.Category, LinkedHashMap<KeyboardBinding, KeyCapturingButton>>
|
||||
private val disclaimer = MarkupRenderer.render(listOf(
|
||||
FormattedLine("This is a work in progress.", color = "#b22222", centered = true), // FIREBRICK
|
||||
FormattedLine(),
|
||||
@ -32,31 +35,55 @@ class KeyBindingsTab(
|
||||
}
|
||||
|
||||
init {
|
||||
top()
|
||||
pad(10f)
|
||||
defaults().pad(5f)
|
||||
|
||||
for (binding in KeyboardBinding.values()) {
|
||||
if (binding.hidden) continue
|
||||
keyFields[binding] = KeyCapturingButton(binding.defaultKey)
|
||||
}
|
||||
val collator = UncivGame.Current.settings.getCollatorFromLocale()
|
||||
groupedWidgets = KeyboardBinding.values().asSequence()
|
||||
.filterNot { it.hidden }
|
||||
.groupBy { it.category } // Materializes a Map<Category,List<KeyboardBinding>>
|
||||
.asSequence()
|
||||
.map { (category, bindings) ->
|
||||
category to bindings.asSequence()
|
||||
.sortedWith(compareBy(collator) { it.label.tr() })
|
||||
.map { it to KeyCapturingButton(it.defaultKey) } // associate would materialize a map
|
||||
.toMap(LinkedHashMap())
|
||||
}
|
||||
.sortedBy { it.first.name.tr() }
|
||||
.toMap(LinkedHashMap())
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
clear()
|
||||
add(disclaimer).colspan(2).center().row()
|
||||
add(disclaimer).center().row()
|
||||
|
||||
for (binding in KeyboardBinding.values()) {
|
||||
if (binding.hidden) continue
|
||||
add(binding.label.toLabel())
|
||||
add(keyFields[binding]).row()
|
||||
keyFields[binding]!!.current = keyBindings[binding]
|
||||
for ((category, bindings) in groupedWidgets)
|
||||
add(getCategoryWidget(category, bindings)).row()
|
||||
}
|
||||
|
||||
private fun getCategoryWidget(
|
||||
category: KeyboardBinding.Category,
|
||||
bindings: LinkedHashMap<KeyboardBinding, KeyCapturingButton>
|
||||
) = ExpanderTab(
|
||||
category.label,
|
||||
startsOutOpened = false,
|
||||
defaultPad = 0f,
|
||||
headerPad = 5f,
|
||||
// expanderWidth = labelWidth,
|
||||
persistenceID = "KeyBindings." + category.name
|
||||
) {
|
||||
it.defaults().padTop(5f)
|
||||
for ((binding, widget) in bindings) {
|
||||
it.add(binding.label.toLabel()).padRight(10f).minWidth(labelWidth / 2)
|
||||
it.add(widget).row()
|
||||
widget.current = keyBindings[binding]
|
||||
}
|
||||
}
|
||||
|
||||
fun save () {
|
||||
for (binding in KeyboardBinding.values()) {
|
||||
if (binding.hidden) continue
|
||||
keyBindings[binding] = keyFields[binding]!!.current
|
||||
for ((binding, widget) in groupedWidgets.asSequence().flatMap { it.value.entries }) {
|
||||
keyBindings[binding] = widget.current
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,49 +230,54 @@ class WorldScreen(
|
||||
/*
|
||||
* These try to be faithful to default Civ5 key bindings as found in several places online
|
||||
* Some are a little arbitrary, e.g. Economic info, Military info
|
||||
* Some are very much so as Unciv *is* Strategic View and the Notification log is always visible
|
||||
* Some are very much so as Unciv *is* Strategic View
|
||||
*/
|
||||
globalShortcuts.add(Input.Keys.F2) { openEmpireOverview(EmpireOverviewCategories.Trades) } // Economic info
|
||||
globalShortcuts.add(Input.Keys.F3) { openEmpireOverview(EmpireOverviewCategories.Units) } // Military info
|
||||
globalShortcuts.add(Input.Keys.F4) { openEmpireOverview(EmpireOverviewCategories.Politics) } // Diplomacy info
|
||||
globalShortcuts.add(Input.Keys.F5) { game.pushScreen(PolicyPickerScreen(selectedCiv, canChangeState)) } // Social Policies Screen
|
||||
globalShortcuts.add(Input.Keys.F6) { game.pushScreen(TechPickerScreen(viewingCiv)) } // Tech Screen
|
||||
globalShortcuts.add(Input.Keys.F7) { openEmpireOverview(EmpireOverviewCategories.Notifications) } // Notification Log
|
||||
globalShortcuts.add(Input.Keys.F8) { game.pushScreen(VictoryScreen(this)) } // Victory Progress
|
||||
globalShortcuts.add(Input.Keys.F9) { openEmpireOverview(EmpireOverviewCategories.Stats) } // Demographics
|
||||
globalShortcuts.add(Input.Keys.F10) { openEmpireOverview(EmpireOverviewCategories.Resources) } // originally Strategic View
|
||||
globalShortcuts.add(Input.Keys.F11) { QuickSave.save(gameInfo, this) } // Quick Save
|
||||
globalShortcuts.add(Input.Keys.F12) { QuickSave.load(this) } // Quick Load
|
||||
globalShortcuts.add(Input.Keys.HOME) { // Capital City View
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewTrades) { openEmpireOverview(EmpireOverviewCategories.Trades) } // Economic info
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewUnits) { openEmpireOverview(EmpireOverviewCategories.Units) } // Military info
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewPolitics) { openEmpireOverview(EmpireOverviewCategories.Politics) } // Diplomacy info
|
||||
globalShortcuts.add(KeyboardBinding.SocialPolicies) { game.pushScreen(PolicyPickerScreen(selectedCiv, canChangeState)) } // Social Policies Screen
|
||||
globalShortcuts.add(KeyboardBinding.TechnologyTree) { game.pushScreen(TechPickerScreen(viewingCiv)) } // Tech Screen
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewNotifications) { openEmpireOverview(EmpireOverviewCategories.Notifications) } // Notification Log
|
||||
globalShortcuts.add(KeyboardBinding.VictoryScreen) { game.pushScreen(VictoryScreen(this)) } // Victory Progress
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewStats) { openEmpireOverview(EmpireOverviewCategories.Stats) } // Demographics
|
||||
globalShortcuts.add(KeyboardBinding.EmpireOverviewResources) { openEmpireOverview(EmpireOverviewCategories.Resources) } // originally Strategic View
|
||||
globalShortcuts.add(KeyboardBinding.QuickSave) { QuickSave.save(gameInfo, this) } // Quick Save
|
||||
globalShortcuts.add(KeyboardBinding.QuickLoad) { QuickSave.load(this) } // Quick Load
|
||||
globalShortcuts.add(KeyboardBinding.ViewCapitalCity) { // Capital City View
|
||||
val capital = gameInfo.getCurrentPlayerCivilization().getCapital()
|
||||
if (capital != null && !mapHolder.setCenterPosition(capital.location))
|
||||
game.pushScreen(CityScreen(capital))
|
||||
}
|
||||
globalShortcuts.add(KeyCharAndCode.ctrl('O')) { // Game Options
|
||||
globalShortcuts.add(KeyboardBinding.Options) { // Game Options
|
||||
this.openOptionsPopup(onClose = {
|
||||
nextTurnButton.update(this)
|
||||
})
|
||||
}
|
||||
globalShortcuts.add(KeyCharAndCode.ctrl('S')) { game.pushScreen(SaveGameScreen(gameInfo)) } // Save
|
||||
globalShortcuts.add(KeyCharAndCode.ctrl('L')) { game.pushScreen(LoadGameScreen()) } // Load
|
||||
globalShortcuts.add(KeyCharAndCode.ctrl('Q')) { game.popScreen() } // WorldScreen is the last screen, so this quits
|
||||
globalShortcuts.add(KeyboardBinding.SaveGame) { game.pushScreen(SaveGameScreen(gameInfo)) } // Save
|
||||
globalShortcuts.add(KeyboardBinding.LoadGame) { game.pushScreen(LoadGameScreen()) } // Load
|
||||
globalShortcuts.add(KeyboardBinding.QuitGame) { game.popScreen() } // WorldScreen is the last screen, so this quits
|
||||
globalShortcuts.add(Input.Keys.NUMPAD_ADD) { this.mapHolder.zoomIn() } // '+' Zoom
|
||||
globalShortcuts.add(Input.Keys.NUMPAD_SUBTRACT) { this.mapHolder.zoomOut() } // '-' Zoom
|
||||
globalShortcuts.add(KeyboardBinding.ToggleUI) { toggleUI() }
|
||||
globalShortcuts.add(KeyboardBinding.ToggleResourceDisplay) { minimapWrapper.resourceImageButton.toggle() }
|
||||
globalShortcuts.add(KeyboardBinding.ToggleYieldDisplay) { minimapWrapper.yieldImageButton.toggle() }
|
||||
globalShortcuts.add(KeyboardBinding.ToggleWorkedTilesDisplay) { minimapWrapper.populationImageButton.toggle() }
|
||||
globalShortcuts.add(KeyboardBinding.ToggleMovementDisplay) { minimapWrapper.movementsImageButton.toggle() }
|
||||
}
|
||||
|
||||
globalShortcuts.add(KeyCharAndCode.ctrl('U')){
|
||||
uiEnabled = !uiEnabled
|
||||
topBar.isVisible = uiEnabled
|
||||
statusButtons.isVisible = uiEnabled
|
||||
techPolicyAndDiplomacy.isVisible = uiEnabled
|
||||
tutorialTaskTable.isVisible = uiEnabled
|
||||
bottomTileInfoTable.isVisible = uiEnabled
|
||||
unitActionsTable.isVisible = uiEnabled
|
||||
notificationsScroll.isVisible = uiEnabled
|
||||
minimapWrapper.isVisible = uiEnabled
|
||||
bottomUnitTable.isVisible = uiEnabled
|
||||
if (uiEnabled) battleTable.update() else battleTable.isVisible = false
|
||||
fogOfWarButton.isVisible = uiEnabled && viewingCiv.isSpectator()
|
||||
}
|
||||
private fun toggleUI() {
|
||||
uiEnabled = !uiEnabled
|
||||
topBar.isVisible = uiEnabled
|
||||
statusButtons.isVisible = uiEnabled
|
||||
techPolicyAndDiplomacy.isVisible = uiEnabled
|
||||
tutorialTaskTable.isVisible = uiEnabled
|
||||
bottomTileInfoTable.isVisible = uiEnabled
|
||||
unitActionsTable.isVisible = uiEnabled
|
||||
notificationsScroll.isVisible = uiEnabled
|
||||
minimapWrapper.isVisible = uiEnabled
|
||||
bottomUnitTable.isVisible = uiEnabled
|
||||
if (uiEnabled) battleTable.update() else battleTable.isVisible = false
|
||||
fogOfWarButton.isVisible = uiEnabled && viewingCiv.isSpectator()
|
||||
}
|
||||
|
||||
private fun addKeyboardListener() {
|
||||
|
@ -24,7 +24,7 @@ class MinimapHolder(val mapHolder: WorldMapHolder) : Table() {
|
||||
backgroundColor = Color.GREEN
|
||||
)
|
||||
/** Button, next to the minimap, to toggle the tile yield map overlay. */
|
||||
private val yieldImageButton = MapOverlayToggleButton(
|
||||
val yieldImageButton = MapOverlayToggleButton(
|
||||
ImageGetter.getImage("StatIcons/Food"),
|
||||
// This is a use in the UI that has little to do with the stat… These buttons have more in common with each other than they do with other uses of getStatIcon().
|
||||
getter = { UncivGame.Current.settings.showTileYields },
|
||||
|
@ -11,10 +11,10 @@ import com.unciv.logic.map.mapunit.MapUnit
|
||||
import com.unciv.models.UnitAction
|
||||
import com.unciv.models.UnitActionType
|
||||
import com.unciv.models.UpgradeUnitAction
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.UncivTooltip
|
||||
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
|
||||
import com.unciv.ui.components.extensions.disable
|
||||
import com.unciv.ui.components.input.KeyboardBindings
|
||||
import com.unciv.ui.components.input.keyShortcuts
|
||||
import com.unciv.ui.components.input.onActivation
|
||||
import com.unciv.ui.components.extensions.packIfNeeded
|
||||
@ -31,7 +31,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
|
||||
for (unitAction in UnitActions.getUnitActions(unit)) {
|
||||
val button = getUnitActionButton(unit, unitAction)
|
||||
if (unitAction is UpgradeUnitAction && GUI.keyboardAvailable) {
|
||||
val tipTitle = "«RED»${unitAction.type.key}«»: {Upgrade}"
|
||||
val tipTitle = "«RED»${KeyboardBindings[unitAction.type.binding]}«»: {Upgrade}"
|
||||
val tipActor = BaseUnitDescriptions.getUpgradeTooltipActor(tipTitle, unit.baseUnit, unitAction.unitToUpgradeTo)
|
||||
button.addListener(UncivTooltip(button, tipActor
|
||||
, offset = Vector2(0f, tipActor.packIfNeeded().height * 0.333f) // scaling fails to express size in parent coordinates
|
||||
@ -46,7 +46,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
|
||||
private fun getUnitActionButton(unit: MapUnit, unitAction: UnitAction): Button {
|
||||
val icon = unitAction.getIcon()
|
||||
// If peripheral keyboard not detected, hotkeys will not be displayed
|
||||
val key = if (GUI.keyboardAvailable) unitAction.type.key else KeyCharAndCode.UNKNOWN
|
||||
val binding = unitAction.type.binding
|
||||
|
||||
val fontColor = if (unitAction.isCurrentAction) Color.YELLOW else Color.WHITE
|
||||
val actionButton = IconTextButton(unitAction.title, icon, fontColor = fontColor)
|
||||
@ -55,7 +55,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
|
||||
actionButton.color = Color.GREEN.cpy().lerp(Color.WHITE, 0.5f)
|
||||
|
||||
if (unitAction !is UpgradeUnitAction) // Does its own toolTip
|
||||
actionButton.addTooltip(key)
|
||||
actionButton.addTooltip(KeyboardBindings[binding])
|
||||
actionButton.pack()
|
||||
if (unitAction.action == null) {
|
||||
actionButton.disable()
|
||||
@ -72,7 +72,7 @@ class UnitActionsTable(val worldScreen: WorldScreen) : Table() {
|
||||
worldScreen.switchToNextUnit()
|
||||
}
|
||||
}
|
||||
actionButton.keyShortcuts.add(key)
|
||||
actionButton.keyShortcuts.add(binding)
|
||||
}
|
||||
|
||||
return actionButton
|
||||
|
Loading…
Reference in New Issue
Block a user