mirror of
https://github.com/yairm210/Unciv.git
synced 2025-01-03 21:40:31 +07:00
Pedia Search (#9997)
* Minor Civilopedia linting * Civilopedia Search Popup * Add missing "entire current complex ruleset" scope * Address comments * Wording change * Remove comment
This commit is contained in:
parent
23c8ba05de
commit
bb3335aaa8
@ -1604,6 +1604,13 @@ Toggle UI (World Screen only) =
|
||||
Overrides yields from underlying terrain =
|
||||
No yields =
|
||||
Mod: [modname] =
|
||||
Search text: =
|
||||
Invalid regular expression =
|
||||
Mod filter: =
|
||||
-Combined- =
|
||||
Search! =
|
||||
Results =
|
||||
Nothing found! =
|
||||
|
||||
# Policies
|
||||
|
||||
|
@ -7,7 +7,6 @@ import com.unciv.models.ruleset.unique.UniqueTarget
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.screens.civilopediascreen.CivilopediaScreen.Companion.showReligionInCivilopedia
|
||||
import com.unciv.ui.screens.civilopediascreen.FormattedLine
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class Belief() : RulesetObject() {
|
||||
var type: BeliefType = BeliefType.None
|
||||
@ -23,7 +22,6 @@ class Belief() : RulesetObject() {
|
||||
override fun makeLink() = "Belief/$name"
|
||||
override fun getCivilopediaTextHeader() = FormattedLine(name, icon = makeLink(), header = 2, color = if (type == BeliefType.None) "#e34a2b" else "")
|
||||
override fun getSortGroup(ruleset: Ruleset) = type.ordinal
|
||||
override fun getIconName() = if (type == BeliefType.None) "Religion" else type.name
|
||||
|
||||
override fun getCivilopediaTextLines(ruleset: Ruleset): List<FormattedLine> {
|
||||
return getCivilopediaTextLines(false)
|
||||
|
@ -56,7 +56,7 @@ class Speed : RulesetObject(), IsPartOfGameInfoSerialization {
|
||||
|
||||
override fun getUniqueTarget(): UniqueTarget = UniqueTarget.Speed
|
||||
|
||||
override fun makeLink(): String = "GameSpeed/$name"
|
||||
override fun makeLink(): String = "Speed/$name"
|
||||
override fun getCivilopediaTextHeader() = FormattedLine(name, header = 2)
|
||||
override fun getCivilopediaTextLines(ruleset: Ruleset) = sequence {
|
||||
yield(FormattedLine("General speed modifier: [${modifier * 100}]%${Fonts.turn}"))
|
||||
|
@ -92,7 +92,9 @@ class TutorialController(screen: BaseScreen) {
|
||||
) : INamed, SimpleCivilopediaText(
|
||||
sequenceOf(FormattedLine(extraImage = name.replace(' ', '_'))) + tutorial.civilopediaText.asSequence(),
|
||||
tutorial.steps?.asSequence() ?: emptySequence()
|
||||
)
|
||||
) {
|
||||
override fun makeLink() = "Tutorial/$name"
|
||||
}
|
||||
|
||||
/** Get all Tutorials intended to be displayed in the Civilopedia
|
||||
* as a List of wrappers supporting INamed and ICivilopediaText
|
||||
|
@ -10,13 +10,16 @@ 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.images.ImageGetter
|
||||
import com.unciv.ui.components.tilegroups.TileGroup
|
||||
import com.unciv.ui.components.tilegroups.TileSetStrings
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
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.models.ruleset.Belief as BaseBelief
|
||||
import com.unciv.models.ruleset.unit.UnitType as BaseUnitType
|
||||
|
||||
|
||||
/** Encapsulates the knowledge on how to get an icon for each of the Civilopedia categories */
|
||||
@ -115,87 +118,105 @@ enum class CivilopediaCategories (
|
||||
val hide: Boolean, // Omitted on CivilopediaScreen
|
||||
val getImage: ((name: String, size: Float) -> Actor?)?,
|
||||
val key: KeyCharAndCode = KeyCharAndCode.UNKNOWN,
|
||||
val headerIcon: String
|
||||
) {
|
||||
val headerIcon: String,
|
||||
val getCategoryIterator: (ruleset: Ruleset, tutorialController: TutorialController) -> Collection<ICivilopediaText>
|
||||
) {
|
||||
Building ("Buildings", false,
|
||||
CivilopediaImageGetters.construction,
|
||||
KeyCharAndCode('B'),
|
||||
"OtherIcons/Cities"
|
||||
"OtherIcons/Cities",
|
||||
{ ruleset, _ -> ruleset.buildings.values.filter { !it.isAnyWonder() } }
|
||||
),
|
||||
Wonder ("Wonders", false,
|
||||
CivilopediaImageGetters.construction,
|
||||
KeyCharAndCode('W'),
|
||||
"OtherIcons/Wonders"
|
||||
"OtherIcons/Wonders",
|
||||
{ ruleset, _ -> ruleset.buildings.values.filter { it.isAnyWonder() } }
|
||||
),
|
||||
Resource ("Resources", false,
|
||||
CivilopediaImageGetters.resource,
|
||||
KeyCharAndCode('R'),
|
||||
"OtherIcons/Resources"
|
||||
"OtherIcons/Resources",
|
||||
{ ruleset, _ -> ruleset.tileResources.values }
|
||||
),
|
||||
Terrain ("Terrains", false,
|
||||
CivilopediaImageGetters.terrain,
|
||||
KeyCharAndCode('T'),
|
||||
"OtherIcons/Terrains"
|
||||
"OtherIcons/Terrains",
|
||||
{ ruleset, _ -> ruleset.terrains.values }
|
||||
),
|
||||
Improvement ("Tile Improvements", false,
|
||||
CivilopediaImageGetters.improvement,
|
||||
KeyCharAndCode('T'),
|
||||
"OtherIcons/Improvements"
|
||||
"OtherIcons/Improvements",
|
||||
{ ruleset, _ -> ruleset.tileImprovements.values }
|
||||
),
|
||||
Unit ("Units", false,
|
||||
CivilopediaImageGetters.construction,
|
||||
KeyCharAndCode('U'),
|
||||
"OtherIcons/Shield"
|
||||
"OtherIcons/Shield",
|
||||
{ ruleset, _ -> ruleset.units.values }
|
||||
),
|
||||
UnitType ("Unit types", false,
|
||||
CivilopediaImageGetters.unitType,
|
||||
KeyCharAndCode('U'),
|
||||
"UnitTypeIcons/UnitTypes"
|
||||
"UnitTypeIcons/UnitTypes",
|
||||
{ ruleset, _ -> BaseUnitType.getCivilopediaIterator(ruleset) }
|
||||
),
|
||||
Nation ("Nations", false,
|
||||
CivilopediaImageGetters.nation,
|
||||
KeyCharAndCode('N'),
|
||||
"OtherIcons/Nations"
|
||||
"OtherIcons/Nations",
|
||||
{ ruleset, _ -> ruleset.nations.values.filter { !it.isSpectator } }
|
||||
),
|
||||
Technology ("Technologies", false,
|
||||
CivilopediaImageGetters.technology,
|
||||
KeyCharAndCode('T'),
|
||||
"TechIcons/Philosophy"
|
||||
"TechIcons/Philosophy",
|
||||
{ ruleset, _ -> ruleset.technologies.values }
|
||||
),
|
||||
Promotion ("Promotions", false,
|
||||
CivilopediaImageGetters.promotion,
|
||||
KeyCharAndCode('P'),
|
||||
"UnitPromotionIcons/Mobility"
|
||||
"UnitPromotionIcons/Mobility",
|
||||
{ ruleset, _ -> ruleset.unitPromotions.values }
|
||||
),
|
||||
Policy ("Policies", false,
|
||||
CivilopediaImageGetters.policy,
|
||||
KeyCharAndCode('P'),
|
||||
"PolicyIcons/Constitution"
|
||||
"PolicyIcons/Constitution",
|
||||
{ ruleset, _ -> ruleset.policies.values }
|
||||
),
|
||||
Belief("Religions and Beliefs", false,
|
||||
CivilopediaImageGetters.belief,
|
||||
KeyCharAndCode('R'),
|
||||
"ReligionIcons/Religion"
|
||||
"ReligionIcons/Religion",
|
||||
{ ruleset, _ -> (ruleset.beliefs.values.asSequence() +
|
||||
BaseBelief.getCivilopediaReligionEntry(ruleset)).toList() }
|
||||
),
|
||||
Tutorial ("Tutorials", false,
|
||||
getImage = null,
|
||||
KeyCharAndCode(Input.Keys.F1),
|
||||
"OtherIcons/ExclamationMark"
|
||||
"OtherIcons/ExclamationMark",
|
||||
{ _, tutorialController -> tutorialController.getCivilopediaTutorials() }
|
||||
),
|
||||
Difficulty ("Difficulty levels", false,
|
||||
getImage = null,
|
||||
KeyCharAndCode('D'),
|
||||
"OtherIcons/Quickstart"
|
||||
"OtherIcons/Quickstart",
|
||||
{ ruleset, _ -> ruleset.difficulties.values }
|
||||
),
|
||||
Era ("Eras", false,
|
||||
getImage = null,
|
||||
KeyCharAndCode('D'),
|
||||
"OtherIcons/Tyrannosaurus"
|
||||
"OtherIcons/Tyrannosaurus",
|
||||
{ ruleset, _ -> ruleset.eras.values }
|
||||
),
|
||||
Speed ("Speeds", false,
|
||||
getImage = null,
|
||||
KeyCharAndCode('S'),
|
||||
"OtherIcons/Timer"
|
||||
"OtherIcons/Timer",
|
||||
{ ruleset, _ -> ruleset.speeds.values }
|
||||
);
|
||||
|
||||
private fun getByOffset(offset: Int) = values()[(ordinal + count + offset) % count]
|
||||
|
@ -7,23 +7,23 @@ import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Button
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.Constants
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.ruleset.Belief
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.ruleset.unique.IHasUniques
|
||||
import com.unciv.models.ruleset.unique.UniqueType
|
||||
import com.unciv.models.ruleset.unit.UnitType
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.Fonts
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.UncivTooltip.Companion.addTooltip
|
||||
import com.unciv.ui.components.extensions.colorFromRGB
|
||||
import com.unciv.ui.components.input.onClick
|
||||
import com.unciv.ui.components.extensions.toImageButton
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.extensions.toTextButton
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.input.KeyboardBinding
|
||||
import com.unciv.ui.components.input.keyShortcuts
|
||||
import com.unciv.ui.components.input.onActivation
|
||||
import com.unciv.ui.components.input.onClick
|
||||
import com.unciv.ui.images.IconTextButton
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
@ -75,6 +75,11 @@ class CivilopediaScreen(
|
||||
private var currentEntry: String = ""
|
||||
private val currentEntryPerCategory = HashMap<CivilopediaCategories, String>()
|
||||
|
||||
private val searchPopup by lazy { CivilopediaSearchPopup(this, tutorialController) {
|
||||
selectLink(it)
|
||||
} }
|
||||
|
||||
|
||||
/** Jump to a "link" selecting both category and entry
|
||||
*
|
||||
* Calls [selectCategory] with the substring before the first '/',
|
||||
@ -160,7 +165,7 @@ class CivilopediaScreen(
|
||||
* @param name Entry (Ruleset object) name
|
||||
* @param noScrollAnimation Disable scroll animation
|
||||
*/
|
||||
fun selectEntry(name: String, noScrollAnimation: Boolean = false) {
|
||||
private fun selectEntry(name: String, noScrollAnimation: Boolean = false) {
|
||||
val entry = entryIndex[name] ?: return
|
||||
// fails: entrySelectScroll.scrollTo(0f, entry.y, 0f, entry.h, false, true)
|
||||
entrySelectScroll.scrollY = (entry.y + (entry.height - entrySelectScroll.height) / 2)
|
||||
@ -195,7 +200,6 @@ class CivilopediaScreen(
|
||||
|
||||
init {
|
||||
val imageSize = 50f
|
||||
globalShortcuts.add(KeyCharAndCode.BACK) { game.popScreen() }
|
||||
|
||||
val religionEnabled = showReligionInCivilopedia(ruleset)
|
||||
val victoryTypes = game.gameInfo?.gameParameters?.victoryTypes ?: ruleset.victories.keys
|
||||
@ -209,32 +213,11 @@ class CivilopediaScreen(
|
||||
}
|
||||
}
|
||||
|
||||
fun getCategoryIterator(category: CivilopediaCategories): Collection<ICivilopediaText> =
|
||||
when (category) {
|
||||
CivilopediaCategories.Building -> ruleset.buildings.values.filter { !it.isAnyWonder() }
|
||||
CivilopediaCategories.Wonder -> ruleset.buildings.values.filter { it.isAnyWonder() }
|
||||
CivilopediaCategories.Resource -> ruleset.tileResources.values
|
||||
CivilopediaCategories.Terrain -> ruleset.terrains.values
|
||||
CivilopediaCategories.Improvement -> ruleset.tileImprovements.values
|
||||
CivilopediaCategories.Unit -> ruleset.units.values
|
||||
CivilopediaCategories.UnitType -> UnitType.getCivilopediaIterator(ruleset)
|
||||
CivilopediaCategories.Nation -> ruleset.nations.values.filter { !it.isSpectator }
|
||||
CivilopediaCategories.Technology -> ruleset.technologies.values
|
||||
CivilopediaCategories.Promotion -> ruleset.unitPromotions.values
|
||||
CivilopediaCategories.Policy -> ruleset.policies.values
|
||||
CivilopediaCategories.Tutorial -> tutorialController.getCivilopediaTutorials()
|
||||
CivilopediaCategories.Difficulty -> ruleset.difficulties.values
|
||||
CivilopediaCategories.Belief -> (ruleset.beliefs.values.asSequence() +
|
||||
Belief.getCivilopediaReligionEntry(ruleset)).toList()
|
||||
CivilopediaCategories.Era -> ruleset.eras.values
|
||||
CivilopediaCategories.Speed -> ruleset.speeds.values
|
||||
}
|
||||
|
||||
for (loopCategory in CivilopediaCategories.values()) {
|
||||
if (loopCategory.hide) continue
|
||||
if (!religionEnabled && loopCategory == CivilopediaCategories.Belief) continue
|
||||
categoryToEntries[loopCategory] =
|
||||
getCategoryIterator(loopCategory)
|
||||
loopCategory.getCategoryIterator(ruleset, tutorialController)
|
||||
.filter { (it as? IHasUniques)?.let { obj -> shouldBeDisplayed(obj) } ?: true }
|
||||
.map { CivilopediaEntry(
|
||||
(it as INamed).name,
|
||||
@ -254,7 +237,6 @@ class CivilopediaScreen(
|
||||
val icon = if (categoryKey.headerIcon.isNotEmpty()) ImageGetter.getImage(categoryKey.headerIcon) else null
|
||||
val button = IconTextButton(categoryKey.label, icon)
|
||||
button.addTooltip(categoryKey.key)
|
||||
// button.style = ImageButton.ImageButtonStyle(button.style)
|
||||
button.onClick { selectCategory(categoryKey) }
|
||||
val cell = buttonTable.add(button)
|
||||
categoryToButtons[categoryKey] = CategoryButtonInfo(button, currentX, cell.prefWidth)
|
||||
@ -265,14 +247,18 @@ class CivilopediaScreen(
|
||||
buttonTableScroll = ScrollPane(buttonTable)
|
||||
buttonTableScroll.setScrollingDisabled(false, true)
|
||||
|
||||
val goToGameButton = Constants.close.toTextButton()
|
||||
goToGameButton.onClick {
|
||||
game.popScreen()
|
||||
}
|
||||
val searchButton = "OtherIcons/Search".toImageButton(imageSize - 16f, imageSize, skinStrings.skinConfig.baseColor, Color.GOLD)
|
||||
searchButton.onActivation { 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)
|
||||
closeButton.onActivation { game.popScreen() }
|
||||
closeButton.keyShortcuts.add(KeyCharAndCode.BACK)
|
||||
|
||||
val topTable = Table()
|
||||
topTable.add(goToGameButton).pad(10f)
|
||||
topTable.add(buttonTableScroll).growX()
|
||||
topTable.add(searchButton).padLeft(10f)
|
||||
topTable.add(closeButton).padLeft(10f).padRight(10f)
|
||||
topTable.width = stage.width
|
||||
topTable.layout()
|
||||
|
||||
|
@ -0,0 +1,187 @@
|
||||
package com.unciv.ui.screens.civilopediascreen
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.Cell
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
||||
import com.badlogic.gdx.utils.Align
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetCache
|
||||
import com.unciv.models.stats.INamed
|
||||
import com.unciv.models.translations.tr
|
||||
import com.unciv.ui.components.ExpanderTab
|
||||
import com.unciv.ui.components.UncivTextField
|
||||
import com.unciv.ui.components.extensions.disable
|
||||
import com.unciv.ui.components.extensions.enable
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.components.input.KeyCharAndCode
|
||||
import com.unciv.ui.components.input.onClick
|
||||
import com.unciv.ui.popups.Popup
|
||||
import com.unciv.ui.popups.ToastPopup
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.screens.basescreen.TutorialController
|
||||
import com.unciv.utils.Concurrency
|
||||
import com.unciv.utils.launchOnGLThread
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.isActive
|
||||
import com.badlogic.gdx.utils.Array as GdxArray
|
||||
|
||||
class CivilopediaSearchPopup(
|
||||
private val pediaScreen: CivilopediaScreen,
|
||||
private val tutorialController: TutorialController,
|
||||
private val linkAction: (String) -> Unit
|
||||
) : Popup(pediaScreen) {
|
||||
private var ruleset = pediaScreen.ruleset
|
||||
private val searchText = UncivTextField.create("") // Always focused, "hint" never seen
|
||||
private val modSelect = ModSelectBox()
|
||||
private lateinit var resultExpander: ExpanderTab
|
||||
private val resultCell: Cell<Actor?>
|
||||
private val searchButton: TextButton
|
||||
|
||||
private var searchJob: Job? = null
|
||||
private var checkLine: (String) -> Boolean = { _ -> false }
|
||||
|
||||
init {
|
||||
searchText.maxLength = 100
|
||||
|
||||
add("Search text:".toLabel())
|
||||
add(searchText).growX().row()
|
||||
add("Mod filter:".toLabel())
|
||||
add(modSelect).growX().row()
|
||||
resultCell = add().colspan(2).growX()
|
||||
row()
|
||||
|
||||
searchButton = addButton("Search!", KeyCharAndCode.RETURN) {
|
||||
startSearch(searchText.text)
|
||||
}.actor
|
||||
addCloseButton()
|
||||
showListeners.add {
|
||||
keyboardFocus = searchText
|
||||
searchText.selectAll()
|
||||
}
|
||||
closeListeners.add {
|
||||
if (isSearchRunning()) searchJob!!.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isSearchRunning() = searchJob?.isActive == true
|
||||
|
||||
private fun startSearch(text: String) {
|
||||
searchButton.disable()
|
||||
|
||||
@Suppress("LiftReturnOrAssignment")
|
||||
if (text.isEmpty()) {
|
||||
checkLine = { true }
|
||||
} else if (".*" in text || '\\' in text || '|' in text) {
|
||||
try {
|
||||
val regex = Regex(text, RegexOption.IGNORE_CASE)
|
||||
checkLine = { regex.containsMatchIn(it) }
|
||||
} catch (ex: Exception) {
|
||||
ToastPopup("Invalid regular expression", pediaScreen, 4000).open(true)
|
||||
searchButton.enable()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
val words = text.split(' ').toSet()
|
||||
checkLine = { line -> words.all { line.contains(it, ignoreCase = true) } }
|
||||
}
|
||||
|
||||
ruleset = modSelect.selectedRuleset()
|
||||
|
||||
if (::resultExpander.isInitialized) {
|
||||
resultExpander.innerTable.clear()
|
||||
} else {
|
||||
resultExpander = ExpanderTab("Results") {}
|
||||
resultCell.setActor(resultExpander)
|
||||
resultExpander.innerTable.defaults().growX().pad(2f)
|
||||
}
|
||||
|
||||
searchJob = Concurrency.run("PediaSearch") {
|
||||
searchLoop()
|
||||
}
|
||||
searchJob!!.invokeOnCompletion {
|
||||
searchJob = null
|
||||
Concurrency.runOnGLThread {
|
||||
finishSearch()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.searchLoop() {
|
||||
for (category in CivilopediaCategories.values()) {
|
||||
if (!isActive) break
|
||||
if (category.hide) continue
|
||||
if (!ruleset.modOptions.isBaseRuleset && category == CivilopediaCategories.Tutorial)
|
||||
continue // Search tutorials only when the mod filter is a base ruleset
|
||||
for (entry in category.getCategoryIterator(ruleset, tutorialController)) {
|
||||
if (!isActive) break
|
||||
if (entry !is INamed) continue
|
||||
if (!ruleset.modOptions.isBaseRuleset) {
|
||||
val sort = entry.getSortGroup(ruleset)
|
||||
if (category == CivilopediaCategories.UnitType && sort < 2)
|
||||
continue // Search "Domain:" entries only when the mod filter is a base ruleset
|
||||
if (category == CivilopediaCategories.Belief && sort == 0)
|
||||
continue // Search "Religions" from `getCivilopediaReligionEntry` only when the mod filter is a base ruleset
|
||||
}
|
||||
searchEntry(entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.searchEntry(entry: ICivilopediaText) {
|
||||
val scope = sequence {
|
||||
entry.getCivilopediaTextHeader()?.let { yield(it) }
|
||||
yieldAll(entry.civilopediaText)
|
||||
yieldAll(entry.getCivilopediaTextLines(ruleset))
|
||||
}
|
||||
for (line in scope) {
|
||||
if (!isActive) break
|
||||
val lineText = line.text.tr(hideIcons = true)
|
||||
if (!checkLine(lineText)) continue
|
||||
addResult(entry)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private fun CoroutineScope.addResult(entry: ICivilopediaText) {
|
||||
launchOnGLThread {
|
||||
val actor = entry.getIconName().toLabel(alignment = Align.left)
|
||||
val link = entry.makeLink()
|
||||
resultExpander.innerTable.add(actor).row()
|
||||
actor.onClick {
|
||||
linkAction(link)
|
||||
close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishSearch() {
|
||||
searchButton.enable()
|
||||
if (!resultExpander.innerTable.cells.isEmpty) return
|
||||
val nothingFound = FormattedLine("Nothing found!", color = "#f53", header = 3, centered = true)
|
||||
.render(0f)
|
||||
resultExpander.innerTable.add(nothingFound)
|
||||
}
|
||||
|
||||
class ModSelectEntry(val key: String, val translate: Boolean = false) {
|
||||
override fun toString() = if (translate) key.tr() else key
|
||||
}
|
||||
|
||||
private inner class ModSelectBox : SelectBox<ModSelectEntry>(BaseScreen.skin) {
|
||||
init {
|
||||
val mods = pediaScreen.ruleset.mods
|
||||
val entries = GdxArray<ModSelectEntry>(mods.size + 1)
|
||||
entries.add(ModSelectEntry("-Combined-", true))
|
||||
// This intersect is needed when pedia was called from the MainMenuScreen with an easter egg ruleset active -
|
||||
// they are not in the cache and have their elements not marked with originRuleset anyway.
|
||||
for (mod in mods.intersect(RulesetCache.keys)) entries.add(ModSelectEntry(mod))
|
||||
items = entries
|
||||
selectedIndex = 0
|
||||
}
|
||||
|
||||
fun selectedRuleset(): Ruleset =
|
||||
if (selectedIndex == 0) pediaScreen.ruleset
|
||||
else RulesetCache[selected.key]!! // `!!` guarded by the intersect above
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ import com.unciv.ui.components.ColorMarkupLabel
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.ui.images.ImageGetter
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.ui.components.extensions.toLabel
|
||||
import com.unciv.utils.Log
|
||||
import kotlin.math.max
|
||||
|
||||
|
@ -4,9 +4,9 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.models.ruleset.IRulesetObject
|
||||
import com.unciv.models.ruleset.Ruleset
|
||||
import com.unciv.models.ruleset.RulesetObject
|
||||
import com.unciv.models.stats.INamed
|
||||
|
||||
|
||||
/** Addon common to most ruleset game objects managing civilopedia display
|
||||
*
|
||||
* ### Usage:
|
||||
@ -91,7 +91,13 @@ interface ICivilopediaText {
|
||||
return SimpleCivilopediaText(newLines.toList())
|
||||
}
|
||||
|
||||
/** Create the correct string for a Civilopedia link */
|
||||
/** Create the correct string for a Civilopedia link.
|
||||
*
|
||||
* To actually make it work both as link and as icon identifier, return a string in the form
|
||||
* category/entryname where `category` **must** correspond exactly to either name or label of
|
||||
* the correct [CivilopediaCategories] member. `entryname` must equal the
|
||||
* [ruleset object name][RulesetObject] as defined by the [INamed] interface.
|
||||
*/
|
||||
fun makeLink(): String
|
||||
|
||||
/** Overrides alphabetical sorting in Civilopedia
|
||||
|
Loading…
Reference in New Issue
Block a user