Diplomacy trade layout fix (#8808)

* Diplomacy and Trade - Linting

* Diplomacy and Trade - Fix gradual layout deterioration
This commit is contained in:
SomeTroglodyte 2023-03-04 18:19:24 +01:00 committed by GitHub
parent 253c669ba9
commit 5e61b0d313
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 52 deletions

View File

@ -56,10 +56,11 @@ import com.unciv.ui.components.AutoScrollPane as ScrollPane
* *
* When [selectCiv] is given and [selectTrade] is not, that Civilization is selected as if clicked on the left side. * When [selectCiv] is given and [selectTrade] is not, that Civilization is selected as if clicked on the left side.
* When [selectCiv] and [selectTrade] are supplied, that Trade for that Civilization is selected, used for the counter-offer option from `TradePopup`. * When [selectCiv] and [selectTrade] are supplied, that Trade for that Civilization is selected, used for the counter-offer option from `TradePopup`.
* Note calling this with [selectCiv] a City State and [selectTrade] supplied is **not allowed**.
*/ */
@Suppress("KDocUnresolvedReference") // Mentioning non-field parameters is flagged, but they work anyway @Suppress("KDocUnresolvedReference") // Mentioning non-field parameters is flagged, but they work anyway
class DiplomacyScreen( class DiplomacyScreen(
val viewingCiv: Civilization, private val viewingCiv: Civilization,
private val selectCiv: Civilization? = null, private val selectCiv: Civilization? = null,
private val selectTrade: Trade? = null private val selectTrade: Trade? = null
): BaseScreen(), RecreateOnResize { ): BaseScreen(), RecreateOnResize {
@ -69,7 +70,7 @@ class DiplomacyScreen(
} }
private val leftSideTable = Table().apply { defaults().pad(nationIconPad) } private val leftSideTable = Table().apply { defaults().pad(nationIconPad) }
val leftSideScroll = ScrollPane(leftSideTable) private val leftSideScroll = ScrollPane(leftSideTable)
private val rightSideTable = Table() private val rightSideTable = Table()
private val closeButton = Constants.close.toTextButton() private val closeButton = Constants.close.toTextButton()
@ -169,20 +170,13 @@ class DiplomacyScreen(
rightSideTable.clear() rightSideTable.clear()
UncivGame.Current.musicController.chooseTrack(otherCiv.civName, UncivGame.Current.musicController.chooseTrack(otherCiv.civName,
MusicMood.peaceOrWar(viewingCiv.isAtWarWith(otherCiv)),MusicTrackChooserFlags.setSelectNation) MusicMood.peaceOrWar(viewingCiv.isAtWarWith(otherCiv)),MusicTrackChooserFlags.setSelectNation)
if (otherCiv.isCityState()) rightSideTable.add( rightSideTable.add(ScrollPane(
ScrollPane(getCityStateDiplomacyTable(otherCiv)) if (otherCiv.isCityState()) getCityStateDiplomacyTable(otherCiv)
) else getMajorCivDiplomacyTable(otherCiv)
else rightSideTable.add(ScrollPane(getMajorCivDiplomacyTable(otherCiv))) )).height(stage.height)
.height(stage.height)
}
private fun setTrade(civ: Civilization): TradeTable {
rightSideTable.clear()
val tradeTable = TradeTable(civ, this)
rightSideTable.add(tradeTable)
return tradeTable
} }
//region City State Diplomacy
private fun getCityStateDiplomacyTableHeader(otherCiv: Civilization): Table { private fun getCityStateDiplomacyTableHeader(otherCiv: Civilization): Table {
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv) val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
@ -290,7 +284,6 @@ class DiplomacyScreen(
return diplomacyTable return diplomacyTable
} }
private fun getCityStateDiplomacyTable(otherCiv: Civilization): Table { private fun getCityStateDiplomacyTable(otherCiv: Civilization): Table {
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv) val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
@ -635,6 +628,8 @@ class DiplomacyScreen(
return warTable return warTable
} }
//endregion
//region Major Civ Diplomacy
private fun getMajorCivDiplomacyTable(otherCiv: Civilization): Table { private fun getMajorCivDiplomacyTable(otherCiv: Civilization): Table {
val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv) val otherCivDiplomacyManager = otherCiv.getDiplomacyManager(viewingCiv)
@ -701,6 +696,13 @@ class DiplomacyScreen(
return diplomacyTable return diplomacyTable
} }
private fun setTrade(civ: Civilization): TradeTable {
rightSideTable.clear()
val tradeTable = TradeTable(civ, this)
rightSideTable.add(tradeTable)
return tradeTable
}
private fun getNegotiatePeaceMajorCivButton( private fun getNegotiatePeaceMajorCivButton(
otherCiv: Civilization, otherCiv: Civilization,
otherCivDiplomacyManager: DiplomacyManager otherCivDiplomacyManager: DiplomacyManager
@ -909,6 +911,8 @@ class DiplomacyScreen(
return declareWarButton return declareWarButton
} }
//endregion
// response currently always gets "Very Well.", but that may expand in the future. // response currently always gets "Very Well.", but that may expand in the future.
@Suppress("SameParameterValue") @Suppress("SameParameterValue")
private fun setRightSideFlavorText( private fun setRightSideFlavorText(
@ -940,6 +944,13 @@ class DiplomacyScreen(
return goToOnMapButton return goToOnMapButton
} }
/** Calculate a width for [TradeTable] two-column layout, called from [OfferColumnsTable]
*
* _Caller is responsible to not exceed this **including its own padding**_
*/
// Note breaking the rule above will squeeze the leftSideScroll to the left - cumulatively.
internal fun getTradeColumnsWidth() = (stage.width - leftSideScroll.width - 3f) / 2 // 3 for SplitPane handle
override fun resize(width: Int, height: Int) { override fun resize(width: Int, height: Int) {
super.resize(width, height) super.resize(width, height)
positionCloseButton() positionCloseButton()

View File

@ -2,6 +2,7 @@ package com.unciv.ui.screens.diplomacyscreen
import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.Constants import com.unciv.Constants
import com.unciv.logic.civilization.Civilization
import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeLogic
import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeOffer
import com.unciv.logic.trade.TradeOffersList import com.unciv.logic.trade.TradeOffersList
@ -14,8 +15,11 @@ import com.unciv.ui.popups.AskNumberPopup
import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.basescreen.BaseScreen
/** This is the class that holds the 4 columns of the offers (ours/theirs/ offered/available) in trade */ /** This is the class that holds the 4 columns of the offers (ours/theirs/ offered/available) in trade */
class OfferColumnsTable(private val tradeLogic: TradeLogic, val screen: DiplomacyScreen, val onChange: () -> Unit): Table( class OfferColumnsTable(
BaseScreen.skin) { private val tradeLogic: TradeLogic,
private val screen: DiplomacyScreen,
private val onChange: () -> Unit
): Table(BaseScreen.skin) {
private fun addOffer(offer: TradeOffer, offerList: TradeOffersList, correspondingOfferList: TradeOffersList) { private fun addOffer(offer: TradeOffer, offerList: TradeOffersList, correspondingOfferList: TradeOffersList) {
offerList.add(offer.copy()) offerList.add(offer.copy())
@ -23,34 +27,31 @@ class OfferColumnsTable(private val tradeLogic: TradeLogic, val screen: Diplomac
onChange() onChange()
} }
private val ourAvailableOffersTable = OffersListScroll("OurAvail") { private fun offerClickImplementation(
when (it.type) { offer: TradeOffer,
TradeType.Gold -> openGoldSelectionPopup(it, tradeLogic.currentTrade.ourOffers, tradeLogic.ourCivilization.gold) invert: Boolean,
TradeType.Gold_Per_Turn -> openGoldSelectionPopup(it, tradeLogic.currentTrade.ourOffers, tradeLogic.ourCivilization.stats.statsForNextTurn.gold.toInt()) list: TradeOffersList,
else -> addOffer(it, tradeLogic.currentTrade.ourOffers, tradeLogic.currentTrade.theirOffers) counterList: TradeOffersList,
civ: Civilization
) {
when (offer.type) {
TradeType.Gold -> openGoldSelectionPopup(offer, list, civ.gold)
TradeType.Gold_Per_Turn -> openGoldSelectionPopup(offer, list, civ.stats.statsForNextTurn.gold.toInt())
else -> addOffer(if (invert) offer.copy(amount = -offer.amount) else offer, list, counterList)
} }
} }
private val ourAvailableOffersTable = OffersListScroll("OurAvail") {
tradeLogic.currentTrade.run { offerClickImplementation(it, false, ourOffers, theirOffers, tradeLogic.ourCivilization) }
}
private val ourOffersTable = OffersListScroll("OurTrade") { private val ourOffersTable = OffersListScroll("OurTrade") {
when (it.type) { tradeLogic.currentTrade.run { offerClickImplementation(it, true, ourOffers, theirOffers, tradeLogic.ourCivilization) }
TradeType.Gold -> openGoldSelectionPopup(it, tradeLogic.currentTrade.ourOffers, tradeLogic.ourCivilization.gold)
TradeType.Gold_Per_Turn -> openGoldSelectionPopup(it, tradeLogic.currentTrade.ourOffers, tradeLogic.ourCivilization.stats.statsForNextTurn.gold.toInt())
else -> addOffer(it.copy(amount = -it.amount), tradeLogic.currentTrade.ourOffers, tradeLogic.currentTrade.theirOffers)
}
} }
private val theirOffersTable = OffersListScroll("TheirTrade") { private val theirOffersTable = OffersListScroll("TheirTrade") {
when (it.type) { tradeLogic.currentTrade.run { offerClickImplementation(it, true, theirOffers, ourOffers, tradeLogic.otherCivilization) }
TradeType.Gold -> openGoldSelectionPopup(it, tradeLogic.currentTrade.theirOffers, tradeLogic.otherCivilization.gold)
TradeType.Gold_Per_Turn -> openGoldSelectionPopup(it, tradeLogic.currentTrade.theirOffers, tradeLogic.otherCivilization.stats.statsForNextTurn.gold.toInt())
else -> addOffer(it.copy(amount = -it.amount), tradeLogic.currentTrade.theirOffers, tradeLogic.currentTrade.ourOffers)
}
} }
private val theirAvailableOffersTable = OffersListScroll("TheirAvail") { private val theirAvailableOffersTable = OffersListScroll("TheirAvail") {
when (it.type) { tradeLogic.currentTrade.run { offerClickImplementation(it, false, theirOffers, ourOffers, tradeLogic.otherCivilization) }
TradeType.Gold -> openGoldSelectionPopup(it, tradeLogic.currentTrade.theirOffers, tradeLogic.otherCivilization.gold)
TradeType.Gold_Per_Turn -> openGoldSelectionPopup(it, tradeLogic.currentTrade.theirOffers, tradeLogic.otherCivilization.stats.statsForNextTurn.gold.toInt())
else -> addOffer(it, tradeLogic.currentTrade.theirOffers, tradeLogic.currentTrade.ourOffers)
}
} }
init { init {
@ -58,9 +59,10 @@ class OfferColumnsTable(private val tradeLogic: TradeLogic, val screen: Diplomac
val isPortraitMode = screen.isNarrowerThan4to3() val isPortraitMode = screen.isNarrowerThan4to3()
val columnWidth = (screen.stage.width - screen.leftSideScroll.width) / 2 val columnWidth = screen.getTradeColumnsWidth() - 20f // Subtract padding: ours and OffersListScroll's
if (!isPortraitMode) { if (!isPortraitMode) {
// In landscape, arrange in 4 panels: ours left / theirs right ; items top / offers bottom.
add("Our items".tr()) add("Our items".tr())
add("[${tradeLogic.otherCivilization.civName}]'s items".tr()).row() add("[${tradeLogic.otherCivilization.civName}]'s items".tr()).row()
@ -73,8 +75,9 @@ class OfferColumnsTable(private val tradeLogic: TradeLogic, val screen: Diplomac
add("[${tradeLogic.otherCivilization.civName}]'s trade offer".tr()).row() add("[${tradeLogic.otherCivilization.civName}]'s trade offer".tr()).row()
add(ourOffersTable).size(columnWidth, screen.stage.height / 3) add(ourOffersTable).size(columnWidth, screen.stage.height / 3)
add(theirOffersTable).size(columnWidth, screen.stage.height / 3) add(theirOffersTable).size(columnWidth, screen.stage.height / 3)
} } else {
else { // In portrait, this will arrange the items lists vertically
// and the offers still side-by-side below that
add("Our items".tr()).colspan(2).row() add("Our items".tr()).colspan(2).row()
add(ourAvailableOffersTable).height(screen.stage.height / 4f).colspan(2).row() add(ourAvailableOffersTable).height(screen.stage.height / 4f).colspan(2).row()

View File

@ -10,31 +10,33 @@ import com.unciv.ui.components.extensions.isEnabled
import com.unciv.ui.components.extensions.onClick import com.unciv.ui.components.extensions.onClick
import com.unciv.ui.components.extensions.toTextButton import com.unciv.ui.components.extensions.toTextButton
class TradeTable(private val otherCivilization: Civilization, stage: DiplomacyScreen): Table( class TradeTable(
BaseScreen.skin) { private val otherCivilization: Civilization,
val currentPlayerCiv = otherCivilization.gameInfo.getCurrentPlayerCivilization() diplomacyScreen: DiplomacyScreen
var tradeLogic = TradeLogic(currentPlayerCiv,otherCivilization) ): Table(BaseScreen.skin) {
var offerColumnsTable = OfferColumnsTable(tradeLogic, stage) { onChange() } private val currentPlayerCiv = otherCivilization.gameInfo.getCurrentPlayerCivilization()
internal val tradeLogic = TradeLogic(currentPlayerCiv, otherCivilization)
internal val offerColumnsTable = OfferColumnsTable(tradeLogic, diplomacyScreen) { onChange() }
// This is so that after a trade has been traded, we can switch out the offersToDisplay to start anew - this is the easiest way // This is so that after a trade has been traded, we can switch out the offersToDisplay to start anew - this is the easiest way
private var offerColumnsTableWrapper = Table() private val offerColumnsTableWrapper = Table()
private val offerButton = "Offer trade".toTextButton() private val offerButton = "Offer trade".toTextButton()
private fun isTradeOffered() = otherCivilization.tradeRequests.any { it.requestingCiv == currentPlayerCiv.civName } private fun isTradeOffered() = otherCivilization.tradeRequests.any { it.requestingCiv == currentPlayerCiv.civName }
private fun retractOffer(){ private fun retractOffer() {
otherCivilization.tradeRequests.removeAll { it.requestingCiv == currentPlayerCiv.civName } otherCivilization.tradeRequests.removeAll { it.requestingCiv == currentPlayerCiv.civName }
currentPlayerCiv.cache.updateCivResources() currentPlayerCiv.cache.updateCivResources()
offerButton.setText("Offer trade".tr()) offerButton.setText("Offer trade".tr())
} }
init{ init {
offerColumnsTableWrapper.add(offerColumnsTable) offerColumnsTableWrapper.add(offerColumnsTable)
add(offerColumnsTableWrapper).row() add(offerColumnsTableWrapper).row()
val lowerTable = Table().apply { defaults().pad(10f) } val lowerTable = Table().apply { defaults().pad(10f) }
val existingOffer = otherCivilization.tradeRequests.firstOrNull { it.requestingCiv == currentPlayerCiv.civName } val existingOffer = otherCivilization.tradeRequests.firstOrNull { it.requestingCiv == currentPlayerCiv.civName }
if (existingOffer != null){ if (existingOffer != null) {
tradeLogic.currentTrade.set(existingOffer.trade.reverse()) tradeLogic.currentTrade.set(existingOffer.trade.reverse())
offerColumnsTable.update() offerColumnsTable.update()
} }
@ -43,12 +45,12 @@ class TradeTable(private val otherCivilization: Civilization, stage: DiplomacySc
else offerButton.apply { isEnabled = false }.setText("Offer trade".tr()) else offerButton.apply { isEnabled = false }.setText("Offer trade".tr())
offerButton.onClick { offerButton.onClick {
if(isTradeOffered()) { if (isTradeOffered()) {
retractOffer() retractOffer()
return@onClick return@onClick
} }
otherCivilization.tradeRequests.add(TradeRequest(currentPlayerCiv.civName,tradeLogic.currentTrade.reverse())) otherCivilization.tradeRequests.add(TradeRequest(currentPlayerCiv.civName, tradeLogic.currentTrade.reverse()))
currentPlayerCiv.cache.updateCivResources() currentPlayerCiv.cache.updateCivResources()
offerButton.setText("Retract offer".tr()) offerButton.setText("Retract offer".tr())
} }
@ -61,7 +63,7 @@ class TradeTable(private val otherCivilization: Civilization, stage: DiplomacySc
pack() pack()
} }
private fun onChange(){ private fun onChange() {
offerColumnsTable.update() offerColumnsTable.update()
retractOffer() retractOffer()
offerButton.isEnabled = !(tradeLogic.currentTrade.theirOffers.size == 0 && tradeLogic.currentTrade.ourOffers.size == 0) offerButton.isEnabled = !(tradeLogic.currentTrade.theirOffers.size == 0 && tradeLogic.currentTrade.ourOffers.size == 0)