From 8fb55e77a36b3c8e9f72452bdbd7ba48c258b91e Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Sun, 4 Jul 2021 20:25:58 +0200 Subject: [PATCH] ExpanderTab revisited (#4357) * ExpanderTab revisited * ExpanderTab revisited - patch1 --- core/src/com/unciv/ui/trade/ExpanderTab.kt | 109 +++++++++++++----- .../com/unciv/ui/trade/OffersListScroll.kt | 15 +-- 2 files changed, 87 insertions(+), 37 deletions(-) diff --git a/core/src/com/unciv/ui/trade/ExpanderTab.kt b/core/src/com/unciv/ui/trade/ExpanderTab.kt index c7a9e2c41b..195edd9478 100644 --- a/core/src/com/unciv/ui/trade/ExpanderTab.kt +++ b/core/src/com/unciv/ui/trade/ExpanderTab.kt @@ -1,45 +1,94 @@ package com.unciv.ui.trade +import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.math.Interpolation import com.badlogic.gdx.scenes.scene2d.Touchable -import com.badlogic.gdx.scenes.scene2d.ui.Skin +import com.badlogic.gdx.scenes.scene2d.actions.FloatAction import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.utils.Align +import com.unciv.UncivGame +import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.onClick import com.unciv.ui.utils.toLabel -class ExpanderTab(private val title:String,skin: Skin): Table(skin){ - private val toggle = Table(skin) // the show/hide toggler - private val tab = Table() // what holds the information to be shown/hidden - val innerTable= Table() // the information itself - var isOpen=true +/** + * A widget with a header that when clicked shows/hides a sub-Table. + * + * @param title The header text, automatically translated. + * @param defaultPad Padding between content and wrapper. Header padding is currently not modifiable. + * @param initContent Optional lambda with [innerTable] as parameter, to help initialize content. + */ +class ExpanderTab( + title: String, + startsOutOpened: Boolean = true, + defaultPad: Float = 10f, + initContent: ((Table) -> Unit)? = null +): Table(CameraStageBaseScreen.skin) { + private companion object { + const val fontSize = 24 + const val arrowSize = 18f + const val arrowImage = "OtherIcons/BackArrow" + val arrowColor = Color(1f,0.96f,0.75f,1f) + const val animationDuration = 0.2f + } - init{ - toggle.defaults().pad(10f) - toggle.touchable= Touchable.enabled - toggle.background(ImageGetter.getBackground(ImageGetter.getBlue())) - toggle.add("+ $title".toLabel(fontSize = 24)) - toggle.onClick { - if(isOpen) close() - else open() + private val header = Table(skin) // Header with label and icon, touchable to show/hide + private val headerLabel = title.toLabel(fontSize = fontSize) + private val headerIcon = ImageGetter.getImage(arrowImage) + private val contentWrapper = Table() // Wrapper for innerTable, this is what will be shown/hidden + + /** The container where the client should add the content to toggle */ + val innerTable = Table() + + /** Indicates whether the contents are currently shown, changing this will animate the widget */ + var isOpen = startsOutOpened + private set(value) { + if (value == field) return + field = value + update() } - add(toggle).fill().row() - tab.add(innerTable).pad(10f) - add(tab) + + init { + header.defaults().pad(10f) + headerIcon.setSize(arrowSize, arrowSize) + headerIcon.setOrigin(Align.center) + headerIcon.rotation = 180f + headerIcon.color = arrowColor + header.background(ImageGetter.getBackground(ImageGetter.getBlue())) + header.add(headerLabel) + header.add(headerIcon).size(arrowSize).align(Align.center) + header.touchable= Touchable.enabled + header.onClick { toggle() } + add(header).expandX().fill().row() + contentWrapper.defaults().pad(defaultPad) + add(contentWrapper).expandX() + initContent?.invoke(innerTable) + update(noAnimation = true) } - fun close(){ - if(!isOpen) return - toggle.clearChildren() - toggle.add("- $title".toLabel(fontSize = 24)) - tab.clear() - isOpen=false + private fun update(noAnimation: Boolean = false) { + if (noAnimation || !UncivGame.Current.settings.continuousRendering) { + contentWrapper.clear() + if (isOpen) contentWrapper.add(innerTable) + headerIcon.rotation = if (isOpen) 90f else 180f + return + } + val action = object: FloatAction ( 90f, 180f, animationDuration, Interpolation.linear) { + override fun update(percent: Float) { + super.update(percent) + headerIcon.rotation = this.value + if (this.isComplete) { + contentWrapper.clear() + if (isOpen) contentWrapper.add(innerTable) + } + } + }.apply { isReverse = isOpen } + addAction(action) } - fun open(){ - if(isOpen) return - toggle.clearChildren() - toggle.add("+ $title".toLabel(fontSize = 24)) - tab.add(innerTable) - isOpen=true + /** Toggle [isOpen], animated */ + fun toggle() { + isOpen = !isOpen } -} \ No newline at end of file +} diff --git a/core/src/com/unciv/ui/trade/OffersListScroll.kt b/core/src/com/unciv/ui/trade/OffersListScroll.kt index 31f1b34876..f6d757dfa6 100644 --- a/core/src/com/unciv/ui/trade/OffersListScroll.kt +++ b/core/src/com/unciv/ui/trade/OffersListScroll.kt @@ -30,8 +30,8 @@ class OffersListScroll(val onOfferClicked: (TradeOffer) -> Unit) : ScrollPane(nu table.clear() expanderTabs.clear() - for (offertype in values()) { - val labelName = when(offertype){ + for (offerType in values()) { + val labelName = when(offerType){ Gold, Gold_Per_Turn, Treaty,Agreement,Introduction -> "" Luxury_Resource -> "Luxury resources" Strategic_Resource -> "Strategic resources" @@ -39,10 +39,11 @@ class OffersListScroll(val onOfferClicked: (TradeOffer) -> Unit) : ScrollPane(nu WarDeclaration -> "Declarations of war" City -> "Cities" } - val offersOfType = offersToDisplay.filter { it.type == offertype } - if (labelName!="" && offersOfType.any()) { - expanderTabs[offertype] = ExpanderTab(labelName.tr(), CameraStageBaseScreen.skin) - expanderTabs[offertype]!!.innerTable.defaults().pad(5f) + val offersOfType = offersToDisplay.filter { it.type == offerType } + if (labelName.isNotEmpty() && offersOfType.any()) { + expanderTabs[offerType] = ExpanderTab(labelName) { + it.defaults().pad(5f) + } } } @@ -85,4 +86,4 @@ class OffersListScroll(val onOfferClicked: (TradeOffer) -> Unit) : ScrollPane(nu } actor = table } -} \ No newline at end of file +}