From 8385f814a6dd148451884142d31801421af3c440 Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Mon, 4 Apr 2022 17:06:58 +0200 Subject: [PATCH] Tabbed pager architecture update (#6460) * Change TabbedPager mechanism to communicate page activation * Change TabbedPager mechanism for fixed content * OptionsPopup better use of TabbedPager * TabbedPager arrow keys * After-merge patch Co-authored-by: Yair Morgenstern --- .../overviewscreen/DiplomacyOverviewTable.kt | 4 +- .../ui/overviewscreen/EmpireOverviewScreen.kt | 21 +--- .../ui/overviewscreen/EmpireOverviewTab.kt | 17 +-- .../overviewscreen/ReligionOverviewTable.kt | 4 +- .../overviewscreen/ResourcesOverviewTable.kt | 1 - .../ui/overviewscreen/UnitOverviewTable.kt | 15 +-- .../ui/overviewscreen/WonderOverviewTable.kt | 4 +- core/src/com/unciv/ui/utils/TabbedPager.kt | 113 ++++++++++++------ .../ui/worldscreen/mainmenu/OptionsPopup.kt | 73 ++++++----- 9 files changed, 144 insertions(+), 108 deletions(-) diff --git a/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt index 5ff37ea9bf..ff1d80756a 100644 --- a/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/DiplomacyOverviewTable.kt @@ -61,9 +61,7 @@ class DiplomacyOverviewTab ( update() } - override fun getFixedContent(): WidgetGroup { - return fixedContent - } + override fun getFixedContent() = fixedContent // Refresh content and determine landscape/portrait layout private fun update() { diff --git a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt index 05339a9bd2..ec78ea5d7f 100644 --- a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewScreen.kt @@ -52,10 +52,8 @@ class EmpireOverviewScreen( keyPressDispatcher = keyPressDispatcher, capacity = EmpireOverviewCategories.values().size) - tabbedPager.addPage(Constants.close) { - _, _ -> game.setWorldScreen() - } - tabbedPager.getPageButton(0).setColor(0.75f, 0.1f, 0.1f, 1f) + tabbedPager.bindArrowKeys() + tabbedPager.addClosePage { game.setWorldScreen() } for (category in EmpireOverviewCategories.values()) { val tabState = category.stateTester(viewingPlayer) @@ -70,17 +68,8 @@ class EmpireOverviewScreen( icon, iconSize, disabled = tabState != EmpireOverviewTabState.Normal, shortcutKey = category.shortcutKey, - scrollAlign = category.scrollAlign, - fixedContent = pageObject.getFixedContent(), - onDeactivation = { _, _, scrollY -> pageObject.deactivated(scrollY) } - ) { - index, name -> - val scrollY = pageObject.activated() - if (scrollY != null) tabbedPager.setPageScrollY(index, scrollY) - if (name == "Stats") - game.settings.addCompletedTutorialTask("See your stats breakdown") - game.settings.lastOverviewPage = name - } + scrollAlign = category.scrollAlign + ) if (category.name == page) tabbedPager.selectPage(index) } @@ -99,6 +88,6 @@ class EmpireOverviewScreen( fun resizePage(tab: EmpireOverviewTab) { val category = (pageObjects.entries.find { it.value == tab } ?: return).key - tabbedPager.replacePage(category.name, tab, tab.getFixedContent()) + tabbedPager.replacePage(category.name, tab) } } diff --git a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewTab.kt b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewTab.kt index a9ae8cd952..cd8adfc1a0 100644 --- a/core/src/com/unciv/ui/overviewscreen/EmpireOverviewTab.kt +++ b/core/src/com/unciv/ui/overviewscreen/EmpireOverviewTab.kt @@ -2,10 +2,10 @@ package com.unciv.ui.overviewscreen import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup import com.badlogic.gdx.utils.Align import com.unciv.logic.civilization.CivilizationInfo import com.unciv.ui.utils.BaseScreen +import com.unciv.ui.utils.TabbedPager import com.unciv.ui.utils.packIfNeeded import com.unciv.ui.utils.toLabel @@ -13,17 +13,18 @@ abstract class EmpireOverviewTab ( val viewingPlayer: CivilizationInfo, val overviewScreen: EmpireOverviewScreen, persistedData: EmpireOverviewTabPersistableData? = null -) : Table(BaseScreen.skin) { +) : Table(BaseScreen.skin), TabbedPager.IPageExtensions { open class EmpireOverviewTabPersistableData { open fun isEmpty() = true } open val persistableData = persistedData ?: EmpireOverviewTabPersistableData() - /** Override if your Tab needs to do stuff on activation. @return non-null to scroll the Tab vertically within the TabbedPager. */ - open fun activated(): Float? = null - /** Override if your Tab needs to do housekeeping when it loses focus. [scrollY] is the Tab's current vertical scroll position. */ - open fun deactivated(scrollY: Float) {} - /** Override to supply content not participating in scrolling */ - open fun getFixedContent(): WidgetGroup? = null + + override fun activated(index: Int, caption: String, pager: TabbedPager) { + val settings = overviewScreen.game.settings + if (caption == "Stats") + settings.addCompletedTutorialTask("See your stats breakdown") + settings.lastOverviewPage = caption + } val gameInfo = viewingPlayer.gameInfo diff --git a/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt index d7eaf051b3..afd9e969f0 100644 --- a/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/ReligionOverviewTable.kt @@ -37,8 +37,7 @@ class ReligionOverviewTab( private val statsTable = Table() private val beliefsTable = Table() - override fun getFixedContent(): WidgetGroup? { - return Table().apply { + override fun getFixedContent() = Table().apply { defaults().pad(5f) align(Align.top) @@ -49,7 +48,6 @@ class ReligionOverviewTab( add(religionButtonLabel) addSeparator() } - } init { defaults().pad(5f) diff --git a/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt index b55ac53b47..500e200a5f 100644 --- a/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/ResourcesOverviewTable.kt @@ -3,7 +3,6 @@ package com.unciv.ui.overviewscreen import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo diff --git a/core/src/com/unciv/ui/overviewscreen/UnitOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/UnitOverviewTable.kt index 21f83c7b9b..5721c5e5cd 100644 --- a/core/src/com/unciv/ui/overviewscreen/UnitOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/UnitOverviewTable.kt @@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.scenes.scene2d.Group import com.badlogic.gdx.scenes.scene2d.ui.Table -import com.badlogic.gdx.scenes.scene2d.ui.WidgetGroup import com.badlogic.gdx.utils.Align import com.unciv.Constants import com.unciv.logic.civilization.CivilizationInfo @@ -30,9 +29,13 @@ class UnitOverviewTab( } override val persistableData = (persistedData as? UnitTabPersistableData) ?: UnitTabPersistableData() - override fun activated() = persistableData.scrollY - override fun deactivated(scrollY: Float) { - persistableData.scrollY = scrollY + override fun activated(index: Int, caption: String, pager: TabbedPager) { + if (persistableData.scrollY != null) + pager.setPageScrollY(index, persistableData.scrollY!!) + super.activated(index, caption, pager) + } + override fun deactivated(index: Int, caption: String, pager: TabbedPager) { + persistableData.scrollY = pager.getPageScrollY(index) } private val supplyTableWidth = (overviewScreen.stage.width * 0.25f).coerceAtLeast(240f) @@ -40,9 +43,7 @@ class UnitOverviewTab( private val unitHeaderTable = Table() private val fixedContent = Table() - override fun getFixedContent(): WidgetGroup { - return fixedContent - } + override fun getFixedContent() = fixedContent init { fixedContent.add(getUnitSupplyTable()).align(Align.top).padBottom(10f).row() diff --git a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt index dbdbad8946..b398d077f8 100644 --- a/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt +++ b/core/src/com/unciv/ui/overviewscreen/WonderOverviewTable.kt @@ -81,9 +81,7 @@ class WonderOverviewTab( private val wonders: Array = collectInfo() private val fixedContent = Table() - override fun getFixedContent(): WidgetGroup { - return fixedContent - } + override fun getFixedContent() = fixedContent init { fixedContent.apply { diff --git a/core/src/com/unciv/ui/utils/TabbedPager.kt b/core/src/com/unciv/ui/utils/TabbedPager.kt index a3008b4b4a..305334c548 100644 --- a/core/src/com/unciv/ui/utils/TabbedPager.kt +++ b/core/src/com/unciv/ui/utils/TabbedPager.kt @@ -1,5 +1,6 @@ package com.unciv.ui.utils +import com.badlogic.gdx.Input import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.* import com.badlogic.gdx.scenes.scene2d.ui.* @@ -9,11 +10,8 @@ import com.unciv.Constants import com.unciv.UncivGame import com.unciv.ui.utils.UncivTooltip.Companion.addTooltip - -/* - Unimplemented ideas: - Use fixedContent for OptionsPopup mod check tab - */ +//TODO If keys are assigned, the widget is in a popup not filling stage width, and a button is +// partially visible on the right end, the key tooltip will show outside the parent. /** * Implements a 'Tabs' widget where different pages can be switched by selecting a header button. @@ -72,10 +70,27 @@ class TabbedPager( private val fixedContentScroll = LinkedScrollPane(horizontalOnly = true) private val fixedContentScrollCell: Cell private val contentScroll = LinkedScrollPane(horizontalOnly = false, linkTo = fixedContentScroll) + private var savedScrollListener: EventListener? = null private val deferredSecretPages = ArrayDeque(0) private var askPasswordLock = false + //endregion + //region Public Interfaces + + /** Pages added via [addPage] can optionally implement this to get notified when they are + * [activated] or [deactivated], or to provide [fixed content][getFixedContent] */ + interface IPageExtensions { + /** Called by [TabbedPager] after a page is shown, whether by user click or programmatically. */ + fun activated(index: Int, caption: String, pager: TabbedPager) + + /** Called by [TabbedPager] before a page is hidden, whether by user click or programmatically. */ + fun deactivated(index: Int, caption: String, pager: TabbedPager) {} + + /** @return Optional second content [Actor], will be placed outside the tab's main [ScrollPane] between header and `content`. Scrolls horizontally only. */ + fun getFixedContent(): Actor? = null + } + //endregion //region Private Classes @@ -84,8 +99,6 @@ class TabbedPager( var content: Actor, var fixedContent: Actor?, var disabled: Boolean, - val onActivation: ((Int, String) -> Unit)?, - val onDeactivation: ((Int, String, Float) -> Unit)?, icon: Actor?, iconSize: Float, val shortcutKey: KeyCharAndCode, @@ -247,6 +260,12 @@ class TabbedPager( } } + private class EmptyClosePage(private val action: ()->Unit) : Actor(), IPageExtensions { + override fun activated(index: Int, caption: String, pager: TabbedPager) { + action() + } + } + //endregion //region Initialization @@ -312,7 +331,7 @@ class TabbedPager( if (activePage != -1) { val page = pages[activePage] - page.onDeactivation?.invoke(activePage, page.caption, contentScroll.scrollY) + (page.content as? IPageExtensions)?.deactivated(activePage, page.caption, this) page.button.color = Color.WHITE fixedContentScroll.actor = null page.scrollX = contentScroll.scrollX @@ -359,7 +378,8 @@ class TabbedPager( else // when coming from a tap/click, can we at least ensure no part of it is outside the visible area headerScroll.run { scrollX = scrollX.coerceIn((page.buttonX + page.buttonW - scrollWidth)..page.buttonX) } - page.onActivation?.invoke(index, page.caption) + + (page.content as? IPageExtensions)?.activated(index, page.caption, this) } return true } @@ -393,6 +413,12 @@ class TabbedPager( /** Access a page's header button e.g. for unusual formatting */ fun getPageButton(index: Int) = pages[index].button + /** Query the vertical scroll position af a page's contents */ + fun getPageScrollY(index: Int): Float { + if (index == activePage) return contentScroll.scrollY + if (index !in 0 until pages.size) return 0f + return pages[index].scrollY + } /** Change the vertical scroll position af a page's contents */ fun setPageScrollY(index: Int, scrollY: Float, animation: Boolean = false) { if (index !in 0 until pages.size) return @@ -403,6 +429,32 @@ class TabbedPager( if (!animation) contentScroll.updateVisualScroll() } + /** Disable/Enable built-in ScrollPane for content pages, including focus stealing prevention */ + fun setScrollDisabled(disabled: Boolean) { + if (disabled == contentScroll.isScrollingDisabledY) return + contentScroll.setScrollingDisabled(disabled, disabled) + if (disabled) { + savedScrollListener = contentScroll.captureListeners.first() + contentScroll.captureListeners.clear() + } else { + if (savedScrollListener != null) + contentScroll.addCaptureListener(savedScrollListener) + } + } + + /** Bind arrow keys to navigate pages left/right. + * Needs [keyPressDispatcher] to be set on instantiation. + * Caller is responsible for cleanup if necessary. */ + fun bindArrowKeys() { + if (keyPressDispatcher == null) return + fun cyclePage(direction: Int) { + if (activePage == -1) return + selectPage((activePage + direction).coerceIn(0 until pages.size)) + } + keyPressDispatcher[KeyCharAndCode(Input.Keys.LEFT)] = { cyclePage(-1) } + keyPressDispatcher[KeyCharAndCode(Input.Keys.RIGHT)] = { cyclePage(1) } + } + /** Remove a page by its index. * @return `true` if page successfully removed */ fun removePage(index: Int): Boolean { @@ -425,18 +477,7 @@ class TabbedPager( if (isActive) selectPage(-1) pages[index].let { it.content = content - measureContent(it) - } - if (isActive) selectPage(index) - } - /** Replace a page's [content] and [fixedContent] by its [index]. */ - fun replacePage(index: Int, content: Actor, fixedContent: Actor?) { - if (index !in 0 until pages.size) return - val isActive = index == activePage - if (isActive) selectPage(-1) - pages[index].let { - it.content = content - it.fixedContent = fixedContent + it.fixedContent = (content as? IPageExtensions)?.getFixedContent() measureContent(it) } if (isActive) selectPage(index) @@ -444,22 +485,17 @@ class TabbedPager( /** Replace a page's [content] by its [caption]. */ fun replacePage(caption: String, content: Actor) = replacePage(getPageIndex(caption), content) - /** Replace a page's [content] and [fixedContent] by its [caption]. */ - fun replacePage(caption: String, content: Actor, fixedContent: Actor?) = replacePage(getPageIndex(caption), content, fixedContent) /** Add a page! * @param caption Text to be shown on the header button (automatically translated), can later be used to reference the page in other calls. - * @param content [Actor] to show in the lower area when this page is selected. + * @param content [Actor] to show in the lower area when this page is selected. Can optionally implement [IPageExtensions] to be notified of activation or deactivation. * @param icon Actor, typically an [Image], to show before the caption on the header button. * @param iconSize Size for [icon] - if not zero, the icon is wrapped to allow a [setSize] even on [Image] which ignores size. * @param insertBefore -1 to add at the end, or index of existing page to insert this before it. * @param secret Marks page as 'secret'. A password is asked once per [TabbedPager] and if it does not match the has passed in the constructor the page and all subsequent secret pages are dropped. * @param disabled Initial disabled state. Disabled pages cannot be selected even with [selectPage], their button is dimmed. * @param shortcutKey Optional keyboard key to associate - goes to the [KeyPressDispatcher] passed in the constructor. - * @param syncScroll If on, the ScrollPanes for [content] and [fixedContent] will synchronize horizontally. - * @param fixedContent Optional second content [Actor], will be placed outside the tab's main [ScrollPane] between header and [content]. Scrolls horizontally only. - * @param onDeactivation _Optional_ callback called when this page is hidden. Lambda arguments are page index and caption, and scrollY of the tab's [ScrollPane]. - * @param onActivation _Optional_ callback called when this page is shown (per actual change to this page, not per header click). Lambda arguments are page index and caption. + * @param syncScroll If on, the ScrollPanes for [content] and [fixed content][IPageExtensions.getFixedContent] will synchronize horizontally. * @return The new page's index or -1 if it could not be immediately added (secret). */ fun addPage( @@ -472,19 +508,14 @@ class TabbedPager( disabled: Boolean = false, shortcutKey: KeyCharAndCode = KeyCharAndCode.UNKNOWN, scrollAlign: Int = Align.top, - syncScroll: Boolean = true, - fixedContent: Actor? = null, - onDeactivation: ((Int, String, Float) -> Unit)? = null, - onActivation: ((Int, String) -> Unit)? = null + syncScroll: Boolean = true ): Int { // Build page descriptor and header button val page = PageState( caption = caption, content = content ?: Group(), - fixedContent = fixedContent, + fixedContent = (content as? IPageExtensions)?.getFixedContent(), disabled = disabled, - onActivation = onActivation, - onDeactivation = onDeactivation, icon = icon, iconSize = iconSize, shortcutKey = shortcutKey, @@ -514,6 +545,18 @@ class TabbedPager( return addAndShowPage(page, insertBefore) } + /** + * Add a "Close" button tho the Tab headers, with empty content which will invoke [action] when clicked + */ + fun addClosePage( + insertBefore: Int = -1, + color: Color = Color(0.75f, 0.1f, 0.1f, 1f), + action: ()->Unit + ) { + val index = addPage(Constants.close, EmptyClosePage(action), insertBefore = insertBefore) + pages[index].button.color = color + } + /** * Activate any [secret][addPage] pages by asking for the password. * diff --git a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt index ebf92736de..1c305c9e11 100644 --- a/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/mainmenu/OptionsPopup.kt @@ -16,6 +16,7 @@ import com.unciv.UncivGame import com.unciv.logic.MapSaver import com.unciv.logic.civilization.PlayerType import com.unciv.models.UncivSound +import com.unciv.models.metadata.BaseRuleset import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.Ruleset.RulesetError import com.unciv.models.ruleset.Ruleset.RulesetErrorSeverity @@ -59,7 +60,6 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { private var modCheckBaseSelect: TranslatedSelectBox? = null private val modCheckResultTable = Table() private val selectBoxMinWidth: Float - private val previousMaxWorldZoom = settings.maxWorldZoomOut //endregion @@ -81,7 +81,7 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { tabMaxHeight = (if (isPortrait()) 0.7f else 0.8f) * stage.height } tabs = TabbedPager(tabMinWidth, tabMaxWidth, 0f, tabMaxHeight, - headerFontSize = 21, backgroundColor = Color.CLEAR, capacity = 8) + headerFontSize = 21, backgroundColor = Color.CLEAR, keyPressDispatcher = this.keyPressDispatcher, capacity = 8) add(tabs).pad(0f).grow().row() tabs.addPage("About", getAboutTab(), ImageGetter.getExternalImage("Icon.png"), 24f) @@ -91,14 +91,17 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { tabs.addPage("Sound", getSoundTab(), ImageGetter.getImage("OtherIcons/Speaker"), 24f) tabs.addPage("Multiplayer", getMultiplayerTab(), ImageGetter.getImage("OtherIcons/Multiplayer"), 24f) tabs.addPage("Advanced", getAdvancedTab(), ImageGetter.getImage("OtherIcons/Settings"), 24f) - if (RulesetCache.size > 1) { - tabs.addPage("Locate mod errors", getModCheckTab(), ImageGetter.getImage("OtherIcons/Mods"), 24f) { _, _ -> + if (RulesetCache.size > BaseRuleset.values().size) { + val content = ModCheckTab(this) { if (modCheckFirstRun) runModChecker() + else runModChecker(modCheckBaseSelect!!.selected.value) } + tabs.addPage("Locate mod errors", content, ImageGetter.getImage("OtherIcons/Mods"), 24f) } if (Gdx.input.isKeyPressed(Input.Keys.SHIFT_RIGHT) && (Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT) || Gdx.input.isKeyPressed(Input.Keys.ALT_RIGHT))) { tabs.addPage("Debug", getDebugTab(), ImageGetter.getImage("OtherIcons/SecretOptions"), 24f, secret = true) } + tabs.bindArrowKeys() // If we're sharing WorldScreen's dispatcher that's OK since it does revertToCheckPoint on update addCloseButton { previousScreen.game.musicController.onChange(null) @@ -274,27 +277,22 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { settings.save() connectionToServerButton.isEnabled = multiplayerServerTextField.text != Constants.dropboxMultiplayerServer } - serverIpTable.add(multiplayerServerTextField).width(screen.stage.width / 2) - add(serverIpTable).row() + serverIpTable.add(multiplayerServerTextField).minWidth(screen.stage.width / 2).growX() + add(serverIpTable).fillX().row() add("Reset to Dropbox".toTextButton().onClick { multiplayerServerTextField.text = Constants.dropboxMultiplayerServer }).row() add(connectionToServerButton.onClick { - val popup = Popup(screen).apply { + val popup = Popup(screen).apply { addGoodSizedLabel("Awaiting response...").row() } popup.open(true) - successfullyConnectedToServer { success: Boolean, result: String -> - if (success) { - popup.addGoodSizedLabel("Success!").row() - popup.addCloseButton() - } else { - popup.addGoodSizedLabel("Failed!").row() - popup.addCloseButton() - } + successfullyConnectedToServer { success: Boolean, _: String -> + popup.addGoodSizedLabel(if (success) "Success!" else "Failed!").row() + popup.addCloseButton() } }).row() } @@ -373,27 +371,38 @@ class OptionsPopup(val previousScreen: BaseScreen) : Popup(previousScreen) { addSetUserId() } - private fun getModCheckTab() = Table(BaseScreen.skin).apply { - defaults().pad(10f).align(Align.top) - val reloadModsButton = "Reload mods".toTextButton().onClick { - runModChecker(modCheckBaseSelect!!.selected.value) - } - add(reloadModsButton).row() + private class ModCheckTab( + options: OptionsPopup, + private val runAction: ()->Unit + ) : Table(), TabbedPager.IPageExtensions { + private val fixedContent = Table() - val labeledBaseSelect = Table(BaseScreen.skin).apply { - add("Check extension mods based on:".toLabel()).padRight(10f) - val baseMods = listOf(modCheckWithoutBase) + RulesetCache.getSortedBaseRulesets() - modCheckBaseSelect = TranslatedSelectBox(baseMods, modCheckWithoutBase, BaseScreen.skin).apply { - selectedIndex = 0 - onChange { - runModChecker(modCheckBaseSelect!!.selected.value) + init { + defaults().pad(10f).align(Align.top) + + fixedContent.defaults().pad(10f).align(Align.top) + val reloadModsButton = "Reload mods".toTextButton().onClick(runAction) + fixedContent.add(reloadModsButton).row() + + val labeledBaseSelect = Table().apply { + add("Check extension mods based on:".toLabel()).padRight(10f) + val baseMods = listOf(modCheckWithoutBase) + RulesetCache.getSortedBaseRulesets() + options.modCheckBaseSelect = TranslatedSelectBox(baseMods, modCheckWithoutBase, BaseScreen.skin).apply { + selectedIndex = 0 + onChange { runAction() } } + add(options.modCheckBaseSelect) } - add(modCheckBaseSelect) - } - add(labeledBaseSelect).row() + fixedContent.add(labeledBaseSelect).row() - add(modCheckResultTable) + add(options.modCheckResultTable) + } + + override fun getFixedContent() = fixedContent + + override fun activated(index: Int, caption: String, pager: TabbedPager) { + runAction() + } } private fun runModChecker(base: String = modCheckWithoutBase) {