mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-28 14:24:43 -04:00
Civilopedia category icons and keyboard navigation (#5341)
* Civilopedia category icons and keyboard navigation * Civilopedia category icons - white alternative
This commit is contained in:
parent
3220206bce
commit
fb30a76e85
BIN
android/Images/OtherIcons/Improvements.png
Normal file
BIN
android/Images/OtherIcons/Improvements.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
android/Images/OtherIcons/Nations.png
Normal file
BIN
android/Images/OtherIcons/Nations.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 KiB |
BIN
android/Images/OtherIcons/Resources.png
Normal file
BIN
android/Images/OtherIcons/Resources.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
android/Images/OtherIcons/Terrains.png
Normal file
BIN
android/Images/OtherIcons/Terrains.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
@ -1,5 +1,6 @@
|
|||||||
package com.unciv.ui.civilopedia
|
package com.unciv.ui.civilopedia
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
import com.badlogic.gdx.graphics.Color
|
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.badlogic.gdx.scenes.scene2d.ui.Container
|
||||||
@ -11,6 +12,7 @@ import com.unciv.models.ruleset.tile.TerrainType
|
|||||||
import com.unciv.ui.tilegroups.TileGroup
|
import com.unciv.ui.tilegroups.TileGroup
|
||||||
import com.unciv.ui.tilegroups.TileSetStrings
|
import com.unciv.ui.tilegroups.TileSetStrings
|
||||||
import com.unciv.ui.utils.ImageGetter
|
import com.unciv.ui.utils.ImageGetter
|
||||||
|
import com.unciv.ui.utils.KeyCharAndCode
|
||||||
import com.unciv.ui.utils.surroundWithCircle
|
import com.unciv.ui.utils.surroundWithCircle
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@ -113,24 +115,89 @@ object CivilopediaImageGetters {
|
|||||||
enum class CivilopediaCategories (
|
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 headerIcon: String
|
||||||
) {
|
) {
|
||||||
Building ("Buildings", false, CivilopediaImageGetters.construction ),
|
Building ("Buildings", false,
|
||||||
Wonder ("Wonders", false, CivilopediaImageGetters.construction ),
|
CivilopediaImageGetters.construction,
|
||||||
Resource ("Resources", false, CivilopediaImageGetters.resource ),
|
KeyCharAndCode('B'),
|
||||||
Terrain ("Terrains", false, CivilopediaImageGetters.terrain ),
|
"OtherIcons/Cities"
|
||||||
Improvement ("Tile Improvements", false, CivilopediaImageGetters.improvement ),
|
),
|
||||||
Unit ("Units", false, CivilopediaImageGetters.construction ),
|
Wonder ("Wonders", false,
|
||||||
Nation ("Nations", false, CivilopediaImageGetters.nation ),
|
CivilopediaImageGetters.construction,
|
||||||
Technology ("Technologies", false, CivilopediaImageGetters.technology ),
|
KeyCharAndCode('W'),
|
||||||
Promotion ("Promotions", false, CivilopediaImageGetters.promotion ),
|
"OtherIcons/Wonders"
|
||||||
Policy ("Policies", false, CivilopediaImageGetters.policy ),
|
),
|
||||||
Belief("Religions and Beliefs", false, CivilopediaImageGetters.belief ),
|
Resource ("Resources", false,
|
||||||
Tutorial ("Tutorials", false, null ),
|
CivilopediaImageGetters.resource,
|
||||||
Difficulty ("Difficulty levels", false, null ),
|
KeyCharAndCode('R'),
|
||||||
;
|
"OtherIcons/Resources"
|
||||||
|
),
|
||||||
|
Terrain ("Terrains", false,
|
||||||
|
CivilopediaImageGetters.terrain,
|
||||||
|
KeyCharAndCode('T'),
|
||||||
|
"OtherIcons/Terrains"
|
||||||
|
),
|
||||||
|
Improvement ("Tile Improvements", false,
|
||||||
|
CivilopediaImageGetters.improvement,
|
||||||
|
KeyCharAndCode('T'),
|
||||||
|
"OtherIcons/Improvements"
|
||||||
|
),
|
||||||
|
Unit ("Units", false,
|
||||||
|
CivilopediaImageGetters.construction,
|
||||||
|
KeyCharAndCode('U'),
|
||||||
|
"OtherIcons/Shield"
|
||||||
|
),
|
||||||
|
Nation ("Nations", false,
|
||||||
|
CivilopediaImageGetters.nation,
|
||||||
|
KeyCharAndCode('N'),
|
||||||
|
"OtherIcons/Nations"
|
||||||
|
),
|
||||||
|
Technology ("Technologies", false,
|
||||||
|
CivilopediaImageGetters.technology,
|
||||||
|
KeyCharAndCode('T'),
|
||||||
|
"TechIcons/Philosophy"
|
||||||
|
),
|
||||||
|
Promotion ("Promotions", false,
|
||||||
|
CivilopediaImageGetters.promotion,
|
||||||
|
KeyCharAndCode('P'),
|
||||||
|
"UnitPromotionIcons/Mobility"
|
||||||
|
),
|
||||||
|
Policy ("Policies", false,
|
||||||
|
CivilopediaImageGetters.policy,
|
||||||
|
KeyCharAndCode('P'),
|
||||||
|
"PolicyIcons/Constitution"
|
||||||
|
),
|
||||||
|
Belief("Religions and Beliefs", false,
|
||||||
|
CivilopediaImageGetters.belief,
|
||||||
|
KeyCharAndCode('R'),
|
||||||
|
"ReligionIcons/Religion"
|
||||||
|
),
|
||||||
|
Tutorial ("Tutorials", false,
|
||||||
|
getImage = null,
|
||||||
|
KeyCharAndCode(Input.Keys.F1),
|
||||||
|
"OtherIcons/ExclamationMark"
|
||||||
|
),
|
||||||
|
Difficulty ("Difficulty levels", false,
|
||||||
|
getImage = null,
|
||||||
|
KeyCharAndCode('D'),
|
||||||
|
"OtherIcons/Quickstart"
|
||||||
|
);
|
||||||
|
|
||||||
|
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 }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.unciv.ui.civilopedia
|
package com.unciv.ui.civilopedia
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
import com.badlogic.gdx.graphics.Color
|
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.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
@ -11,6 +12,7 @@ import com.unciv.models.ruleset.unique.Unique
|
|||||||
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.utils.*
|
import com.unciv.ui.utils.*
|
||||||
|
import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip
|
||||||
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
import com.unciv.ui.utils.AutoScrollPane as ScrollPane
|
||||||
|
|
||||||
/** Screen displaying the Civilopedia
|
/** Screen displaying the Civilopedia
|
||||||
@ -44,15 +46,19 @@ class CivilopediaScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val categoryToEntries = LinkedHashMap<CivilopediaCategories, Collection<CivilopediaEntry>>()
|
private val categoryToEntries = LinkedHashMap<CivilopediaCategories, Collection<CivilopediaEntry>>()
|
||||||
private val categoryToButtons = LinkedHashMap<CivilopediaCategories, Button>()
|
private class CategoryButtonInfo(val button: Button, val x: Float, val width: Float)
|
||||||
|
private val categoryToButtons = LinkedHashMap<CivilopediaCategories, CategoryButtonInfo>()
|
||||||
private val entryIndex = LinkedHashMap<String, CivilopediaEntry>()
|
private val entryIndex = LinkedHashMap<String, CivilopediaEntry>()
|
||||||
|
|
||||||
|
private val buttonTableScroll: ScrollPane
|
||||||
|
|
||||||
private val entrySelectTable = Table().apply { defaults().pad(6f).left() }
|
private val entrySelectTable = Table().apply { defaults().pad(6f).left() }
|
||||||
private val entrySelectScroll: ScrollPane
|
private val entrySelectScroll: ScrollPane
|
||||||
private val flavourTable = Table()
|
private val flavourTable = Table()
|
||||||
|
|
||||||
private var currentCategory: CivilopediaCategories = CivilopediaCategories.Tutorial
|
private var currentCategory: CivilopediaCategories = CivilopediaCategories.Tutorial
|
||||||
private var currentEntry: String = ""
|
private var currentEntry: String = ""
|
||||||
|
private val currentEntryPerCategory = HashMap<CivilopediaCategories, String>()
|
||||||
|
|
||||||
/** Jump to a "link" selecting both category and entry
|
/** Jump to a "link" selecting both category and entry
|
||||||
*
|
*
|
||||||
@ -87,9 +93,11 @@ class CivilopediaScreen(
|
|||||||
entryIndex.clear()
|
entryIndex.clear()
|
||||||
flavourTable.clear()
|
flavourTable.clear()
|
||||||
|
|
||||||
for (button in categoryToButtons.values) button.color = Color.WHITE
|
for (button in categoryToButtons.values) button.button.color = Color.WHITE
|
||||||
if (category !in categoryToButtons) return // defense against being passed a bad selector
|
val buttonInfo = categoryToButtons[category]
|
||||||
categoryToButtons[category]!!.color = Color.BLUE
|
?: return // defense against being passed a bad selector
|
||||||
|
buttonInfo.button.color = Color.BLUE
|
||||||
|
buttonTableScroll.scrollX = buttonInfo.x + (buttonInfo.width - buttonTableScroll.width) / 2
|
||||||
|
|
||||||
if (category !in categoryToEntries) return // defense, allowing buggy panes to remain empty while others work
|
if (category !in categoryToEntries) return // defense, allowing buggy panes to remain empty while others work
|
||||||
var entries = categoryToEntries[category]!!
|
var entries = categoryToEntries[category]!!
|
||||||
@ -123,6 +131,9 @@ class CivilopediaScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
entrySelectScroll.layout() // necessary for positioning in selectRow to work
|
entrySelectScroll.layout() // necessary for positioning in selectRow to work
|
||||||
|
|
||||||
|
val entry = currentEntryPerCategory[category]
|
||||||
|
if (entry != null) selectEntry(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Select a specified entry within the current category. Unknown strings are ignored!
|
/** Select a specified entry within the current category. Unknown strings are ignored!
|
||||||
@ -132,15 +143,14 @@ class CivilopediaScreen(
|
|||||||
fun selectEntry(name: String, noScrollAnimation: Boolean = false) {
|
fun selectEntry(name: String, noScrollAnimation: Boolean = false) {
|
||||||
val entry = entryIndex[name] ?: return
|
val entry = entryIndex[name] ?: return
|
||||||
// fails: entrySelectScroll.scrollTo(0f, entry.y, 0f, entry.h, false, true)
|
// fails: entrySelectScroll.scrollTo(0f, entry.y, 0f, entry.h, false, true)
|
||||||
entrySelectScroll.let {
|
entrySelectScroll.scrollY = (entry.y + (entry.height - entrySelectScroll.height) / 2)
|
||||||
it.scrollY = (entry.y + (entry.height - it.height) / 2).coerceIn(0f, it.maxY)
|
|
||||||
}
|
|
||||||
if (noScrollAnimation)
|
if (noScrollAnimation)
|
||||||
entrySelectScroll.updateVisualScroll() // snap without animation on fresh pedia open
|
entrySelectScroll.updateVisualScroll() // snap without animation on fresh pedia open
|
||||||
selectEntry(entry)
|
selectEntry(entry)
|
||||||
}
|
}
|
||||||
private fun selectEntry(entry: CivilopediaEntry) {
|
private fun selectEntry(entry: CivilopediaEntry) {
|
||||||
currentEntry = entry.name
|
currentEntry = entry.name
|
||||||
|
currentEntryPerCategory[currentCategory] = entry.name
|
||||||
flavourTable.clear()
|
flavourTable.clear()
|
||||||
if (entry.flavour != null) {
|
if (entry.flavour != null) {
|
||||||
flavourTable.isVisible = true
|
flavourTable.isVisible = true
|
||||||
@ -207,17 +217,22 @@ class CivilopediaScreen(
|
|||||||
buttonTable.pad(15f)
|
buttonTable.pad(15f)
|
||||||
buttonTable.defaults().pad(10f)
|
buttonTable.defaults().pad(10f)
|
||||||
|
|
||||||
|
var currentX = 10f // = padLeft
|
||||||
for (categoryKey in categoryToEntries.keys) {
|
for (categoryKey in categoryToEntries.keys) {
|
||||||
val button = categoryKey.label.toTextButton()
|
val button = Button(skin)
|
||||||
button.style = TextButton.TextButtonStyle(button.style)
|
if (categoryKey.headerIcon.isNotEmpty())
|
||||||
categoryToButtons[categoryKey] = button
|
button.add(ImageGetter.getImage(categoryKey.headerIcon)).size(20f).padRight(5f)
|
||||||
|
button.add(categoryKey.label.toLabel())
|
||||||
|
button.addTooltip(categoryKey.key)
|
||||||
|
// button.style = ImageButton.ImageButtonStyle(button.style)
|
||||||
button.onClick { selectCategory(categoryKey) }
|
button.onClick { selectCategory(categoryKey) }
|
||||||
buttonTable.add(button)
|
val cell = buttonTable.add(button)
|
||||||
|
categoryToButtons[categoryKey] = CategoryButtonInfo(button, currentX, cell.prefWidth)
|
||||||
|
currentX += cell.prefWidth + 20f
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonTable.pack()
|
buttonTable.pack()
|
||||||
buttonTable.width = stage.width
|
buttonTableScroll = ScrollPane(buttonTable)
|
||||||
val buttonTableScroll = ScrollPane(buttonTable)
|
|
||||||
buttonTableScroll.setScrollingDisabled(false, true)
|
buttonTableScroll.setScrollingDisabled(false, true)
|
||||||
|
|
||||||
val goToGameButton = Constants.close.toTextButton()
|
val goToGameButton = Constants.close.toTextButton()
|
||||||
@ -228,8 +243,9 @@ class CivilopediaScreen(
|
|||||||
|
|
||||||
val topTable = Table()
|
val topTable = Table()
|
||||||
topTable.add(goToGameButton).pad(10f)
|
topTable.add(goToGameButton).pad(10f)
|
||||||
topTable.add(buttonTableScroll)
|
topTable.add(buttonTableScroll).growX()
|
||||||
topTable.pack()
|
topTable.width = stage.width
|
||||||
|
topTable.layout()
|
||||||
|
|
||||||
val entryTable = Table()
|
val entryTable = Table()
|
||||||
val splitPane = SplitPane(topTable, entryTable, true, skin)
|
val splitPane = SplitPane(topTable, entryTable, true, skin)
|
||||||
@ -257,6 +273,34 @@ class CivilopediaScreen(
|
|||||||
selectLink(link)
|
selectLink(link)
|
||||||
else
|
else
|
||||||
selectEntry(link, noScrollAnimation = true)
|
selectEntry(link, noScrollAnimation = true)
|
||||||
|
|
||||||
|
for (categoryKey in CivilopediaCategories.values()) {
|
||||||
|
keyPressDispatcher[categoryKey.key] = { navigateCategories(categoryKey.key) }
|
||||||
|
}
|
||||||
|
keyPressDispatcher[Input.Keys.LEFT] = { selectCategory(currentCategory.getByOffset(-1)) }
|
||||||
|
keyPressDispatcher[Input.Keys.RIGHT] = { selectCategory(currentCategory.getByOffset(1)) }
|
||||||
|
keyPressDispatcher[Input.Keys.UP] = { navigateEntries(-1) }
|
||||||
|
keyPressDispatcher[Input.Keys.DOWN] = { navigateEntries(1) }
|
||||||
|
keyPressDispatcher[Input.Keys.PAGE_UP] = { navigateEntries(-10) }
|
||||||
|
keyPressDispatcher[Input.Keys.PAGE_DOWN] = { navigateEntries(10) }
|
||||||
|
keyPressDispatcher[Input.Keys.HOME] = { navigateEntries(Int.MIN_VALUE) }
|
||||||
|
keyPressDispatcher[Input.Keys.END] = { navigateEntries(Int.MAX_VALUE) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateCategories(key: KeyCharAndCode) {
|
||||||
|
selectCategory(currentCategory.nextForKey(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateEntries(direction: Int) {
|
||||||
|
//todo this is abusing a Map as Array - there must be a collection allowing both easy positional and associative access
|
||||||
|
val index = entryIndex.keys.indexOf(currentEntry)
|
||||||
|
if (index < 0) return selectEntry(entryIndex.keys.first(), true)
|
||||||
|
val newIndex = when (direction) {
|
||||||
|
Int.MIN_VALUE -> 0
|
||||||
|
Int.MAX_VALUE -> entryIndex.size - 1
|
||||||
|
else -> (index + entryIndex.size + direction) % entryIndex.size
|
||||||
|
}
|
||||||
|
selectEntry(entryIndex.keys.drop(newIndex).first())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resize(width: Int, height: Int) {
|
override fun resize(width: Int, height: Int) {
|
||||||
|
@ -158,7 +158,7 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [Anvil](https://thenounproject.com/term/anvil/166414/) By Jason Dilworth for Iron
|
* [Anvil](https://thenounproject.com/term/anvil/166414/) By Jason Dilworth for Iron
|
||||||
* [Deer](https://thenounproject.com/term/deer/338013/) By Richard Nixon
|
* [Deer](https://thenounproject.com/term/deer/338013/) By Richard Nixon
|
||||||
* [Banana](https://thenounproject.com/term/banana/1262865/) By Adrian Coquet
|
* [Banana](https://thenounproject.com/term/banana/1262865/) By Adrian Coquet
|
||||||
* [Oil](https://thenounproject.com/term/oil/88649/) By Tiago Maricate
|
* [Oil](https://thenounproject.com/term/oil/88649/) By Tiago Maricate (also as Civilopedia category icon)
|
||||||
* [Statue](https://thenounproject.com/term/statue/5221/) By Joris Hoogendoorn for Marble
|
* [Statue](https://thenounproject.com/term/statue/5221/) By Joris Hoogendoorn for Marble
|
||||||
* [Ribbon](https://thenounproject.com/term/ribbon/418996) By Anton for Silk
|
* [Ribbon](https://thenounproject.com/term/ribbon/418996) By Anton for Silk
|
||||||
* [Stone](https://thenounproject.com/term/stone/1373902/) By AFY Studio
|
* [Stone](https://thenounproject.com/term/stone/1373902/) By AFY Studio
|
||||||
@ -648,6 +648,8 @@ Unless otherwise specified, all the following are from [the Noun Project](https:
|
|||||||
* [ship helm](https://thenounproject.com/term/ship-helm/2170591/) by Vectors Market for Maritime City-States
|
* [ship helm](https://thenounproject.com/term/ship-helm/2170591/) by Vectors Market for Maritime City-States
|
||||||
* [Magnifying Glass](https://thenounproject.com/term/magnifying-glass/1311/) by John Caserta for Mod filter
|
* [Magnifying Glass](https://thenounproject.com/term/magnifying-glass/1311/) by John Caserta for Mod filter
|
||||||
* [tick](https://thenounproject.com/term/tick/3968142/) by Adrien Coquet on Nation picker
|
* [tick](https://thenounproject.com/term/tick/3968142/) by Adrien Coquet on Nation picker
|
||||||
|
* [people](https://thenounproject.com/term/people/458671) by Wilson Joseph as base for Civilopedia category Nations
|
||||||
|
* [Mountains ](https://thenounproject.com/term/mountains/15616/) by Andrew J. Young as base for Civilopedia category Terrains
|
||||||
|
|
||||||
## Main menu
|
## Main menu
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user