Переглянути джерело

CMarketBase::hRight CMarketBase::hLeft removed. Final changes

SoundSSGood 1 рік тому
батько
коміт
c6c213c454

+ 1 - 1
client/widgets/CArtifactsOfHeroBackpack.h

@@ -24,7 +24,7 @@ class CArtifactsOfHeroBackpack : public CArtifactsOfHeroBase
 public:
 	CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_t slotsRowsMax);
 	CArtifactsOfHeroBackpack();
-	void onSliderMoved(int newVal);;
+	void onSliderMoved(int newVal);
 	void updateBackpackSlots(const std::optional<const ArtifactPosition> & removedSlot = std::nullopt) override;
 	size_t getActiveSlotRowsNum();
 	size_t getSlotsNum();

+ 1 - 1
client/widgets/CArtifactsOfHeroBase.h

@@ -41,7 +41,7 @@ public:
 	virtual void unmarkSlots();
 	virtual ArtPlacePtr getArtPlace(const ArtifactPosition & slot);
 	virtual void updateWornSlots();
-	virtual void updateBackpackSlots(const std::optional<const ArtifactPosition> & removedSlot = std::nullopt);
+	virtual void updateBackpackSlots(const std::optional<const ArtifactPosition> & removedSlot);
 	virtual void updateSlot(const ArtifactPosition & slot);
 	virtual const CArtifactInstance * getPickedArtifact();
 	void addGestureCallback(CArtPlace::ClickFunctor callback);

+ 1 - 1
client/widgets/CArtifactsOfHeroMarket.h

@@ -14,7 +14,7 @@
 class CArtifactsOfHeroMarket : public CArtifactsOfHeroBase
 {
 public:
-	std::function<void(CArtPlace*)> selectArtCallback;
+	std::function<void(const CArtPlace*)> selectArtCallback;
 
 	CArtifactsOfHeroMarket(const Point & position, const int selectionWidth);
 	void scrollBackpack(bool left) override;

+ 1 - 1
client/widgets/CWindowWithArtifacts.cpp

@@ -322,7 +322,7 @@ void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const
 			if(withRedraw)
 			{
 				artSetPtr->updateWornSlots();
-				artSetPtr->updateBackpackSlots();
+				artSetPtr->updateBackpackSlots(std::nullopt);
 
 				// Update arts bonuses on window.
 				// TODO rework this part when CHeroWindow and CExchangeWindow are reworked

+ 18 - 19
client/widgets/markets/CAltarArtifacts.cpp

@@ -55,12 +55,12 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 	// Altar
 	offerTradePanel = std::make_shared<ArtifactsAltarPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
 		{
-			CAltarArtifacts::onSlotClickPressed(altarSlot, hRight);
+			CAltarArtifacts::onSlotClickPressed(altarSlot, offerTradePanel);
 		});
 	offerTradePanel->updateSlotsCallback = std::bind(&CAltarArtifacts::updateAltarSlots, this);
 	offerTradePanel->moveTo(pos.topLeft() + Point(315, 52));
 
-	CMarketBase::updateSelected();
+	CMarketBase::updateShowcases();
 	CAltarArtifacts::deselect();
 };
 
@@ -79,11 +79,9 @@ void CAltarArtifacts::deselect()
 	CExperienceAltar::deselect();
 	tradeSlotsMap.clear();
 	// The event for removing artifacts from the altar will not be triggered. Therefore, we clean the altar immediately.
-	for(auto & slot : offerTradePanel->slots)
-	{
-		slot->setID(-1);
-		slot->subtitle->clear();
-	}
+	for(const auto & slot : offerTradePanel->slots)
+		slot->clear();
+	offerTradePanel->showcaseSlot->clear();
 }
 
 void CAltarArtifacts::update()
@@ -92,16 +90,17 @@ void CAltarArtifacts::update()
 	CExperienceAltar::update();
 	if(const auto art = hero->getArt(ArtifactPosition::TRANSITION_POS))
 	{
-		hRight = offerTradePanel->selectedSlot;
-		hRight->setID(art->getTypeId().num);
+		offerTradePanel->showcaseSlot->setID(art->getTypeId().num);
+		offerTradePanel->highlightedSlot = offerTradePanel->showcaseSlot;
 		offerQty = calcExpCost(art->getTypeId());
 	}
 	else
 	{
-		hRight.reset();
+		offerTradePanel->showcaseSlot->clear();
+		offerTradePanel->highlightedSlot.reset();
 		offerQty = 0;
 	}
-	updateSelected();
+	updateShowcases();
 }
 
 void CAltarArtifacts::makeDeal()
@@ -136,7 +135,7 @@ void CAltarArtifacts::updateAltarSlots()
 	assert(tradeSlotsMap.size() <= GameConstants::ALTAR_ARTIFACTS_SLOTS);
 	
 	auto tradeSlotsMapNewArts = tradeSlotsMap;
-	for(auto & altarSlot : offerTradePanel->slots)
+	for(const auto & altarSlot : offerTradePanel->slots)
 		if(altarSlot->id != -1)
 		{
 			if(tradeSlotsMap.find(altarSlot) == tradeSlotsMap.end())
@@ -161,14 +160,14 @@ void CAltarArtifacts::updateAltarSlots()
 	auto newArtsFromBulkMove = altarArtifacts->artifactsInBackpack;
 	for(const auto & [altarSlot, art] : tradeSlotsMap)
 	{
-		newArtsFromBulkMove.erase(std::remove_if(newArtsFromBulkMove.begin(), newArtsFromBulkMove.end(), [art = art](auto & slotInfo)
+		newArtsFromBulkMove.erase(std::remove_if(newArtsFromBulkMove.begin(), newArtsFromBulkMove.end(), [artForRemove = art](auto & slotInfo)
 			{
-				return slotInfo.artifact == art;
+				return slotInfo.artifact == artForRemove;
 			}));
 	}
 	for(const auto & slotInfo : newArtsFromBulkMove)
 	{
-		for(auto & altarSlot : offerTradePanel->slots)
+		for(const auto & altarSlot : offerTradePanel->slots)
 			if(altarSlot->id == -1)
 			{
 				altarSlot->setID(slotInfo.artifact->getTypeId().num);
@@ -192,15 +191,15 @@ void CAltarArtifacts::putBackArtifacts()
 
 CMarketBase::SelectionParams CAltarArtifacts::getSelectionParams() const
 {
-	if(hRight)
+	if(offerTradePanel->highlightedSlot)
 		return std::make_tuple(
 			std::nullopt,
-			SelectionParamOneSide {std::to_string(offerQty), CGI->artifacts()->getByIndex(hRight->id)->getIconIndex()}
+			SelectionParamOneSide {std::to_string(offerQty), CGI->artifacts()->getByIndex(offerTradePanel->highlightedSlot->id)->getIconIndex()}
 	);
 	return std::make_tuple(std::nullopt, std::nullopt);
 }
 
-void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
+void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<TradePanelBase> & curPanel)
 {
 	assert(altarSlot);
 
@@ -234,7 +233,7 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 	}
 }
 
-TExpType CAltarArtifacts::calcExpCost(ArtifactID id)
+TExpType CAltarArtifacts::calcExpCost(ArtifactID id) const
 {
 	int bidQty = 0;
 	int expOfArt = 0;

+ 2 - 2
client/widgets/markets/CAltarArtifacts.h

@@ -34,6 +34,6 @@ private:
 
 	void updateAltarSlots();
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
-	TExpType calcExpCost(ArtifactID id);
+	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<TradePanelBase> & curPanel) override;
+	TExpType calcExpCost(ArtifactID id) const;
 };

+ 30 - 30
client/widgets/markets/CAltarCreatures.cpp

@@ -47,19 +47,19 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance *
 	// Hero creatures panel
 	assert(bidTradePanel);
 	bidTradePanel->moveTo(pos.topLeft() + Point(45, 110));
-	bidTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(149, 422));
-	bidTradePanel->selectedSlot->subtitle->moveBy(Point(0, 3));
+	bidTradePanel->showcaseSlot->moveTo(pos.topLeft() + Point(149, 422));
+	bidTradePanel->showcaseSlot->subtitle->moveBy(Point(0, 3));
 	for(const auto & slot : bidTradePanel->slots)
-		slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, hLeft);};
+		slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, bidTradePanel);};
 
 	// Altar creatures panel
 	offerTradePanel = std::make_shared<CreaturesPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
 		{
-			CAltarCreatures::onSlotClickPressed(altarSlot, hRight);
+			CAltarCreatures::onSlotClickPressed(altarSlot, offerTradePanel);
 		}, bidTradePanel->slots);
 	offerTradePanel->moveTo(pos.topLeft() + Point(334, 110));
-	offerTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(395, 422));
-	offerTradePanel->selectedSlot->subtitle->moveBy(Point(0, 3));
+	offerTradePanel->showcaseSlot->moveTo(pos.topLeft() + Point(395, 422));
+	offerTradePanel->showcaseSlot->subtitle->moveBy(Point(0, 3));
 	offerTradePanel->updateSlotsCallback = [this]()
 	{
 		for(const auto & altarSlot : offerTradePanel->slots)
@@ -84,7 +84,7 @@ void CAltarCreatures::readExpValues()
 void CAltarCreatures::highlightingChanged()
 {
 	int sliderAmount = 0;
-	if(hLeft)
+	if(bidTradePanel->highlightedSlot)
 	{
 		std::optional<SlotID> lastSlot;
 		for(auto slot = SlotID(0); slot.num < GameConstants::ARMY_SIZE; slot++)
@@ -102,16 +102,16 @@ void CAltarCreatures::highlightingChanged()
 				}
 			}
 		}
-		sliderAmount = hero->getStackCount(SlotID(hLeft->serial));
-		if(lastSlot.has_value() && lastSlot.value() == SlotID(hLeft->serial))
+		sliderAmount = hero->getStackCount(SlotID(bidTradePanel->highlightedSlot->serial));
+		if(lastSlot.has_value() && lastSlot.value() == SlotID(bidTradePanel->highlightedSlot->serial))
 			sliderAmount--;
 	}
 	offerSlider->setAmount(sliderAmount);
 	offerSlider->block(!offerSlider->getAmount());
-	if(hLeft)
-		offerSlider->scrollTo(unitsOnAltar[hLeft->serial]);
+	if(bidTradePanel->highlightedSlot)
+		offerSlider->scrollTo(unitsOnAltar[bidTradePanel->highlightedSlot->serial]);
 	maxAmount->block(offerSlider->getAmount() == 0);
-	updateSelected();
+	updateShowcases();
 }
 
 void CAltarCreatures::update()
@@ -170,10 +170,10 @@ CMarketBase::SelectionParams CAltarCreatures::getSelectionParams() const
 {
 	std::optional<SelectionParamOneSide> bidSelected = std::nullopt;
 	std::optional<SelectionParamOneSide> offerSelected = std::nullopt;
-	if(hLeft)
-		bidSelected = SelectionParamOneSide {std::to_string(offerSlider->getValue()), CGI->creatures()->getByIndex(hLeft->id)->getIconIndex()};
-	if(hRight && offerSlider->getValue() > 0)
-		offerSelected = SelectionParamOneSide {hRight->subtitle->getText(), CGI->creatures()->getByIndex(hRight->id)->getIconIndex()};
+	if(bidTradePanel->highlightedSlot)
+		bidSelected = SelectionParamOneSide {std::to_string(offerSlider->getValue()), CGI->creatures()->getByIndex(bidTradePanel->highlightedSlot->id)->getIconIndex()};
+	if(offerTradePanel->highlightedSlot && offerSlider->getValue() > 0)
+		offerSelected = SelectionParamOneSide { offerTradePanel->highlightedSlot->subtitle->getText(), CGI->creatures()->getByIndex(offerTradePanel->highlightedSlot->id)->getIconIndex()};
 	return std::make_tuple(bidSelected, offerSelected);
 }
 
@@ -196,10 +196,10 @@ void CAltarCreatures::sacrificeAll()
 		unitsOnAltar[lastSlot.value().num]--;
 	}
 
-	if(hRight)
-		offerSlider->scrollTo(unitsOnAltar[hRight->serial]);
+	if(offerTradePanel->highlightedSlot)
+		offerSlider->scrollTo(unitsOnAltar[offerTradePanel->highlightedSlot->serial]);
 	offerTradePanel->update();
-	updateSelected();
+	updateShowcases();
 
 	deal->block(calcExpAltarForHero() == 0);
 }
@@ -214,26 +214,26 @@ void CAltarCreatures::updateAltarSlot(const std::shared_ptr<CTradeableItem> & sl
 
 void CAltarCreatures::onOfferSliderMoved(int newVal)
 {
-	if(hLeft)
-		unitsOnAltar[hLeft->serial] = newVal;
-	if(hRight)
-		updateAltarSlot(hRight);
+	if(bidTradePanel->highlightedSlot)
+		unitsOnAltar[bidTradePanel->highlightedSlot->serial] = newVal;
+	if(offerTradePanel->highlightedSlot)
+		updateAltarSlot(offerTradePanel->highlightedSlot);
 	deal->block(calcExpAltarForHero() == 0);
 	highlightingChanged();
 	redraw();
 }
 
-void CAltarCreatures::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
+void CAltarCreatures::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<TradePanelBase> & curPanel)
 {
-	if(hCurSlot == newSlot)
+	assert(newSlot);
+	assert(curPanel);
+	if(newSlot == curPanel->highlightedSlot)
 		return;
 
-	auto * oppositeSlot = &hLeft;
 	auto oppositePanel = bidTradePanel;
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	if(hCurSlot == hLeft)
+	curPanel->onSlotClickPressed(newSlot);
+	if(curPanel->highlightedSlot == bidTradePanel->highlightedSlot)
 	{
-		oppositeSlot = &hRight;
 		oppositePanel = offerTradePanel;
 	}
 	std::shared_ptr<CTradeableItem> oppositeNewSlot;
@@ -244,7 +244,7 @@ void CAltarCreatures::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 			break;
 		}
 	assert(oppositeNewSlot);
-	CMarketBase::onSlotClickPressed(oppositeNewSlot, *oppositeSlot);
+	oppositePanel->onSlotClickPressed(oppositeNewSlot);
 	highlightingChanged();
 	redraw();
 }

+ 2 - 2
client/widgets/markets/CAltarCreatures.h

@@ -28,7 +28,7 @@ private:
 	CMarketBase::SelectionParams getSelectionParams() const override;
 	void updateAltarSlot(const std::shared_ptr<CTradeableItem> & slot);
 	void readExpValues();
-	void highlightingChanged();
+	void highlightingChanged() override;
 	void onOfferSliderMoved(int newVal) override;
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
+	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<TradePanelBase> & curPanel) override;
 };

+ 13 - 27
client/widgets/markets/CArtifactsBuying.cpp

@@ -26,7 +26,7 @@
 
 CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance * hero)
 	: CMarketBase(market, hero, [this](){return CArtifactsBuying::getSelectionParams();})
-	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CArtifactsBuying::onSlotClickPressed(heroSlot, hLeft);})
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CArtifactsBuying::onSlotClickPressed(heroSlot, bidTradePanel);})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -43,15 +43,15 @@ CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance
 	// Player's resources
 	assert(bidTradePanel);
 	bidTradePanel->moveTo(pos.topLeft() + Point(39, 184));
-	bidTradePanel->selectedSlot->image->moveTo(pos.topLeft() + Point(141, 454));
+	bidTradePanel->showcaseSlot->image->moveTo(pos.topLeft() + Point(141, 454));
 
 	// Artifacts panel
 	offerTradePanel = std::make_shared<ArtifactsPanel>([this](const std::shared_ptr<CTradeableItem> & newSlot)
 		{
-			CArtifactsBuying::onSlotClickPressed(newSlot, hRight);
+			CArtifactsBuying::onSlotClickPressed(newSlot, offerTradePanel);
 		}, [this]()
 		{
-			CMarketBase::updateSubtitles(EMarketMode::RESOURCE_ARTIFACT);
+			CMarketBase::updateSubtitlesForBid(EMarketMode::RESOURCE_ARTIFACT, bidTradePanel->getSelectedItemId());
 		}, market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT));
 	offerTradePanel->deleteSlotsCheck = [this](const std::shared_ptr<CTradeableItem> & slot)
 	{
@@ -65,41 +65,27 @@ CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance
 
 void CArtifactsBuying::makeDeal()
 {
-	LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_ARTIFACT, GameResID(hLeft->id), ArtifactID(hRight->id), offerQty, hero);
+	LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_ARTIFACT, GameResID(bidTradePanel->highlightedSlot->id),
+		ArtifactID(offerTradePanel->highlightedSlot->id), offerQty, hero);
 	deselect();
 }
 
 CMarketBase::SelectionParams CArtifactsBuying::getSelectionParams() const
 {
-	if(hLeft && hRight)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 		return std::make_tuple(
-			SelectionParamOneSide {std::to_string(deal->isBlocked() ? 0 : bidQty), hLeft->id},
-			SelectionParamOneSide {std::to_string(deal->isBlocked() ? 0 : offerQty), CGI->artifacts()->getByIndex(hRight->id)->getIconIndex()});
+			SelectionParamOneSide {std::to_string(deal->isBlocked() ? 0 : bidQty), bidTradePanel->highlightedSlot->id},
+			SelectionParamOneSide {std::to_string(deal->isBlocked() ? 0 : offerQty), CGI->artifacts()->getByIndex(offerTradePanel->highlightedSlot->id)->getIconIndex()});
 	else
 		return std::make_tuple(std::nullopt, std::nullopt);
 }
 
 void CArtifactsBuying::highlightingChanged()
 {
-	if(hLeft)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 	{
-		if(hRight)
-		{
-			market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::RESOURCE_ARTIFACT);
-			deal->block(LOCPLINT->cb->getResourceAmount(GameResID(hLeft->id)) >= bidQty ? false : true);
-		}
-		offerTradePanel->update();
+		market->getOffer(bidTradePanel->highlightedSlot->id, offerTradePanel->highlightedSlot->id, bidQty, offerQty, EMarketMode::RESOURCE_ARTIFACT);
+		deal->block(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->highlightedSlot->id)) >= bidQty ? false : true);
 	}
-	updateSelected();
-}
-
-void CArtifactsBuying::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
-{
-	assert(newSlot);
-	if(newSlot == hCurSlot)
-		return;
-
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	highlightingChanged();
-	redraw();
+	CMarketBase::highlightingChanged();
 }

+ 1 - 2
client/widgets/markets/CArtifactsBuying.h

@@ -19,6 +19,5 @@ public:
 
 private:
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void highlightingChanged();
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
+	void highlightingChanged() override;
 };

+ 22 - 37
client/widgets/markets/CArtifactsSelling.cpp

@@ -29,8 +29,8 @@
 CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero)
 	: CMarketBase(market, hero, [this](){return CArtifactsSelling::getSelectionParams();})
 	, CResourcesBuying(
-		[this](const std::shared_ptr<CTradeableItem> & resSlot){CArtifactsSelling::onSlotClickPressed(resSlot, hRight);},
-		[this](){CMarketBase::updateSubtitles(EMarketMode::ARTIFACT_RESOURCE);})
+		[this](const std::shared_ptr<CTradeableItem> & resSlot){CArtifactsSelling::onSlotClickPressed(resSlot, offerTradePanel);},
+		[this](){CMarketBase::updateSubtitlesForBid(EMarketMode::ARTIFACT_RESOURCE, this->hero->getArt(selectedHeroSlot)->getTypeId().num);})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -44,26 +44,21 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 	// Market resources panel
 	assert(offerTradePanel);
 	offerTradePanel->moveTo(pos.topLeft() + Point(326, 184));
-	offerTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(409, 473));
-	offerTradePanel->selectedSlot->subtitle->moveBy(Point(0, 1));
+	offerTradePanel->showcaseSlot->moveTo(pos.topLeft() + Point(409, 473));
+	offerTradePanel->showcaseSlot->subtitle->moveBy(Point(0, 1));
 	
 	// Hero's artifacts
 	heroArts = std::make_shared<CArtifactsOfHeroMarket>(Point(-361, 46), offerTradePanel->selectionWidth);
 	heroArts->setHero(hero);
-	heroArts->selectArtCallback = [this](CArtPlace * artPlace)
+	heroArts->selectArtCallback = [this](const CArtPlace * artPlace)
 	{
 		assert(artPlace);
-		const auto artForTrade = artPlace->getArt();
-		assert(artForTrade);
-		bidSelectedSlot->setID(artForTrade->getTypeId().num);
-		hLeft = bidSelectedSlot;
 		selectedHeroSlot = artPlace->slot;
 		CArtifactsSelling::highlightingChanged();
-		offerTradePanel->update();
-		redraw();
+		CIntObject::redraw();
 	};
 
-	CArtifactsSelling::updateSelected();
+	CArtifactsSelling::updateShowcases();
 	CArtifactsSelling::deselect();
 }
 
@@ -72,31 +67,31 @@ void CArtifactsSelling::deselect()
 	CMarketBase::deselect();
 	selectedHeroSlot = ArtifactPosition::PRE_FIRST;
 	heroArts->unmarkSlots();
+	bidSelectedSlot->clear();
 }
 
 void CArtifactsSelling::makeDeal()
 {
 	const auto art = hero->getArt(selectedHeroSlot);
 	assert(art);
-	LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_RESOURCE, art->getId(), GameResID(hRight->id), offerQty, hero);
+	LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_RESOURCE, art->getId(), GameResID(offerTradePanel->getSelectedItemId()), offerQty, hero);
 }
 
-void CArtifactsSelling::updateSelected()
+void CArtifactsSelling::updateShowcases()
 {
-	CMarketBase::updateSelected();
-
-	if(hLeft && hRight)
+	const auto art = hero->getArt(selectedHeroSlot);
+	if(art && offerTradePanel->highlightedSlot)
 	{
 		bidSelectedSlot->image->enable();
-		bidSelectedSlot->image->setFrame(CGI->artifacts()->getByIndex(hLeft->id)->getIconIndex());
+		bidSelectedSlot->setID(art->getTypeId().num);
+		bidSelectedSlot->image->setFrame(CGI->artifacts()->getByIndex(art->getTypeId())->getIconIndex());
 		bidSelectedSlot->subtitle->setText(std::to_string(bidQty));
 	}
 	else
 	{
-		bidSelectedSlot->image->disable();
-		bidSelectedSlot->image->setFrame(0);
-		bidSelectedSlot->subtitle->clear();
+		bidSelectedSlot->clear();
 	}
+	CMarketBase::updateShowcases();
 }
 
 void CArtifactsSelling::update()
@@ -121,10 +116,10 @@ std::shared_ptr<CArtifactsOfHeroMarket> CArtifactsSelling::getAOHset() const
 
 CMarketBase::SelectionParams CArtifactsSelling::getSelectionParams() const
 {
-	if(hLeft && hRight)
+	if(hero->getArt(selectedHeroSlot) && offerTradePanel->highlightedSlot)
 		return std::make_tuple(
 			std::nullopt,
-			SelectionParamOneSide {std::to_string(offerQty), hRight->id}
+			SelectionParamOneSide {std::to_string(offerQty), offerTradePanel->getSelectedItemId()}
 		);
 	else
 		return std::make_tuple(std::nullopt, std::nullopt);
@@ -132,21 +127,11 @@ CMarketBase::SelectionParams CArtifactsSelling::getSelectionParams() const
 
 void CArtifactsSelling::highlightingChanged()
 {
-	if(hLeft && hRight)
+	const auto art = hero->getArt(selectedHeroSlot);
+	if(art && offerTradePanel->highlightedSlot)
 	{
-		market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
+		market->getOffer(art->getTypeId(), offerTradePanel->getSelectedItemId(), bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
 		deal->block(false);
 	}
-	updateSelected();
-}
-
-void CArtifactsSelling::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
-{
-	assert(newSlot);
-	if(newSlot == hCurSlot)
-		return;
-
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	highlightingChanged();
-	redraw();
+	CMarketBase::highlightingChanged();
 }

+ 2 - 3
client/widgets/markets/CArtifactsSelling.h

@@ -18,7 +18,7 @@ public:
 	CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero);
 	void deselect() override;
 	void makeDeal() override;
-	void updateSelected() override;
+	void updateShowcases() override;
 	void update() override;
 	std::shared_ptr<CArtifactsOfHeroMarket> getAOHset() const;
 
@@ -29,6 +29,5 @@ private:
 	ArtifactPosition selectedHeroSlot;
 
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void highlightingChanged();
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
+	void highlightingChanged() override;
 };

+ 16 - 41
client/widgets/markets/CFreelancerGuild.cpp

@@ -28,8 +28,8 @@
 CFreelancerGuild::CFreelancerGuild(const IMarket * market, const CGHeroInstance * hero)
 	: CMarketBase(market, hero, [this](){return CFreelancerGuild::getSelectionParams();})
 	, CResourcesBuying(
-		[this](const std::shared_ptr<CTradeableItem> & heroSlot){CFreelancerGuild::onSlotClickPressed(heroSlot, hLeft);},
-		[this](){CMarketBase::updateSubtitles(EMarketMode::CREATURE_RESOURCE);})
+		[this](const std::shared_ptr<CTradeableItem> & heroSlot){CFreelancerGuild::onSlotClickPressed(heroSlot, offerTradePanel);},
+		[this](){CMarketBase::updateSubtitlesForBid(EMarketMode::CREATURE_RESOURCE, bidTradePanel->getSelectedItemId());})
 	, CMarketSlider([this](int newVal){CMarketSlider::onOfferSliderMoved(newVal);})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -45,23 +45,13 @@ CFreelancerGuild::CFreelancerGuild(const IMarket * market, const CGHeroInstance
 	// Hero creatures panel
 	assert(bidTradePanel);
 	bidTradePanel->moveTo(pos.topLeft() + Point(45, 123));
-	bidTradePanel->selectedSlot->subtitle->moveBy(Point(0, -1));
+	bidTradePanel->showcaseSlot->subtitle->moveBy(Point(0, -1));
 	bidTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1);
 	std::for_each(bidTradePanel->slots.cbegin(), bidTradePanel->slots.cend(), [this](auto & slot)
 		{
 			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot)
 			{
-				CFreelancerGuild::onSlotClickPressed(heroSlot, hLeft);
-			};
-		});
-
-	// Guild resources panel
-	assert(offerTradePanel);
-	std::for_each(offerTradePanel->slots.cbegin(), offerTradePanel->slots.cend(), [this](auto & slot)
-		{
-			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot)
-			{
-				CFreelancerGuild::onSlotClickPressed(heroSlot, hRight);
+				CFreelancerGuild::onSlotClickPressed(heroSlot, bidTradePanel);
 			};
 		});
 
@@ -78,46 +68,31 @@ void CFreelancerGuild::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market, EMarketMode::CREATURE_RESOURCE, SlotID(hLeft->serial), GameResID(hRight->id), bidQty * toTrade, hero);
+		LOCPLINT->cb->trade(market, EMarketMode::CREATURE_RESOURCE, SlotID(bidTradePanel->highlightedSlot->serial), GameResID(offerTradePanel->highlightedSlot->id), bidQty * toTrade, hero);
 		deselect();
 	}
 }
 
 CMarketBase::SelectionParams CFreelancerGuild::getSelectionParams() const
 {
-	if(hLeft && hRight)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 		return std::make_tuple(
-			SelectionParamOneSide {std::to_string(bidQty * offerSlider->getValue()), CGI->creatures()->getByIndex(hLeft->id)->getIconIndex()},
-			SelectionParamOneSide {std::to_string(offerQty * offerSlider->getValue()), hRight->id});
+			SelectionParamOneSide {std::to_string(bidQty * offerSlider->getValue()), CGI->creatures()->getByIndex(bidTradePanel->highlightedSlot->id)->getIconIndex()},
+			SelectionParamOneSide {std::to_string(offerQty * offerSlider->getValue()), offerTradePanel->highlightedSlot->id});
 	else
 		return std::make_tuple(std::nullopt, std::nullopt);
 }
 
 void CFreelancerGuild::highlightingChanged()
 {
-	if(hLeft)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 	{
-		if(hRight)
-		{
-			market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::CREATURE_RESOURCE);
-			offerSlider->setAmount((hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1 && hero->needsLastStack() ? 1 : 0)) / bidQty);
-			offerSlider->scrollTo(0);
-			offerSlider->block(false);
-			maxAmount->block(false);
-			deal->block(false);
-		}
-		offerTradePanel->update();
+		market->getOffer(bidTradePanel->highlightedSlot->id, offerTradePanel->highlightedSlot->id, bidQty, offerQty, EMarketMode::CREATURE_RESOURCE);
+		offerSlider->setAmount((hero->getStackCount(SlotID(bidTradePanel->highlightedSlot->serial)) - (hero->stacksCount() == 1 && hero->needsLastStack() ? 1 : 0)) / bidQty);
+		offerSlider->scrollTo(0);
+		offerSlider->block(false);
+		maxAmount->block(false);
+		deal->block(false);
 	}
-	updateSelected();
-}
-
-void CFreelancerGuild::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
-{
-	assert(newSlot);
-	if(newSlot == hCurSlot)
-		return;
-
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	highlightingChanged();
-	redraw();
+	CMarketBase::highlightingChanged();
 }

+ 1 - 2
client/widgets/markets/CFreelancerGuild.h

@@ -20,6 +20,5 @@ public:
 
 private:
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void highlightingChanged();
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
+	void highlightingChanged() override;
 };

+ 49 - 33
client/widgets/markets/CMarketBase.cpp

@@ -36,26 +36,32 @@ CMarketBase::CMarketBase(const IMarket * market, const CGHeroInstance * hero, co
 
 void CMarketBase::deselect()
 {
-	if(hLeft)
-		hLeft->selectSlot(false);
-	if(hRight)
-		hRight->selectSlot(false);
-	hLeft = hRight = nullptr;
+	if(bidTradePanel && bidTradePanel->highlightedSlot)
+	{
+		bidTradePanel->highlightedSlot->selectSlot(false);
+		bidTradePanel->highlightedSlot.reset();
+	}
+	if(offerTradePanel && offerTradePanel->highlightedSlot)
+	{
+		offerTradePanel->highlightedSlot->selectSlot(false);
+		offerTradePanel->highlightedSlot.reset();
+	}
 	deal->block(true);
 	bidQty = 0;
 	offerQty = 0;
-	updateSelected();
+	updateShowcases();
 }
 
-void CMarketBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
+void CMarketBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<TradePanelBase> & curPanel)
 {
-	if(newSlot == hCurSlot)
+	assert(newSlot);
+	assert(curPanel);
+	if(newSlot == curPanel->highlightedSlot)
 		return;
 
-	if(hCurSlot)
-		hCurSlot->selectSlot(false);
-	hCurSlot = newSlot;
-	newSlot->selectSlot(true);
+	curPanel->onSlotClickPressed(newSlot);
+	highlightingChanged();
+	redraw();
 }
 
 void CMarketBase::update()
@@ -66,35 +72,39 @@ void CMarketBase::update()
 		offerTradePanel->update();
 }
 
-void CMarketBase::updateSubtitles(EMarketMode marketMode)
+void CMarketBase::updateSubtitlesForBid(EMarketMode marketMode, int bidId)
 {
-	if(hLeft)
+	if(bidId == -1)
+	{
+		if(offerTradePanel)
+			offerTradePanel->clearSubtitles();
+	}
+	else
+	{
 		for(const auto & slot : offerTradePanel->slots)
 		{
-			int bidQty = 0;
-			int offerQty = 0;
-			market->getOffer(hLeft->id, slot->id, bidQty, offerQty, marketMode);
-			offerTradePanel->updateOffer(*slot, bidQty, offerQty);
+			int slotBidQty = 0;
+			int slotOfferQty = 0;
+			market->getOffer(bidId, slot->id, slotBidQty, slotOfferQty, marketMode);
+			offerTradePanel->updateOffer(*slot, slotBidQty, slotOfferQty);
 		}
-	else
-		offerTradePanel->clearSubtitles();
+	}
 };
 
-void CMarketBase::updateSelected()
+void CMarketBase::updateShowcases()
 {
-	const auto updateSelectedBody = [](std::shared_ptr<TradePanelBase> & tradePanel, const std::optional<const SelectionParamOneSide> & params)
+	const auto updateSelectedBody = [](const std::shared_ptr<TradePanelBase> & tradePanel, const std::optional<const SelectionParamOneSide> & params)
 	{
-		std::optional<size_t> lImageIndex = std::nullopt;
 		if(params.has_value())
 		{
-			tradePanel->setSelectedSubtitleText(params.value().text);
-			lImageIndex = params.value().imageIndex;
+			tradePanel->setShowcaseSubtitle(params.value().text);
+			tradePanel->showcaseSlot->image->enable();
+			tradePanel->showcaseSlot->image->setFrame(params.value().imageIndex);
 		}
 		else
 		{
-			tradePanel->clearSelectedSubtitleText();
+			tradePanel->showcaseSlot->clear();
 		}
-		tradePanel->setSelectedFrameIndex(lImageIndex);
 	};
 
 	assert(selectionParamsCallback);
@@ -105,6 +115,12 @@ void CMarketBase::updateSelected()
 		updateSelectedBody(offerTradePanel, std::get<1>(params));
 }
 
+void CMarketBase::highlightingChanged()
+{
+	offerTradePanel->update();
+	updateShowcases();
+}
+
 CExperienceAltar::CExperienceAltar()
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -142,14 +158,14 @@ CCreaturesSelling::CCreaturesSelling()
 	bidTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitles, this);
 }
 
-bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot)
+bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot) const
 {
 	return hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
 }
 
-void CCreaturesSelling::updateSubtitles()
+void CCreaturesSelling::updateSubtitles() const
 {
-	for(auto & heroSlot : bidTradePanel->slots)
+	for(const auto & heroSlot : bidTradePanel->slots)
 		heroSlot->subtitle->setText(std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial))));
 }
 
@@ -171,7 +187,7 @@ CResourcesSelling::CResourcesSelling(const CTradeableItem::ClickPressedFunctor &
 	labels.emplace_back(std::make_shared<CLabel>(156, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]));
 }
 
-void CResourcesSelling::updateSubtitles()
+void CResourcesSelling::updateSubtitles() const
 {
 	for(const auto & slot : bidTradePanel->slots)
 		slot->subtitle->setText(std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial))));
@@ -198,10 +214,10 @@ void CMarketSlider::deselect()
 
 void CMarketSlider::onOfferSliderMoved(int newVal)
 {
-	if(hLeft && hRight)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 	{
 		offerSlider->scrollTo(newVal);
-		updateSelected();
+		updateShowcases();
 		redraw();
 	}
 }

+ 10 - 12
client/widgets/markets/CMarketBase.h

@@ -39,9 +39,6 @@ public:
 	std::shared_ptr<TradePanelBase> bidTradePanel;
 	std::shared_ptr<TradePanelBase> offerTradePanel;
 
-	// Highlighted trade slots (nullptr if no highlight)
-	std::shared_ptr<CTradeableItem> hLeft;
-	std::shared_ptr<CTradeableItem> hRight;
 	std::shared_ptr<CButton> deal;
 	std::vector<std::shared_ptr<CLabel>> labels;
 	std::vector<std::shared_ptr<CTextBox>> texts;
@@ -57,10 +54,11 @@ public:
 	virtual void update();
 
 protected:
-	virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
-	virtual void updateSubtitles(EMarketMode marketMode);
-	virtual void updateSelected();
-	virtual CMarketBase::SelectionParams getSelectionParams() const = 0;
+	virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<TradePanelBase> & curPanel);
+	virtual void updateSubtitlesForBid(EMarketMode marketMode, int bidId);
+	virtual void updateShowcases();
+	virtual SelectionParams getSelectionParams() const = 0;
+	virtual void highlightingChanged();
 };
 
 // Market subclasses
@@ -82,8 +80,8 @@ class CCreaturesSelling : virtual public CMarketBase
 {
 public:
 	CCreaturesSelling();
-	bool slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot);
-	void updateSubtitles();
+	bool slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot) const;
+	void updateSubtitles() const;
 };
 
 class CResourcesBuying : virtual public CMarketBase
@@ -96,8 +94,8 @@ public:
 class CResourcesSelling : virtual public CMarketBase
 {
 public:
-	CResourcesSelling(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
-	void updateSubtitles();
+	explicit CResourcesSelling(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
+	void updateSubtitles() const;
 };
 
 class CMarketSlider : virtual public CMarketBase
@@ -107,7 +105,7 @@ public:
 	std::shared_ptr<CButton> maxAmount;
 	const Point dealButtonPosWithSlider = Point(306, 520);
 
-	CMarketSlider(const CSlider::SliderMovingFunctor & movingCallback);
+	explicit CMarketSlider(const CSlider::SliderMovingFunctor & movingCallback);
 	void deselect() override;
 	virtual void onOfferSliderMoved(int newVal);
 };

+ 19 - 40
client/widgets/markets/CMarketResources.cpp

@@ -25,10 +25,10 @@
 
 CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance * hero)
 	: CMarketBase(market, hero, [this](){return CMarketResources::getSelectionParams();})
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CMarketResources::onSlotClickPressed(heroSlot, bidTradePanel);})
 	, CResourcesBuying(
-		[this](const std::shared_ptr<CTradeableItem> & resSlot){CMarketResources::onSlotClickPressed(resSlot, hRight);},
+		[this](const std::shared_ptr<CTradeableItem> & resSlot){CMarketResources::onSlotClickPressed(resSlot, offerTradePanel);},
 		[this](){CMarketResources::updateSubtitles();})
-	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CMarketResources::onSlotClickPressed(heroSlot, hLeft);})
 	, CMarketSlider([this](int newVal){CMarketSlider::onOfferSliderMoved(newVal);})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -43,13 +43,6 @@ CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance
 
 	// Market resources panel
 	assert(offerTradePanel);
-	std::for_each(offerTradePanel->slots.cbegin(), offerTradePanel->slots.cend(), [this](auto & slot)
-		{
-			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & resSlot)
-			{
-				CMarketResources::onSlotClickPressed(resSlot, hRight);
-			};
-		});
 
 	CMarketBase::update();
 	CMarketResources::deselect();
@@ -65,54 +58,40 @@ void CMarketResources::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_RESOURCE, GameResID(hLeft->id), GameResID(hRight->id), bidQty * toTrade, hero);
+		LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_RESOURCE, GameResID(bidTradePanel->getSelectedItemId()),
+			GameResID(offerTradePanel->highlightedSlot->id), bidQty * toTrade, hero);
 		deselect();
 	}
 }
 
 CMarketBase::SelectionParams CMarketResources::getSelectionParams() const
 {
-	if(hLeft && hRight && hLeft->id != hRight->id)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot && bidTradePanel->getSelectedItemId() != offerTradePanel->getSelectedItemId())
 		return std::make_tuple(
-			SelectionParamOneSide {std::to_string(bidQty * offerSlider->getValue()), hLeft->id},
-			SelectionParamOneSide {std::to_string(offerQty * offerSlider->getValue()), hRight->id});
+			SelectionParamOneSide {std::to_string(bidQty * offerSlider->getValue()), bidTradePanel->getSelectedItemId()},
+			SelectionParamOneSide {std::to_string(offerQty * offerSlider->getValue()), offerTradePanel->getSelectedItemId()});
 	else
 		return std::make_tuple(std::nullopt, std::nullopt);
 }
 
 void CMarketResources::highlightingChanged()
 {
-	if(hLeft)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 	{
-		if(hRight)
-		{
-			market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::RESOURCE_RESOURCE);
-			offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(hLeft->id)) / bidQty);
-			offerSlider->scrollTo(0);
-			const bool isControlsBlocked = hLeft->id != hRight->id ? false : true;
-			offerSlider->block(isControlsBlocked);
-			maxAmount->block(isControlsBlocked);
-			deal->block(isControlsBlocked);
-		}
-		offerTradePanel->update();
+		market->getOffer(bidTradePanel->getSelectedItemId(), offerTradePanel->highlightedSlot->id, bidQty, offerQty, EMarketMode::RESOURCE_RESOURCE);
+		offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->getSelectedItemId())) / bidQty);
+		offerSlider->scrollTo(0);
+		const bool isControlsBlocked = bidTradePanel->getSelectedItemId() != offerTradePanel->getSelectedItemId() ? false : true;
+		offerSlider->block(isControlsBlocked);
+		maxAmount->block(isControlsBlocked);
+		deal->block(isControlsBlocked);
 	}
-	updateSelected();
-}
-
-void CMarketResources::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
-{
-	assert(newSlot);
-	if(newSlot == hCurSlot)
-		return;
-
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	highlightingChanged();
-	redraw();
+	CMarketBase::highlightingChanged();
 }
 
 void CMarketResources::updateSubtitles()
 {
-	CMarketBase::updateSubtitles(EMarketMode::RESOURCE_RESOURCE);
-	if(hLeft)
-		offerTradePanel->slots[hLeft->serial]->subtitle->setText(CGI->generaltexth->allTexts[164]); // n/a
+	CMarketBase::updateSubtitlesForBid(EMarketMode::RESOURCE_RESOURCE, bidTradePanel->getSelectedItemId());
+	if(bidTradePanel->highlightedSlot)
+		offerTradePanel->slots[bidTradePanel->highlightedSlot->serial]->subtitle->setText(CGI->generaltexth->allTexts[164]); // n/a
 }

+ 1 - 2
client/widgets/markets/CMarketResources.h

@@ -20,7 +20,6 @@ public:
 
 private:
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void highlightingChanged();
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
+	void highlightingChanged() override;
 	void updateSubtitles();
 };

+ 15 - 29
client/widgets/markets/CTransferResources.cpp

@@ -24,7 +24,7 @@
 
 CTransferResources::CTransferResources(const IMarket * market, const CGHeroInstance * hero)
 	: CMarketBase(market, hero, [this](){return CTransferResources::getSelectionParams();})
-	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CTransferResources::onSlotClickPressed(heroSlot, hLeft);})
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CTransferResources::onSlotClickPressed(heroSlot, bidTradePanel);})
 	, CMarketSlider([this](int newVal){CMarketSlider::onOfferSliderMoved(newVal);})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -32,7 +32,7 @@ CTransferResources::CTransferResources(const IMarket * market, const CGHeroInsta
 	labels.emplace_back(std::make_shared<CLabel>(titlePos.x, titlePos.y, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[158]));
 	labels.emplace_back(std::make_shared<CLabel>(445, 56, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[169]));
 	deal = std::make_shared<CButton>(dealButtonPosWithSlider, AnimationPath::builtin("TPMRKB.DEF"),
-		CGI->generaltexth->zelp[595], [this]() {CTransferResources::makeDeal();});
+		CGI->generaltexth->zelp[595], [this](){CTransferResources::makeDeal();});
 
 	// Player's resources
 	assert(bidTradePanel);
@@ -41,7 +41,7 @@ CTransferResources::CTransferResources(const IMarket * market, const CGHeroInsta
 	// Players panel
 	offerTradePanel = std::make_shared<PlayersPanel>([this](const std::shared_ptr<CTradeableItem> & heroSlot)
 		{
-			CTransferResources::onSlotClickPressed(heroSlot, hRight);
+			CTransferResources::onSlotClickPressed(heroSlot, offerTradePanel);
 		});
 	offerTradePanel->moveTo(pos.topLeft() + Point(333, 84));
 
@@ -59,45 +59,31 @@ void CTransferResources::makeDeal()
 {
 	if(auto toTrade = offerSlider->getValue(); toTrade != 0)
 	{
-		LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_PLAYER, GameResID(hLeft->id), PlayerColor(hRight->id), toTrade, hero);
+		LOCPLINT->cb->trade(market, EMarketMode::RESOURCE_PLAYER, GameResID(bidTradePanel->getSelectedItemId()),
+			PlayerColor(offerTradePanel->highlightedSlot->id), toTrade, hero);
 		deselect();
 	}
 }
 
 CMarketBase::SelectionParams CTransferResources::getSelectionParams() const
 {
-	if(hLeft && hRight)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 		return std::make_tuple(
-			SelectionParamOneSide {std::to_string(offerSlider->getValue()), hLeft->id},
-			SelectionParamOneSide {CGI->generaltexth->capColors[hRight->id], hRight->id});
+			SelectionParamOneSide {std::to_string(offerSlider->getValue()), bidTradePanel->getSelectedItemId()},
+			SelectionParamOneSide {CGI->generaltexth->capColors[offerTradePanel->highlightedSlot->id], offerTradePanel->getSelectedItemId()});
 	else
 		return std::make_tuple(std::nullopt, std::nullopt);
 }
 
 void CTransferResources::highlightingChanged()
 {
-	if(hLeft)
+	if(bidTradePanel->highlightedSlot && offerTradePanel->highlightedSlot)
 	{
-		if(hRight)
-		{
-			offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(hLeft->id)));
-			offerSlider->scrollTo(0);
-			offerSlider->block(false);
-			maxAmount->block(false);
-			deal->block(false);
-		}
-		offerTradePanel->update();
+		offerSlider->setAmount(LOCPLINT->cb->getResourceAmount(GameResID(bidTradePanel->getSelectedItemId())));
+		offerSlider->scrollTo(0);
+		offerSlider->block(false);
+		maxAmount->block(false);
+		deal->block(false);
 	}
-	updateSelected();
-}
-
-void CTransferResources::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
-{
-	assert(newSlot);
-	if(newSlot == hCurSlot)
-		return;
-
-	CMarketBase::onSlotClickPressed(newSlot, hCurSlot);
-	highlightingChanged();
-	redraw();
+	CMarketBase::highlightingChanged();
 }

+ 1 - 2
client/widgets/markets/CTransferResources.h

@@ -20,6 +20,5 @@ public:
 
 private:
 	CMarketBase::SelectionParams getSelectionParams() const override;
-	void highlightingChanged();
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
+	void highlightingChanged() override;
 };

+ 33 - 24
client/widgets/markets/TradePanels.cpp

@@ -75,7 +75,7 @@ void CTradeableItem::setType(EType newType)
 		case EType::ARTIFACT_PLACEHOLDER:
 		case EType::ARTIFACT_INSTANCE:
 			image->moveTo(pos.topLeft() + Point(0, 1));
-			subtitle->moveTo(pos.topLeft() + Point(22, 56));
+			subtitle->moveTo(pos.topLeft() + Point(21, 56));
 			break;
 		case EType::ARTIFACT_TYPE:
 			subtitle->moveTo(pos.topLeft() + Point(35, 57));
@@ -104,6 +104,14 @@ void CTradeableItem::setID(int newID)
 	}
 }
 
+void CTradeableItem::clear()
+{
+	setID(-1);
+	image->setFrame(0);
+	image->disable();
+	subtitle->clear();
+}
+
 AnimationPath CTradeableItem::getFilename()
 {
 	switch(type)
@@ -228,28 +236,29 @@ void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty)
 	slot.subtitle->setText(subtitle);
 }
 
-void TradePanelBase::setSelectedFrameIndex(const std::optional<size_t> & index)
+void TradePanelBase::setShowcaseSubtitle(const std::string & text)
 {
-	if(index.has_value())
-	{
-		selectedSlot->image->enable();
-		selectedSlot->image->setFrame(index.value());
-	}
-	else
-	{
-		selectedSlot->image->disable();
-		selectedSlot->image->setFrame(0);
-	}
+	showcaseSlot->subtitle->setText(text);
 }
 
-void TradePanelBase::setSelectedSubtitleText(const std::string & text)
+int TradePanelBase::getSelectedItemId() const
 {
-	selectedSlot->subtitle->setText(text);
+	if(highlightedSlot)
+		return highlightedSlot->id;
+	else
+		return -1;
 }
 
-void TradePanelBase::clearSelectedSubtitleText()
+void TradePanelBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot)
 {
-	selectedSlot->subtitle->clear();
+	assert(vstd::contains(slots, newSlot));
+	if(newSlot == highlightedSlot)
+		return;
+
+	if(highlightedSlot)
+		highlightedSlot->selectSlot(false);
+	highlightedSlot = newSlot;
+	newSlot->selectSlot(true);
 }
 
 ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
@@ -265,7 +274,7 @@ ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & click
 		slot->setSelectionWidth(selectionWidth);
 	}
 	updateSlotsCallback = updateSubtitles;
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0);
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0);
 }
 
 ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
@@ -287,8 +296,8 @@ ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & click
 		}
 	}
 	updateSlotsCallback = updateSubtitles;
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
-	selectedSlot->subtitle->moveBy(Point(0, 1));
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
+	showcaseSlot->subtitle->moveBy(Point(0, 1));
 }
 
 PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
@@ -313,7 +322,7 @@ PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPres
 		slot->subtitle->setText(CGI->generaltexth->capColors[players[slotNum].num]);
 		slotNum++;
 	}
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::PLAYER, 0, 0);
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::PLAYER, 0, 0);
 }
 
 CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const slotsData & initialSlots)
@@ -331,7 +340,7 @@ CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & click
 			slot->subtitle->setText(std::to_string(creaturesNum));
 		slot->setSelectionWidth(selectionWidth);
 	}
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
 }
 
 CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
@@ -348,7 +357,7 @@ CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & click
 		slot->subtitle->setText(emptySlots ? "" : srcSlot->subtitle->getText());
 		slot->setSelectionWidth(selectionWidth);
 	}
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
 }
 
 ArtifactsAltarPanel::ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
@@ -364,6 +373,6 @@ ArtifactsAltarPanel::ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunct
 		slot->subtitle->moveBy(Point(0, -1));
 		slotNum++;
 	}
-	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
-	selectedSlot->subtitle->moveBy(Point(0, 3));
+	showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
+	showcaseSlot->subtitle->moveBy(Point(0, 3));
 }

+ 6 - 5
client/widgets/markets/TradePanels.h

@@ -35,6 +35,7 @@ public:
 
 	void setType(EType newType);
 	void setID(int newID);
+	void clear();
 
 	void showPopupWindow(const Point & cursorPosition) override;
 	void hover(bool on) override;
@@ -52,16 +53,16 @@ public:
 	UpdateSlotsFunctor updateSlotsCallback;
 	DeleteSlotsCheck deleteSlotsCheck;
 	const int selectionWidth = 2;
-	std::shared_ptr<CTradeableItem> selectedSlot;		// Separate slot that displays the contents of the highlighted slot
+	std::shared_ptr<CTradeableItem> showcaseSlot;		// Separate slot that displays the contents for trading
 	std::shared_ptr<CTradeableItem> highlightedSlot;	// One of the slots highlighted by a frame
 
 	virtual void update();
 	virtual void deselect();
 	virtual void clearSubtitles();
 	void updateOffer(CTradeableItem & slot, int, int);
-	void setSelectedFrameIndex(const std::optional<size_t> & index);
-	void setSelectedSubtitleText(const std::string & text);
-	void clearSelectedSubtitleText();
+	void setShowcaseSubtitle(const std::string & text);
+	int getSelectedItemId() const;
+	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot);
 };
 
 class ResourcesPanel : public TradePanelBase
@@ -153,5 +154,5 @@ class ArtifactsAltarPanel : public TradePanelBase
 	const Point selectedPos = Point(-48, 389);
 
 public:
-	ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
+	explicit ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
 };

+ 1 - 1
client/windows/CMarketWindow.cpp

@@ -115,7 +115,7 @@ void CMarketWindow::artifactMoved(const ArtifactLocation & srcLoc, const Artifac
 
 void CMarketWindow::createChangeModeButtons(EMarketMode currentMode, const IMarket * market, const CGHeroInstance * hero)
 {
-	auto isButton = [this, currentMode, market, hero](EMarketMode modeButton) -> bool
+	auto isButton = [currentMode, market, hero](EMarketMode modeButton) -> bool
 	{
 		if(currentMode == modeButton)
 			return false;