Civilopedia key bindings (#10723)

* Move CivilopediaImageGetters object to own file

* Keyboard bindings for Civilopedia

* Better default key choices

* Change default Key Binding Tab visibility to ON
This commit is contained in:
SomeTroglodyte
2023-12-13 21:36:29 +01:00
committed by GitHub
parent aba77b8350
commit a24f9d7716
6 changed files with 156 additions and 163 deletions

View File

@ -286,7 +286,7 @@
}, },
{ {
"name": "AutoPlay", "name": "AutoPlay",
"steps": ["When at later stages of the game, you might have a lot of units but only a little to do. To help you we have implemented an AutoPlay feature that lets you use the AI to play part or all of your turn.", "steps": ["When at later stages of the game, you might have a lot of units but only a little to do. To help you we have implemented an AutoPlay feature that lets you use the AI to play part or all of your turn.",
"To enable AutoPlay, go to options and open the AutoPlay tab and press \"Show AutoPlay button\".", "To enable AutoPlay, go to options and open the AutoPlay tab and press \"Show AutoPlay button\".",
"Clicking on the AutoPlay button opens a popup menue for choosing to AutoPlay parts or all of your turn.", "Clicking on the AutoPlay button opens a popup menue for choosing to AutoPlay parts or all of your turn.",
"Clicking Start AutoPlay in the pop-up menue or long pressing the AutoPlay button begins the multi-turn AutoPlay. This will play your next turns as if you were an AI.", "Clicking Start AutoPlay in the pop-up menue or long pressing the AutoPlay button begins the multi-turn AutoPlay. This will play your next turns as if you were an AI.",
@ -435,7 +435,6 @@
{}, {},
{"text":"For discussion about missing entries, see the linked github issue.","link":"https://github.com/yairm210/Unciv/issues/8862"} {"text":"For discussion about missing entries, see the linked github issue.","link":"https://github.com/yairm210/Unciv/issues/8862"}
] ]
// "uniques": ["Will not be displayed in Civilopedia"] // would prevent use for help link
}, },
{ {
"name": "Civilopedia", "name": "Civilopedia",

View File

@ -165,10 +165,29 @@ enum class KeyboardBinding(
AddConstructionAllTop(Category.CityScreenConstructionMenu, "Add or move to the top in all cities", KeyCharAndCode.ctrl('t')), AddConstructionAllTop(Category.CityScreenConstructionMenu, "Add or move to the top in all cities", KeyCharAndCode.ctrl('t')),
RemoveConstructionAll(Category.CityScreenConstructionMenu, "Remove from the queue in all cities", KeyCharAndCode.ctrl('r')), RemoveConstructionAll(Category.CityScreenConstructionMenu, "Remove from the queue in all cities", KeyCharAndCode.ctrl('r')),
// Civilopedia
PediaBuildings(Category.Civilopedia, "Buildings", 'b'),
PediaWonders(Category.Civilopedia, "Wonders", 'w'),
PediaResources(Category.Civilopedia, "Resources", 'r'),
PediaTerrains(Category.Civilopedia, "Terrains", 't'),
PediaImprovements(Category.Civilopedia, "Tile Improvements", 'i'),
PediaUnits(Category.Civilopedia, "Units", 'u'),
PediaUnitTypes(Category.Civilopedia, "Unit types", 'y'),
PediaNations(Category.Civilopedia, "Nations", 'n'),
PediaTechnologies(Category.Civilopedia, "Technologies", KeyCharAndCode.ctrl('t')),
PediaPromotions(Category.Civilopedia, "Promotions", 'p'),
PediaPolicies(Category.Civilopedia, "Policies", 'o'),
PediaBeliefs(Category.Civilopedia, "Religions and Beliefs", 'f'),
PediaTutorials(Category.Civilopedia, "Tutorials", Input.Keys.F1),
PediaDifficulties(Category.Civilopedia, "Difficulty levels", 'd'),
PediaEras(Category.Civilopedia, "Eras", 'e'),
PediaSpeeds(Category.Civilopedia, "Speeds", 's'),
PediaSearch(Category.Civilopedia, "Open the Search Dialog", KeyCharAndCode.ctrl('f')),
// Popups // Popups
Confirm(Category.Popups, "Confirm Dialog", 'y'), Confirm(Category.Popups, "Confirm Dialog", 'y'),
Cancel(Category.Popups, "Cancel Dialog", 'n'), Cancel(Category.Popups, "Cancel Dialog", 'n'),
UpgradeAll(Category.Popups, KeyCharAndCode.ctrl('a')), UpgradeAll(Category.Popups, KeyCharAndCode.ctrl('a')), // rethink? No UnitUpgradeMenu category, but CityScreenConstructionMenu gets one?
; ;
//endregion //endregion
@ -188,6 +207,7 @@ enum class KeyboardBinding(
}, },
CityScreen, CityScreen,
CityScreenConstructionMenu, // Maybe someday a category hierarchy? CityScreenConstructionMenu, // Maybe someday a category hierarchy?
Civilopedia,
Popups Popups
; ;
val label = unCamelCase(name) val label = unCamelCase(name)

View File

@ -43,7 +43,7 @@ class OptionsPopup(
private var keyBindingsTab: KeyBindingsTab? = null private var keyBindingsTab: KeyBindingsTab? = null
/** Enable the still experimental Keyboard Bindings page in OptionsPopup */ /** Enable the still experimental Keyboard Bindings page in OptionsPopup */
var enableKeyBindingsTab: Boolean = false var enableKeyBindingsTab: Boolean = true
//endregion //endregion
@ -209,7 +209,8 @@ class OptionsPopup(
internal fun showOrHideKeyBindings() { internal fun showOrHideKeyBindings() {
// At the moment, the Key bindings Tab exists only on-demand. To refactor it back to permanent, // At the moment, the Key bindings Tab exists only on-demand. To refactor it back to permanent,
// move the `keyBindingsTab =` line and addPage call to before the Advanced Tab creation, // move the `keyBindingsTab =` line and addPage call to before the Advanced Tab creation,
// then delete this function, delete the enableKeyBindingsTab flag and clean up what is flagged by the compiler as missing or unused. // then delete this function, delete the enableKeyBindingsTab flag and clean up what is flagged
// by the compiler as missing or unused - like the `add("Show keyboard bindings".toCheckBox` option on DebugTab.
val existingIndex = tabs.getPageIndex(keysTabCaption) val existingIndex = tabs.getPageIndex(keysTabCaption)
if (enableKeyBindingsTab && existingIndex < 0) { if (enableKeyBindingsTab && existingIndex < 0) {
if (keyBindingsTab == null) if (keyBindingsTab == null)

View File

@ -1,111 +1,12 @@
package com.unciv.ui.screens.civilopediascreen package com.unciv.ui.screens.civilopediascreen
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.unciv.Constants
import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.Terrain import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.unit.UnitMovementType
import com.unciv.ui.components.extensions.setSize
import com.unciv.ui.components.extensions.surroundWithCircle
import com.unciv.ui.components.input.KeyCharAndCode
import com.unciv.ui.components.tilegroups.TileGroup
import com.unciv.ui.components.tilegroups.TileSetStrings
import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.screens.basescreen.TutorialController import com.unciv.ui.screens.basescreen.TutorialController
import com.unciv.models.ruleset.Belief as BaseBelief import com.unciv.models.ruleset.Belief as BaseBelief
import com.unciv.models.ruleset.unit.UnitType as BaseUnitType import com.unciv.models.ruleset.unit.UnitType as BaseUnitType
/** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */
object CivilopediaImageGetters {
private const val policyIconFolder = "PolicyIcons"
private const val policyBranchIconFolder = "PolicyBranchIcons"
private const val policyInnerSize = 0.25f
// Todo: potential synergy with map editor
fun terrainImage(terrain: Terrain, ruleset: Ruleset, imageSize: Float): Actor {
val tile = Tile()
tile.ruleset = ruleset
when (terrain.type) {
TerrainType.NaturalWonder -> {
tile.naturalWonder = terrain.name
tile.baseTerrain = terrain.turnsInto ?: terrain.occursOn.firstOrNull() ?: Constants.grassland
}
TerrainType.TerrainFeature -> {
tile.baseTerrain =
if (terrain.occursOn.isEmpty() || terrain.occursOn.contains(Constants.grassland))
Constants.grassland
else
terrain.occursOn.lastOrNull()!!
tile.setTerrainTransients()
tile.addTerrainFeature(terrain.name)
}
else ->
tile.baseTerrain = terrain.name
}
tile.setTerrainTransients()
val group = TileGroup(tile, TileSetStrings(), imageSize * 36f/54f) // TileGroup normally spills out of its bounding box
group.isForceVisible = true
group.isForMapEditorIcon = true
group.update()
return Container(group)
}
val construction = { name: String, size: Float ->
ImageGetter.getConstructionPortrait(name, size)
}
val improvement = { name: String, size: Float ->
ImageGetter.getImprovementPortrait(name, size)
}
val nation = { name: String, size: Float ->
val nation = ImageGetter.ruleset.nations[name]
if (nation == null) null
else ImageGetter.getNationPortrait(nation, size)
}
val policy = fun(name: String, size: Float): IconCircleGroup? {
// result is nullable: policy branch complete have no icons but are linked -> nonexistence must be passed down
fun tryImage(path: String, color: Color): IconCircleGroup? {
if (ImageGetter.imageExists(path)) return ImageGetter.getImage(path).apply {
setSize(size * policyInnerSize,size * policyInnerSize)
this.color = color
}.surroundWithCircle(size)
return null
}
return tryImage("$policyBranchIconFolder/$name", Color.BLACK)
?: tryImage("$policyIconFolder/$name", Color.BROWN)
}
val resource = { name: String, size: Float ->
ImageGetter.getResourcePortrait(name, size)
}
val technology = { name: String, size: Float ->
ImageGetter.getTechIconPortrait(name, size)
}
val promotion = { name: String, size: Float ->
ImageGetter.getPromotionPortrait(name, size)
}
val terrain = { name: String, size: Float ->
val terrain = ImageGetter.ruleset.terrains[name]
if (terrain == null) null
else terrainImage(terrain, ImageGetter.ruleset, size)
}
val belief = { name: String, size: Float ->
ImageGetter.getReligionPortrait(name, size)
}
val unitType = { name: String, size: Float ->
val path = UnitMovementType.values().firstOrNull { "Domain: [${it.name}]" == name }
?.let {"UnitTypeIcons/Domain${it.name}" }
?: "UnitTypeIcons/$name"
if (ImageGetter.imageExists(path)) ImageGetter.getImage(path).apply { setSize(size) }
else null
}
}
/** Enum used as keys for Civilopedia "pages" (categories). /** Enum used as keys for Civilopedia "pages" (categories).
* *
* Note names are singular on purpose - a "link" allows both key and label * Note names are singular on purpose - a "link" allows both key and label
@ -117,121 +18,110 @@ enum class CivilopediaCategories (
val label: String, val label: String,
val hide: Boolean, // Omitted on CivilopediaScreen val hide: Boolean, // Omitted on CivilopediaScreen
val getImage: ((name: String, size: Float) -> Actor?)?, val getImage: ((name: String, size: Float) -> Actor?)?,
val key: KeyCharAndCode = KeyCharAndCode.UNKNOWN, val binding: KeyboardBinding,
val headerIcon: String, val headerIcon: String,
val getCategoryIterator: (ruleset: Ruleset, tutorialController: TutorialController) -> Collection<ICivilopediaText> val getCategoryIterator: (ruleset: Ruleset, tutorialController: TutorialController) -> Collection<ICivilopediaText>
) { ) {
Building ("Buildings", false, Building ("Buildings", false,
CivilopediaImageGetters.construction, CivilopediaImageGetters.construction,
KeyCharAndCode('B'), KeyboardBinding.PediaBuildings,
"OtherIcons/Cities", "OtherIcons/Cities",
{ ruleset, _ -> ruleset.buildings.values.filter { !it.isAnyWonder() } } { ruleset, _ -> ruleset.buildings.values.filter { !it.isAnyWonder() } }
), ),
Wonder ("Wonders", false, Wonder ("Wonders", false,
CivilopediaImageGetters.construction, CivilopediaImageGetters.construction,
KeyCharAndCode('W'), KeyboardBinding.PediaWonders,
"OtherIcons/Wonders", "OtherIcons/Wonders",
{ ruleset, _ -> ruleset.buildings.values.filter { it.isAnyWonder() } } { ruleset, _ -> ruleset.buildings.values.filter { it.isAnyWonder() } }
), ),
Resource ("Resources", false, Resource ("Resources", false,
CivilopediaImageGetters.resource, CivilopediaImageGetters.resource,
KeyCharAndCode('R'), KeyboardBinding.PediaResources,
"OtherIcons/Resources", "OtherIcons/Resources",
{ ruleset, _ -> ruleset.tileResources.values } { ruleset, _ -> ruleset.tileResources.values }
), ),
Terrain ("Terrains", false, Terrain ("Terrains", false,
CivilopediaImageGetters.terrain, CivilopediaImageGetters.terrain,
KeyCharAndCode('T'), KeyboardBinding.PediaTerrains,
"OtherIcons/Terrains", "OtherIcons/Terrains",
{ ruleset, _ -> ruleset.terrains.values } { ruleset, _ -> ruleset.terrains.values }
), ),
Improvement ("Tile Improvements", false, Improvement ("Tile Improvements", false,
CivilopediaImageGetters.improvement, CivilopediaImageGetters.improvement,
KeyCharAndCode('T'), KeyboardBinding.PediaImprovements,
"OtherIcons/Improvements", "OtherIcons/Improvements",
{ ruleset, _ -> ruleset.tileImprovements.values } { ruleset, _ -> ruleset.tileImprovements.values }
), ),
Unit ("Units", false, Unit ("Units", false,
CivilopediaImageGetters.construction, CivilopediaImageGetters.construction,
KeyCharAndCode('U'), KeyboardBinding.PediaUnits,
"OtherIcons/Shield", "OtherIcons/Shield",
{ ruleset, _ -> ruleset.units.values } { ruleset, _ -> ruleset.units.values }
), ),
UnitType ("Unit types", false, UnitType ("Unit types", false,
CivilopediaImageGetters.unitType, CivilopediaImageGetters.unitType,
KeyCharAndCode('U'), KeyboardBinding.PediaUnitTypes,
"UnitTypeIcons/UnitTypes", "UnitTypeIcons/UnitTypes",
{ ruleset, _ -> BaseUnitType.getCivilopediaIterator(ruleset) } { ruleset, _ -> BaseUnitType.getCivilopediaIterator(ruleset) }
), ),
Nation ("Nations", false, Nation ("Nations", false,
CivilopediaImageGetters.nation, CivilopediaImageGetters.nation,
KeyCharAndCode('N'), KeyboardBinding.PediaNations,
"OtherIcons/Nations", "OtherIcons/Nations",
{ ruleset, _ -> ruleset.nations.values.filter { !it.isSpectator } } { ruleset, _ -> ruleset.nations.values.filter { !it.isSpectator } }
), ),
Technology ("Technologies", false, Technology ("Technologies", false,
CivilopediaImageGetters.technology, CivilopediaImageGetters.technology,
KeyCharAndCode('T'), KeyboardBinding.PediaTechnologies,
"TechIcons/Philosophy", "TechIcons/Philosophy",
{ ruleset, _ -> ruleset.technologies.values } { ruleset, _ -> ruleset.technologies.values }
), ),
Promotion ("Promotions", false, Promotion ("Promotions", false,
CivilopediaImageGetters.promotion, CivilopediaImageGetters.promotion,
KeyCharAndCode('P'), KeyboardBinding.PediaPromotions,
"UnitPromotionIcons/Mobility", "UnitPromotionIcons/Mobility",
{ ruleset, _ -> ruleset.unitPromotions.values } { ruleset, _ -> ruleset.unitPromotions.values }
), ),
Policy ("Policies", false, Policy ("Policies", false,
CivilopediaImageGetters.policy, CivilopediaImageGetters.policy,
KeyCharAndCode('P'), KeyboardBinding.PediaPolicies,
"PolicyIcons/Constitution", "PolicyIcons/Constitution",
{ ruleset, _ -> ruleset.policies.values } { ruleset, _ -> ruleset.policies.values }
), ),
Belief("Religions and Beliefs", false, Belief("Religions and Beliefs",
hide = false, // Skipping this page when showReligionInCivilopedia returns false is hardcoded
CivilopediaImageGetters.belief, CivilopediaImageGetters.belief,
KeyCharAndCode('R'), KeyboardBinding.PediaBeliefs,
"ReligionIcons/Religion", "ReligionIcons/Religion",
{ ruleset, _ -> (ruleset.beliefs.values.asSequence() + { ruleset, _ -> (ruleset.beliefs.values.asSequence() +
BaseBelief.getCivilopediaReligionEntry(ruleset)).toList() } BaseBelief.getCivilopediaReligionEntry(ruleset)).toList() }
), ),
Tutorial ("Tutorials", false, Tutorial ("Tutorials", false,
getImage = null, getImage = null,
KeyCharAndCode(Input.Keys.F1), KeyboardBinding.PediaTutorials,
"OtherIcons/ExclamationMark", "OtherIcons/ExclamationMark",
{ _, tutorialController -> tutorialController.getCivilopediaTutorials() } { _, tutorialController -> tutorialController.getCivilopediaTutorials() }
), ),
Difficulty ("Difficulty levels", false, Difficulty ("Difficulty levels", false,
getImage = null, getImage = null,
KeyCharAndCode('D'), KeyboardBinding.PediaDifficulties,
"OtherIcons/Quickstart", "OtherIcons/Quickstart",
{ ruleset, _ -> ruleset.difficulties.values } { ruleset, _ -> ruleset.difficulties.values }
), ),
Era ("Eras", false, Era ("Eras", false,
getImage = null, getImage = null,
KeyCharAndCode('D'), KeyboardBinding.PediaEras,
"OtherIcons/Tyrannosaurus", "OtherIcons/Tyrannosaurus",
{ ruleset, _ -> ruleset.eras.values } { ruleset, _ -> ruleset.eras.values }
), ),
Speed ("Speeds", false, Speed ("Speeds", false,
getImage = null, getImage = null,
KeyCharAndCode('S'), KeyboardBinding.PediaSpeeds,
"OtherIcons/Timer", "OtherIcons/Timer",
{ ruleset, _ -> ruleset.speeds.values } { ruleset, _ -> ruleset.speeds.values }
); );
private fun getByOffset(offset: Int) = values()[(ordinal + count + offset) % count]
fun nextForKey(key: KeyCharAndCode): CivilopediaCategories {
for (i in 1..count) {
val next = getByOffset(i)
if (next.key == key) return next
}
return this
}
companion object { companion object {
private val count = values().size
fun fromLink(name: String): CivilopediaCategories? = fun fromLink(name: String): CivilopediaCategories? =
values().firstOrNull { it.name == name } values().firstOrNull { it.name == name }
?: values().firstOrNull { it.label == name } ?: values().firstOrNull { it.label == name }

View File

@ -0,0 +1,101 @@
package com.unciv.ui.screens.civilopediascreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.unciv.Constants
import com.unciv.logic.map.tile.Tile
import com.unciv.models.ruleset.Ruleset
import com.unciv.models.ruleset.tile.Terrain
import com.unciv.models.ruleset.tile.TerrainType
import com.unciv.models.ruleset.unit.UnitMovementType
import com.unciv.ui.components.extensions.setSize
import com.unciv.ui.components.extensions.surroundWithCircle
import com.unciv.ui.components.tilegroups.TileGroup
import com.unciv.ui.components.tilegroups.TileSetStrings
import com.unciv.ui.images.IconCircleGroup
import com.unciv.ui.images.ImageGetter
/** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */
internal object CivilopediaImageGetters {
private const val policyIconFolder = "PolicyIcons"
private const val policyBranchIconFolder = "PolicyBranchIcons"
private const val policyInnerSize = 0.25f
// Todo: potential synergy with map editor
private fun terrainImage(terrain: Terrain, ruleset: Ruleset, imageSize: Float): Actor {
val tile = Tile()
tile.ruleset = ruleset
when (terrain.type) {
TerrainType.NaturalWonder -> {
tile.naturalWonder = terrain.name
tile.baseTerrain = terrain.turnsInto ?: terrain.occursOn.firstOrNull() ?: Constants.grassland
}
TerrainType.TerrainFeature -> {
tile.baseTerrain =
if (terrain.occursOn.isEmpty() || terrain.occursOn.contains(Constants.grassland))
Constants.grassland
else
terrain.occursOn.lastOrNull()!!
tile.setTerrainTransients()
tile.addTerrainFeature(terrain.name)
}
else ->
tile.baseTerrain = terrain.name
}
tile.setTerrainTransients()
val group = TileGroup(tile, TileSetStrings(), imageSize * 36f / 54f) // TileGroup normally spills out of its bounding box
group.isForceVisible = true
group.isForMapEditorIcon = true
group.update()
return Container(group)
}
val construction = { name: String, size: Float ->
ImageGetter.getConstructionPortrait(name, size)
}
val improvement = { name: String, size: Float ->
ImageGetter.getImprovementPortrait(name, size)
}
val nation = { name: String, size: Float ->
val nation = ImageGetter.ruleset.nations[name]
if (nation == null) null
else ImageGetter.getNationPortrait(nation, size)
}
val policy = fun(name: String, size: Float): IconCircleGroup? {
// result is nullable: policy branch complete have no icons but are linked -> nonexistence must be passed down
fun tryImage(path: String, color: Color): IconCircleGroup? {
if (ImageGetter.imageExists(path)) return ImageGetter.getImage(path).apply {
setSize(size * policyInnerSize,size * policyInnerSize)
this.color = color
}.surroundWithCircle(size)
return null
}
return tryImage("$policyBranchIconFolder/$name", Color.BLACK)
?: tryImage("$policyIconFolder/$name", Color.BROWN)
}
val resource = { name: String, size: Float ->
ImageGetter.getResourcePortrait(name, size)
}
val technology = { name: String, size: Float ->
ImageGetter.getTechIconPortrait(name, size)
}
val promotion = { name: String, size: Float ->
ImageGetter.getPromotionPortrait(name, size)
}
val terrain = { name: String, size: Float ->
val terrain = ImageGetter.ruleset.terrains[name]
if (terrain == null) null
else terrainImage(terrain, ImageGetter.ruleset, size)
}
val belief = { name: String, size: Float ->
ImageGetter.getReligionPortrait(name, size)
}
val unitType = { name: String, size: Float ->
val path = UnitMovementType.values().firstOrNull { "Domain: [${it.name}]" == name }
?.let {"UnitTypeIcons/Domain${it.name}" }
?: "UnitTypeIcons/$name"
if (ImageGetter.imageExists(path)) ImageGetter.getImage(path).apply { setSize(size) }
else null
}
}

View File

@ -14,7 +14,6 @@ import com.unciv.models.ruleset.unique.IHasUniques
import com.unciv.models.ruleset.unique.UniqueType import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.models.stats.INamed import com.unciv.models.stats.INamed
import com.unciv.models.translations.tr import com.unciv.models.translations.tr
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
import com.unciv.ui.components.extensions.colorFromRGB import com.unciv.ui.components.extensions.colorFromRGB
import com.unciv.ui.components.extensions.toImageButton import com.unciv.ui.components.extensions.toImageButton
import com.unciv.ui.components.extensions.toLabel import com.unciv.ui.components.extensions.toLabel
@ -236,8 +235,7 @@ class CivilopediaScreen(
if (entries.isEmpty()) continue if (entries.isEmpty()) continue
val icon = if (categoryKey.headerIcon.isNotEmpty()) ImageGetter.getImage(categoryKey.headerIcon) else null val icon = if (categoryKey.headerIcon.isNotEmpty()) ImageGetter.getImage(categoryKey.headerIcon) else null
val button = IconTextButton(categoryKey.label, icon) val button = IconTextButton(categoryKey.label, icon)
button.addTooltip(categoryKey.key) button.onActivation(binding = categoryKey.binding) { selectCategory(categoryKey) }
button.onClick { selectCategory(categoryKey) }
val cell = buttonTable.add(button) val cell = buttonTable.add(button)
categoryToButtons[categoryKey] = CategoryButtonInfo(button, currentX, cell.prefWidth) categoryToButtons[categoryKey] = CategoryButtonInfo(button, currentX, cell.prefWidth)
currentX += cell.prefWidth + 20f currentX += cell.prefWidth + 20f
@ -245,11 +243,10 @@ class CivilopediaScreen(
buttonTable.pack() buttonTable.pack()
buttonTableScroll = ScrollPane(buttonTable) buttonTableScroll = ScrollPane(buttonTable)
buttonTableScroll.setScrollingDisabled(false, true) buttonTableScroll.setScrollingDisabled(x = false, y = true)
val searchButton = "OtherIcons/Search".toImageButton(imageSize - 16f, imageSize, skinStrings.skinConfig.baseColor, Color.GOLD) val searchButton = "OtherIcons/Search".toImageButton(imageSize - 16f, imageSize, skinStrings.skinConfig.baseColor, Color.GOLD)
searchButton.onActivation { searchPopup.open(true) } searchButton.onActivation(binding = KeyboardBinding.PediaSearch) { searchPopup.open(true) }
searchButton.keyShortcuts.add(KeyboardBinding.Civilopedia) // "hit twice to search"
val closeButton = "OtherIcons/Close".toImageButton(imageSize - 20f, imageSize, skinStrings.skinConfig.baseColor, Color.RED) val closeButton = "OtherIcons/Close".toImageButton(imageSize - 20f, imageSize, skinStrings.skinConfig.baseColor, Color.RED)
closeButton.onActivation { game.popScreen() } closeButton.onActivation { game.popScreen() }
@ -292,26 +289,8 @@ class CivilopediaScreen(
else else
selectEntry(link, noScrollAnimation = true) selectEntry(link, noScrollAnimation = true)
for (categoryKey in categoryToEntries.keys) { globalShortcuts.add(Input.Keys.LEFT) { navigateCategories(-1) }
globalShortcuts.add(categoryKey.key) { navigateCategories(categoryKey.key) } globalShortcuts.add(Input.Keys.RIGHT) { navigateCategories(1) }
}
globalShortcuts.add(Input.Keys.LEFT) {
val categoryKey = categoryToEntries.keys
val currentIndex = categoryKey.indexOf(currentCategory)
val targetCategory = categoryKey.elementAt(
(currentIndex + categoryKey.size - 1) % categoryKey.size
)
selectCategory(targetCategory)
}
globalShortcuts.add(Input.Keys.RIGHT) {
val categoryKey = categoryToEntries.keys
val currentIndex = categoryKey.indexOf(currentCategory)
val targetCategory = categoryKey.elementAt(
(currentIndex + categoryKey.size + 1) % categoryKey.size
)
selectCategory(targetCategory)
}
globalShortcuts.add(Input.Keys.UP) { navigateEntries(-1) } globalShortcuts.add(Input.Keys.UP) { navigateEntries(-1) }
globalShortcuts.add(Input.Keys.DOWN) { navigateEntries(1) } globalShortcuts.add(Input.Keys.DOWN) { navigateEntries(1) }
globalShortcuts.add(Input.Keys.PAGE_UP) { navigateEntries(-10) } globalShortcuts.add(Input.Keys.PAGE_UP) { navigateEntries(-10) }
@ -320,8 +299,11 @@ class CivilopediaScreen(
globalShortcuts.add(Input.Keys.END) { navigateEntries(Int.MAX_VALUE) } globalShortcuts.add(Input.Keys.END) { navigateEntries(Int.MAX_VALUE) }
} }
private fun navigateCategories(key: KeyCharAndCode) { private fun navigateCategories(direction: Int) {
selectCategory(currentCategory.nextForKey(key)) val categoryKeys = categoryToEntries.keys
val currentIndex = categoryKeys.indexOf(currentCategory)
val newIndex = (currentIndex + categoryKeys.size + direction) % categoryKeys.size
selectCategory(categoryKeys.elementAt(newIndex))
} }
private fun navigateEntries(direction: Int) { private fun navigateEntries(direction: Int) {