浏览代码

Cleanup & refactoring

SoundSSGood 1 年之前
父节点
当前提交
4839891de4

+ 0 - 2
client/CMakeLists.txt

@@ -145,7 +145,6 @@ set(client_SRCS
 	windows/CPuzzleWindow.cpp
 	windows/CQuestLog.cpp
 	windows/CSpellWindow.cpp
-	windows/CTradeWindow.cpp
 	windows/CTutorialWindow.cpp
 	windows/CWindowObject.cpp
 	windows/CreaturePurchaseCard.cpp
@@ -335,7 +334,6 @@ set(client_HEADERS
 	windows/CPuzzleWindow.h
 	windows/CQuestLog.h
 	windows/CSpellWindow.h
-	windows/CTradeWindow.h
 	windows/CTutorialWindow.h
 	windows/CWindowObject.h
 	windows/CreaturePurchaseCard.h

+ 13 - 0
client/widgets/TextControls.cpp

@@ -95,6 +95,19 @@ void CLabel::setText(const std::string & Txt)
 	}
 }
 
+void CLabel::clear()
+{
+	text.clear();
+
+	if(autoRedraw)
+	{
+		if(background || !parent)
+			redraw();
+		else
+			parent->redraw();
+	}
+}
+
 void CLabel::setMaxWidth(int width)
 {
 	maxWidth = width;

+ 1 - 0
client/widgets/TextControls.h

@@ -57,6 +57,7 @@ public:
 	virtual void setText(const std::string & Txt);
 	virtual void setMaxWidth(int width);
 	virtual void setColor(const ColorRGBA & Color);
+	void clear();
 	size_t getWidth();
 
 	CLabel(int x = 0, int y = 0, EFonts Font = FONT_SMALL, ETextAlignment Align = ETextAlignment::TOPLEFT,

+ 6 - 6
client/widgets/markets/CAltarArtifacts.cpp

@@ -57,9 +57,9 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 	int slotNum = 0;
 	for(auto & altarSlotPos : posSlotsAltar)
 	{
-		auto altarSlot = std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum);
+		auto altarSlot = std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, slotNum);
 		altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1, hRight);
-		altarSlot->subtitle.clear();
+		altarSlot->subtitle->clear();
 		items.front().emplace_back(altarSlot);
 		slotNum++;
 	}
@@ -91,7 +91,7 @@ void CAltarArtifacts::makeDeal()
 	for(auto item : items[0])
 	{
 		item->setID(-1);
-		item->subtitle.clear();
+		item->subtitle->clear();
 	}
 	calcExpAltarForHero();
 	deal->block(tradeSlotsMap.empty());
@@ -135,7 +135,7 @@ void CAltarArtifacts::updateSlots()
 			if(tradeSlotsMap.find(altarSlot->getArtInstance()) == tradeSlotsMap.end())
 			{
 				altarSlot->setID(-1);
-				altarSlot->subtitle.clear();
+				altarSlot->subtitle->clear();
 			}
 			else
 			{
@@ -148,7 +148,7 @@ void CAltarArtifacts::updateSlots()
 		assert(tradeSlot.second->id == -1);
 		assert(altarArtifacts->getSlotByInstance(tradeSlot.first) != ArtifactPosition::PRE_FIRST);
 		tradeSlot.second->setArtInstance(tradeSlot.first);
-		tradeSlot.second->subtitle = std::to_string(calcExpCost(tradeSlot.first));
+		tradeSlot.second->subtitle->setText(std::to_string(calcExpCost(tradeSlot.first)));
 	}
 	for(auto & slotInfo : altarArtifacts->artifactsInBackpack)
 	{
@@ -158,7 +158,7 @@ void CAltarArtifacts::updateSlots()
 				if(altarSlot->id == -1)
 				{
 					altarSlot->setArtInstance(slotInfo.artifact);
-					altarSlot->subtitle = std::to_string(calcExpCost(slotInfo.artifact));
+					altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.artifact)));
 					tradeSlotsMap.try_emplace(slotInfo.artifact, altarSlot);
 					break;
 				}

+ 20 - 37
client/widgets/markets/CAltarCreatures.cpp

@@ -27,6 +27,7 @@
 
 CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
+	, CMarketMisc([this](){return CAltarCreatures::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -47,8 +48,8 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance *
 	// Hero creatures panel
 	assert(bidTradePanel);
 	bidTradePanel->moveTo(pos.topLeft() + Point(45, 110));
-	bidTradePanel->selectedImage->moveTo(pos.topLeft() + Point(149, 422));
-	bidTradePanel->selectedSubtitle->moveTo(pos.topLeft() + Point(180, 503));
+	bidTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(149, 422));
+	bidTradePanel->selectedSlot->subtitle->moveBy(Point(0, 3));
 	for(const auto & slot : bidTradePanel->slots)
 		slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, hLeft);};
 
@@ -58,8 +59,8 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance *
 			CAltarCreatures::onSlotClickPressed(altarSlot, hRight);
 		}, bidTradePanel->slots);
 	offerTradePanel->moveTo(pos.topLeft() + Point(334, 110));
-	offerTradePanel->selectedImage->moveTo(pos.topLeft() + Point(395, 422));
-	offerTradePanel->selectedSubtitle->moveTo(pos.topLeft() + Point(426, 503));
+	offerTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(395, 422));
+	offerTradePanel->selectedSlot->subtitle->moveBy(Point(0, 3));
 	offerTradePanel->updateSlotsCallback = [this]()
 	{
 		for(const auto & altarSlot : offerTradePanel->slots)
@@ -113,38 +114,9 @@ void CAltarCreatures::updateControls()
 	maxAmount->block(offerSlider->getAmount() == 0);
 }
 
-void CAltarCreatures::updateSelected()
-{
-	std::optional<size_t> lImageIndex = std::nullopt;
-	std::optional<size_t> rImageIndex = std::nullopt;
-
-	if(hLeft)
-	{
-		bidTradePanel->selectedSubtitle->setText(std::to_string(offerSlider->getValue()));
-		lImageIndex = CGI->creatures()->getByIndex(hLeft->id)->getIconIndex();
-	}
-	else
-	{
-		bidTradePanel->selectedSubtitle->setText("");
-	}
-	if(hRight)
-	{
-		offerTradePanel->selectedSubtitle->setText(hRight->subtitle);
-		if(offerSlider->getValue() != 0)
-			rImageIndex = CGI->creatures()->getByIndex(hRight->id)->getIconIndex();
-	}
-	else
-	{
-		offerTradePanel->selectedSubtitle->setText("");
-	}
-	bidTradePanel->setSelectedFrameIndex(lImageIndex);
-	offerTradePanel->setSelectedFrameIndex(rImageIndex);
-}
-
 void CAltarCreatures::updateSlots()
 {
-	offerTradePanel->updateSlots();
-	CCreaturesSelling::updateSlots();
+	CTradeBase::updateSlots();
 	assert(bidTradePanel->slots.size() == offerTradePanel->slots.size());
 }
 
@@ -190,10 +162,21 @@ void CAltarCreatures::makeDeal()
 	for(auto heroSlot : offerTradePanel->slots)
 	{
 		heroSlot->setType(EType::CREATURE_PLACEHOLDER);
-		heroSlot->subtitle.clear();
+		heroSlot->subtitle->clear();
 	}
 }
 
+CMarketMisc::SelectionParams CAltarCreatures::getSelectionParams()
+{
+	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()};
+	return std::make_tuple(bidSelected, offerSelected);
+}
+
 void CAltarCreatures::sacrificeAll()
 {
 	std::optional<SlotID> lastSlot;
@@ -225,8 +208,8 @@ void CAltarCreatures::updateAltarSlot(const std::shared_ptr<CTradeableItem> & sl
 {
 	auto units = unitsOnAltar[slot->serial];
 	slot->setType(units > 0 ? EType::CREATURE : EType::CREATURE_PLACEHOLDER);
-	slot->subtitle = units > 0 ?
-		boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "";
+	slot->subtitle->setText(units > 0 ?
+		boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "");
 }
 
 void CAltarCreatures::onOfferSliderMoved(int newVal)

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

@@ -11,7 +11,7 @@
 
 #include "CTradeBase.h"
 
-class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling
+class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling, public CMarketMisc
 {
 public:
 	CAltarCreatures(const IMarket * market, const CGHeroInstance * hero);
@@ -25,10 +25,10 @@ private:
 	std::vector<int> unitsOnAltar;
 	std::vector<int> expPerUnit;
 
+	CMarketMisc::SelectionParams getSelectionParams();
 	void updateAltarSlot(const std::shared_ptr<CTradeableItem> & slot);
 	void readExpValues();
 	void updateControls();
-	void updateSelected();
 	void onOfferSliderMoved(int newVal);
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
 };

+ 5 - 28
client/widgets/markets/CArtifactsBuying.cpp

@@ -27,6 +27,7 @@
 
 CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CArtifactsBuying::onSlotClickPressed(heroSlot, hLeft);})
 	, CMarketMisc([this](){return CArtifactsBuying::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
@@ -40,34 +41,16 @@ CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance
 
 	// Player's resources
 	assert(bidTradePanel);
-	std::for_each(bidTradePanel->slots.cbegin(), bidTradePanel->slots.cend(), [this](auto & slot)
-		{
-			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot)
-			{
-				CArtifactsBuying::onSlotClickPressed(heroSlot, hLeft);
-			};
-		});
-	bidTradePanel->moveTo(pos.topLeft() + Point(39, 182));
-	bidTradePanel->selectedImage->moveTo(pos.topLeft() + Point(141, 453));
+	bidTradePanel->moveTo(pos.topLeft() + Point(39, 184));
+	bidTradePanel->selectedSlot->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);
-		
 		}, [this]()
 		{
-			// TODO move to parent
-			if(hLeft)
-				for(const auto & slot : offerTradePanel->slots)
-				{
-					int h1, h2; //hlp variables for getting offer
-					this->market->getOffer(hLeft->id, slot->id, h1, h2, EMarketMode::RESOURCE_ARTIFACT);
-
-					offerTradePanel->updateOffer(*slot, h1, h2);
-				}
-			else
-				offerTradePanel->clearSubtitles();
+			CTradeBase::updateSubtitles(EMarketMode::RESOURCE_ARTIFACT);
 		}, market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT));
 	offerTradePanel->deleteSlotsCheck = [this](const std::shared_ptr<CTradeableItem> & slot)
 	{
@@ -75,7 +58,7 @@ CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance
 	};
 	offerTradePanel->moveTo(pos.topLeft() + Point(328, 182));
 
-	CArtifactsBuying::updateSlots();
+	CTradeBase::updateSlots();
 	CMarketMisc::deselect();
 }
 
@@ -85,12 +68,6 @@ void CArtifactsBuying::makeDeal()
 	deselect();
 }
 
-void CArtifactsBuying::updateSlots()
-{
-	CResourcesSelling::updateSlots();
-	offerTradePanel->updateSlots();
-}
-
 CMarketMisc::SelectionParams CArtifactsBuying::getSelectionParams()
 {
 	if(hLeft && hRight)

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

@@ -16,7 +16,6 @@ class CArtifactsBuying : public CResourcesSelling, public CMarketMisc
 public:
 	CArtifactsBuying(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
-	void updateSlots() override;
 
 private:
 	CMarketMisc::SelectionParams getSelectionParams();

+ 23 - 49
client/widgets/markets/CArtifactsSelling.cpp

@@ -24,15 +24,16 @@
 
 CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
-	, CResourcesBuying([this](){CArtifactsSelling::updateSubtitles();})
+	, CResourcesBuying(
+		[this](const std::shared_ptr<CTradeableItem> & resSlot){CArtifactsSelling::onSlotClickPressed(resSlot, hRight);},
+		[this](){CTradeBase::updateSubtitles(EMarketMode::ARTIFACT_RESOURCE);})
 	, CMarketMisc([this](){return CArtifactsSelling::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
 	deal = std::make_shared<CButton>(Point(270, 520), AnimationPath::builtin("TPMRKB.DEF"),
 		CGI->generaltexth->zelp[595], [this](){CArtifactsSelling::makeDeal();});
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), 10, 0, 136, 470);
-	bidSelectedSubtitle = std::make_shared<CLabel>(157, 529, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	bidSelectedSlot = std::make_shared<CTradeableItem>(Rect(Point(123, 470), Point(69, 66)), EType::ARTIFACT_TYPE, 0, 0);
 
 	// Hero's artifacts
 	heroArts = std::make_shared<CArtifactsOfHeroMarket>(Point(-361, 46));
@@ -40,11 +41,13 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 	heroArts->selectArtCallback = [this](CArtPlace * artPlace)
 	{
 		assert(artPlace);
-		artForTrade = artPlace->getArt();
-		assert(artForTrade.has_value());
+		const auto artForTrade = artPlace->getArt();
+		assert(artForTrade);
+		bidSelectedSlot->setID(artForTrade->getTypeId().num);
+		hLeft = bidSelectedSlot;
 		if(hRight)
-		{
-			this->market->getOffer(artForTrade.value()->getTypeId().num, hRight->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
+		{	// dublicate
+			this->market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
 			deal->block(false);
 		}
 		CArtifactsSelling::updateSelected();
@@ -54,20 +57,11 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 
 	// 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)
-			{
-				CArtifactsSelling::onSlotClickPressed(resSlot, hRight);
-			};
-		});
-	offerTradePanel->selectedImage->moveTo(pos.topLeft() + Point(428, 479));
-	offerTradePanel->selectedSubtitle->moveTo(pos.topLeft() + Point(445, 526));
-	offerTradePanel->moveTo(pos.topLeft() + Point(326, 183));
+	offerTradePanel->moveTo(pos.topLeft() + Point(326, 184));
+	offerTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(409, 473));
 	
-
 	CArtifactsSelling::updateSelected();
-	CArtifactsSelling::deselect();
+	CMarketMisc::deselect();
 }
 
 void CArtifactsSelling::makeDeal()
@@ -75,27 +69,21 @@ void CArtifactsSelling::makeDeal()
 
 }
 
-void CArtifactsSelling::deselect()
-{
-	CTradeBase::deselect();
-	artForTrade = std::nullopt;
-}
-
 void CArtifactsSelling::updateSelected()
 {
 	CMarketMisc::updateSelected();
 
-	if(artForTrade.has_value() && hRight)
+	if(hLeft && hRight)
 	{
-		bidSelectedSubtitle->setText(std::to_string(bidQty));
-		selectedImage->enable();
-		selectedImage->setFrame(CGI->artifacts()->getByIndex(artForTrade.value()->getTypeId())->getIconIndex());
+		bidSelectedSlot->image->enable();
+		bidSelectedSlot->image->setFrame(CGI->artifacts()->getByIndex(hLeft->id)->getIconIndex());
+		bidSelectedSlot->subtitle->setText(std::to_string(bidQty));
 	}
 	else
 	{
-		selectedImage->disable();
-		selectedImage->setFrame(0);
-		bidSelectedSubtitle->setText("");
+		bidSelectedSlot->image->disable();
+		bidSelectedSlot->image->setFrame(0);
+		bidSelectedSlot->subtitle->clear();
 	}
 }
 
@@ -106,7 +94,7 @@ std::shared_ptr<CArtifactsOfHeroMarket> CArtifactsSelling::getAOHset() const
 
 CMarketMisc::SelectionParams CArtifactsSelling::getSelectionParams()
 {
-	if(artForTrade.has_value() && hRight)
+	if(hLeft && hRight)
 		return std::make_tuple(
 			std::nullopt,
 			SelectionParamOneSide {std::to_string(offerQty), GameResID(hRight->id)}
@@ -115,20 +103,6 @@ CMarketMisc::SelectionParams CArtifactsSelling::getSelectionParams()
 		return std::make_tuple(std::nullopt, std::nullopt);
 }
 
-void CArtifactsSelling::updateSubtitles()
-{
-	if(artForTrade.has_value())
-		for(const auto & slot : offerTradePanel->slots)
-		{
-			int bidQty = 0;
-			int offerQty = 0;
-			market->getOffer(artForTrade.value()->getTypeId().num, slot->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
-			offerTradePanel->updateOffer(*slot, bidQty, offerQty);
-		}
-	else
-		offerTradePanel->clearSubtitles();
-}
-
 void CArtifactsSelling::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
 {
 	assert(newSlot);
@@ -136,11 +110,11 @@ void CArtifactsSelling::onSlotClickPressed(const std::shared_ptr<CTradeableItem>
 		return;
 
 	CTradeBase::onSlotClickPressed(newSlot, hCurSlot);
-	if(artForTrade.has_value())
+	if(hLeft)
 	{
 		if(hRight)
 		{
-			market->getOffer(artForTrade.value()->getTypeId().num, hRight->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
+			market->getOffer(hLeft->id, hRight->id, bidQty, offerQty, EMarketMode::ARTIFACT_RESOURCE);
 			deal->block(false);
 		}
 		updateSelected();

+ 1 - 5
client/widgets/markets/CArtifactsSelling.h

@@ -17,18 +17,14 @@ class CArtifactsSelling : public CResourcesBuying, public CMarketMisc
 public:
 	CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
-	void deselect() override;
 	void updateSelected();
 	std::shared_ptr<CArtifactsOfHeroMarket> getAOHset() const;
 
 private:
 	std::shared_ptr<CArtifactsOfHeroMarket> heroArts;
-	std::optional<const CArtifactInstance*> artForTrade;
-	std::shared_ptr<CAnimImage> selectedImage;
-	std::shared_ptr<CLabel> selectedSubtitle;
 	std::shared_ptr<CLabel> bidSelectedSubtitle;
+	std::shared_ptr<CTradeableItem> bidSelectedSlot;
 
-	void updateSubtitles();
 	CMarketMisc::SelectionParams getSelectionParams();
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
 };

+ 4 - 1
client/widgets/markets/CFreelancerGuild.cpp

@@ -28,7 +28,9 @@
 
 CFreelancerGuild::CFreelancerGuild(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
-	, CResourcesBuying([this](){CResourcesBuying::updateSubtitles(EMarketMode::CREATURE_RESOURCE);})
+	, CResourcesBuying(
+		[this](const std::shared_ptr<CTradeableItem> & heroSlot){CFreelancerGuild::onSlotClickPressed(heroSlot, hLeft);},
+		[this](){CTradeBase::updateSubtitles(EMarketMode::CREATURE_RESOURCE);})
 	, CMarketMisc([this](){return CFreelancerGuild::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -49,6 +51,7 @@ 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->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1);
 	std::for_each(bidTradePanel->slots.cbegin(), bidTradePanel->slots.cend(), [this](auto & slot)
 		{

+ 8 - 12
client/widgets/markets/CMarketResources.cpp

@@ -26,7 +26,10 @@
 
 CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
-	, CResourcesBuying([this](){CMarketResources::updateSubtitles();})
+	, CResourcesBuying(
+		[this](const std::shared_ptr<CTradeableItem> & resSlot){CMarketResources::onSlotClickPressed(resSlot, hRight);},
+		[this](){CMarketResources::updateSubtitles();})
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CMarketResources::onSlotClickPressed(heroSlot, hLeft);})
 	, CMarketMisc([this](){return CMarketResources::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -43,14 +46,7 @@ CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance
 
 	// Player's resources
 	assert(bidTradePanel);
-	std::for_each(bidTradePanel->slots.cbegin(), bidTradePanel->slots.cend(), [this](auto & slot)
-		{
-			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot)
-			{
-				CMarketResources::onSlotClickPressed(heroSlot, hLeft);
-			};
-		});
-	bidTradePanel->moveTo(pos.topLeft() + Point(39, 181));
+	bidTradePanel->moveTo(pos.topLeft() + Point(39, 182));
 
 	// Market resources panel
 	assert(offerTradePanel);
@@ -62,7 +58,7 @@ CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance
 			};
 		});
 
-	CResourcesSelling::updateSlots();
+	CTradeBase::updateSlots();
 	CMarketMisc::deselect();
 }
 
@@ -121,7 +117,7 @@ void CMarketResources::onSlotClickPressed(const std::shared_ptr<CTradeableItem>
 
 void CMarketResources::updateSubtitles()
 {
-	CResourcesBuying::updateSubtitles(EMarketMode::RESOURCE_RESOURCE);
+	CTradeBase::updateSubtitles(EMarketMode::RESOURCE_RESOURCE);
 	if(hLeft)
-		offerTradePanel->slots[hLeft->serial]->subtitle = CGI->generaltexth->allTexts[164]; // n/a
+		offerTradePanel->slots[hLeft->serial]->subtitle->setText(CGI->generaltexth->allTexts[164]); // n/a
 }

+ 36 - 34
client/widgets/markets/CTradeBase.cpp

@@ -12,6 +12,7 @@
 
 #include "../MiscWidgets.h"
 
+#include "../Images.h"
 #include "../../gui/CGuiHandler.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/Slider.h"
@@ -81,6 +82,28 @@ void CTradeBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newS
 	newSlot->selectSlot(true);
 }
 
+void CTradeBase::updateSlots()
+{
+	if(bidTradePanel)
+		bidTradePanel->updateSlots();
+	if(offerTradePanel)
+		offerTradePanel->updateSlots();
+}
+
+void CTradeBase::updateSubtitles(EMarketMode marketMode)
+{
+	if(hLeft)
+		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);
+		}
+	else
+		offerTradePanel->clearSubtitles();
+};
+
 CExperienceAltar::CExperienceAltar()
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -116,55 +139,34 @@ bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem>
 void CCreaturesSelling::updateSubtitle()
 {
 	for(auto & heroSlot : bidTradePanel->slots)
-		heroSlot->subtitle = std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)));
+		heroSlot->subtitle->setText(std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial))));
 }
 
-void CCreaturesSelling::updateSlots()
-{
-	bidTradePanel->updateSlots();
-}
-
-CResourcesBuying::CResourcesBuying(TradePanelBase::UpdateSlotsFunctor callback)
+CResourcesBuying::CResourcesBuying(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
+	const TradePanelBase::UpdateSlotsFunctor & updSlotsCallback)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
-	offerTradePanel = std::make_shared<ResourcesPanel>([](const std::shared_ptr<CTradeableItem>&) {}, callback);
-	offerTradePanel->moveTo(pos.topLeft() + Point(327, 181));
+	offerTradePanel = std::make_shared<ResourcesPanel>(clickPressedCallback, updSlotsCallback);
+	offerTradePanel->moveTo(pos.topLeft() + Point(327, 182));
 	labels.emplace_back(std::make_shared<CLabel>(445, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[168]));
 }
 
-void CResourcesBuying::updateSubtitles(EMarketMode marketMode)
-{
-	if(hLeft)
-		for(const auto & slot : offerTradePanel->slots)
-		{
-			int h1, h2; //hlp variables for getting offer
-			market->getOffer(hLeft->id, slot->id, h1, h2, marketMode);
-
-			offerTradePanel->updateOffer(*slot, h1, h2);
-		}
-	else
-		offerTradePanel->clearSubtitles();
-};
-
-CResourcesSelling::CResourcesSelling()
+CResourcesSelling::CResourcesSelling(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
-	bidTradePanel = std::make_shared<ResourcesPanel>([](const std::shared_ptr<CTradeableItem>&) {}, [this]()
-		{
-			for(const auto & slot : bidTradePanel->slots)
-				slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial)));
-		});
+	bidTradePanel = std::make_shared<ResourcesPanel>(clickPressedCallback, std::bind(&CResourcesSelling::updateSubtitle, this));
 	labels.emplace_back(std::make_shared<CLabel>(156, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]));
 }
 
-void CResourcesSelling::updateSlots()
+void CResourcesSelling::updateSubtitle()
 {
-	bidTradePanel->updateSlots();
+	for(const auto & slot : bidTradePanel->slots)
+		slot->subtitle->setText(std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial))));
 }
 
-CMarketMisc::CMarketMisc(SelectionParamsFunctor callback)
+CMarketMisc::CMarketMisc(const SelectionParamsFunctor & callback)
 	: selectionParamsCallback(callback)
 {
 }
@@ -184,12 +186,12 @@ void CMarketMisc::updateSelected()
 		std::optional<size_t> lImageIndex = std::nullopt;
 		if(params.has_value())
 		{
-			tradePanel->selectedSubtitle->setText(params.value().text);
+			tradePanel->setSelectedSubtitleText(params.value().text);
 			lImageIndex = params.value().imageIndex;
 		}
 		else
 		{
-			tradePanel->selectedSubtitle->setText("");
+			tradePanel->clearSelectedSubtitleText();
 		}
 		tradePanel->setSelectedFrameIndex(lImageIndex);
 	};

+ 14 - 14
client/widgets/markets/CTradeBase.h

@@ -21,7 +21,7 @@ VCMI_LIB_NAMESPACE_END
 class CButton;
 class CSlider;
 
-class CTradeBase
+class CTradeBase : public CIntObject
 {
 public:
 	const IMarket * market;
@@ -49,11 +49,12 @@ public:
 	virtual void makeDeal() = 0;
 	virtual void deselect();
 	virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
-	virtual void updateSlots() {};	// TODO make pure virtual
+	virtual void updateSlots();
+	virtual void updateSubtitles(EMarketMode marketMode);
 };
 
 // Market subclasses
-class CExperienceAltar : virtual public CTradeBase, virtual public CIntObject
+class CExperienceAltar : virtual public CTradeBase
 {
 public:
 	std::shared_ptr<CLabel> expToLevel;
@@ -66,30 +67,29 @@ public:
 	virtual TExpType calcExpAltarForHero() = 0;
 };
 
-class CCreaturesSelling : virtual public CTradeBase, virtual public CIntObject
+class CCreaturesSelling : virtual public CTradeBase
 {
 public:
 	CCreaturesSelling();
 	bool slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot);
 	void updateSubtitle();
-	void updateSlots() override;
 };
 
-class CResourcesBuying : virtual public CTradeBase, virtual public CIntObject
+class CResourcesBuying : virtual public CTradeBase
 {
 public:
-	CResourcesBuying(TradePanelBase::UpdateSlotsFunctor callback);
-	void updateSubtitles(EMarketMode marketMode);
+	CResourcesBuying(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
+		const TradePanelBase::UpdateSlotsFunctor & updSlotsCallback);
 };
 
-class CResourcesSelling : virtual public CTradeBase, virtual public CIntObject
+class CResourcesSelling : virtual public CTradeBase
 {
 public:
-	CResourcesSelling();
-	void updateSlots() override;
+	CResourcesSelling(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
+	void updateSubtitle();
 };
 
-class CMarketMisc : virtual public CTradeBase, virtual public CIntObject
+class CMarketMisc : virtual public CTradeBase
 {
 public:
 	struct SelectionParamOneSide
@@ -98,9 +98,9 @@ public:
 		int imageIndex; 
 	};
 	using SelectionParams = std::tuple<std::optional<const SelectionParamOneSide>, std::optional<const SelectionParamOneSide>>;
-	using SelectionParamsFunctor = std::function<SelectionParams()>;
+	using SelectionParamsFunctor = std::function<const SelectionParams()>;
 
-	CMarketMisc(SelectionParamsFunctor callback);
+	CMarketMisc(const SelectionParamsFunctor & callback);
 	void deselect() override;
 	void updateSelected();
 

+ 4 - 10
client/widgets/markets/CTransferResources.cpp

@@ -25,6 +25,7 @@
 
 CTransferResources::CTransferResources(const IMarket * market, const CGHeroInstance * hero)
 	: CTradeBase(market, hero)
+	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CTransferResources::onSlotClickPressed(heroSlot, hLeft);})
 	, CMarketMisc([this](){return CTransferResources::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -42,23 +43,16 @@ CTransferResources::CTransferResources(const IMarket * market, const CGHeroInsta
 
 	// Player's resources
 	assert(bidTradePanel);
-	std::for_each(bidTradePanel->slots.cbegin(), bidTradePanel->slots.cend(), [this](auto & slot)
-		{
-			slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot)
-			{
-				CTransferResources::onSlotClickPressed(heroSlot, hLeft);
-			};
-		});
-	bidTradePanel->moveTo(pos.topLeft() + Point(40, 182));
+	bidTradePanel->moveTo(pos.topLeft() + Point(40, 183));
 
 	// Players panel
 	offerTradePanel = std::make_shared<PlayersPanel>([this](const std::shared_ptr<CTradeableItem> & heroSlot)
 		{
 			CTransferResources::onSlotClickPressed(heroSlot, hRight);
 		});
-	offerTradePanel->moveTo(pos.topLeft() + Point(333, 83));
+	offerTradePanel->moveTo(pos.topLeft() + Point(333, 84));
 
-	CResourcesSelling::updateSlots();
+	CTradeBase::updateSlots();
 	CTransferResources::deselect();
 }
 

+ 66 - 114
client/widgets/markets/TradePanels.cpp

@@ -23,14 +23,12 @@
 #include "../../../lib/CGeneralTextHandler.h"
 #include "../../../lib/mapObjects/CGHeroInstance.h"
 
-CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, bool Left, int Serial)
-	: SelectableSlot(area, Point(1, 1))
+CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, int Serial)
+	: SelectableSlot(area, Point(1, 2))
 	, artInstance(nullptr)
 	, type(EType(-1)) // set to invalid, will be corrected in setType
 	, id(ID)
 	, serial(Serial)
-	, left(Left)
-	, downSelection(false)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -38,6 +36,7 @@ CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, bool Left,
 	addUsedEvents(HOVER);
 	addUsedEvents(SHOW_POPUP);
 	
+	subtitle = std::make_shared<CLabel>(0, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 	setType(Type);
 
 	this->pos.w = area.w;
@@ -60,6 +59,28 @@ void CTradeableItem::setType(EType newType)
 		{
 			image = std::make_shared<CAnimImage>(getFilename(), getIndex());
 		}
+
+		switch(type)
+		{
+		case EType::RESOURCE:
+			subtitle->moveTo(pos.topLeft() + Point(35, 55));
+			image->moveTo(pos.topLeft() + Point(19, 8));
+			break;
+		case EType::CREATURE_PLACEHOLDER:
+		case EType::CREATURE:
+			subtitle->moveTo(pos.topLeft() + Point(30, 77));
+			break;
+		case EType::PLAYER:
+			subtitle->moveTo(pos.topLeft() + Point(31, 76));
+			break;
+		case EType::ARTIFACT_PLACEHOLDER:
+		case EType::ARTIFACT_INSTANCE:
+			break;
+		case EType::ARTIFACT_TYPE:
+			subtitle->moveTo(pos.topLeft() + Point(35, 57));
+			image->moveTo(pos.topLeft() + Point(13, 0));
+			break;
+		}
 	}
 }
 
@@ -122,66 +143,12 @@ int CTradeableItem::getIndex()
 	}
 }
 
-void CTradeableItem::showAll(Canvas & to)
-{
-	Point posToBitmap;
-	Point posToSubCenter;
-
-	switch(type)
-	{
-	case EType::RESOURCE:
-		posToBitmap = Point(19, 9);
-		posToSubCenter = Point(35, 57);
-		break;
-	case EType::CREATURE_PLACEHOLDER:
-	case EType::CREATURE:
-		posToSubCenter = Point(29, 77);
-		break;
-	case EType::PLAYER:
-		posToSubCenter = Point(31, 77);
-		break;
-	case EType::ARTIFACT_PLACEHOLDER:
-	case EType::ARTIFACT_INSTANCE:
-		posToSubCenter = Point(22, 51);
-		if (downSelection)
-			posToSubCenter.y += 8;
-		break;
-	case EType::ARTIFACT_TYPE:
-		posToSubCenter = Point(35, 57);
-		posToBitmap = Point(13, 0);
-		break;
-	}
-
-	if(image)
-	{
-		image->moveTo(pos.topLeft() + posToBitmap);
-		CIntObject::showAll(to);
-	}
-
-	to.drawText(pos.topLeft() + posToSubCenter, FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, subtitle);
-}
-
 void CTradeableItem::clickPressed(const Point & cursorPosition)
 {
 	if(clickPressedCallback)
 		clickPressedCallback(shared_from_this());
 }
 
-void CTradeableItem::showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to)
-{
-	Rect oldPos = pos;
-	std::string oldSub = subtitle;
-	downSelection = true;
-
-	moveTo(dstPos);
-	subtitle = customSub;
-	showAll(to);
-
-	downSelection = false;
-	moveTo(oldPos.topLeft());
-	subtitle = oldSub;
-}
-
 void CTradeableItem::hover(bool on)
 {
 	if(!on)
@@ -228,28 +195,7 @@ void CTradeableItem::showPopupWindow(const Point & cursorPosition)
 	}
 }
 
-std::string CTradeableItem::getName(int number) const
-{
-	switch(type)
-	{
-	case EType::PLAYER:
-		return CGI->generaltexth->capColors[id];
-	case EType::RESOURCE:
-		return CGI->generaltexth->restypes[id];
-	case EType::CREATURE:
-		if (number == 1)
-			return CGI->creh->objects[id]->getNameSingularTranslated();
-		else
-			return CGI->creh->objects[id]->getNamePluralTranslated();
-	case EType::ARTIFACT_TYPE:
-	case EType::ARTIFACT_INSTANCE:
-		return CGI->artifacts()->getByIndex(id)->getNameTranslated();
-	}
-	logGlobal->error("Invalid trade item type: %d", (int)type);
-	return "";
-}
-
-const CArtifactInstance * CTradeableItem::getArtInstance() const
+const CArtifactInstance* CTradeableItem::getArtInstance() const
 {
 	switch(type)
 	{
@@ -289,52 +235,62 @@ void TradePanelBase::deselect()
 void TradePanelBase::clearSubtitles()
 {
 	for(const auto & slot : slots)
-		slot->subtitle.clear();
+		slot->subtitle->clear();
 }
 
 void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty)
 {
-	slot.subtitle = std::to_string(qty);
+	std::string subtitle = std::to_string(qty);
 	if(cost != 1)
 	{
-		slot.subtitle.append("/");
-		slot.subtitle.append(std::to_string(cost));
+		subtitle.append("/");
+		subtitle.append(std::to_string(cost));
 	}
+	slot.subtitle->setText(subtitle);
 }
 
-void TradePanelBase::setSelectedFrameIndex(std::optional<size_t> index)
+void TradePanelBase::setSelectedFrameIndex(const std::optional<size_t> & index)
 {
 	if(index.has_value())
 	{
-		selectedImage->enable();
-		selectedImage->setFrame(index.value());
+		selectedSlot->image->enable();
+		selectedSlot->image->setFrame(index.value());
 	}
 	else
 	{
-		selectedImage->disable();
-		selectedImage->setFrame(0);
+		selectedSlot->image->disable();
+		selectedSlot->image->setFrame(0);
 	}
 }
 
-ResourcesPanel::ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles)
+void TradePanelBase::setSelectedSubtitleText(const std::string & text)
+{
+	selectedSlot->subtitle->setText(text);
+}
+
+void TradePanelBase::clearSelectedSubtitleText()
+{
+	selectedSlot->subtitle->clear();
+}
+
+ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
+	const UpdateSlotsFunctor & updateSubtitles)
 {
 	assert(resourcesForTrade.size() == slotsPos.size());
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
 	for(const auto & res : resourcesForTrade)
 	{
-		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[res.num], slotDimension),
-			EType::RESOURCE, res.num, true, res.num));
+		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[res.num], slotDimension), EType::RESOURCE, res.num, res.num));
 		slot->clickPressedCallback = clickPressedCallback;
 		slot->setSelectionWidth(selectionWidth);
 	}
 	updateSlotsCallback = updateSubtitles;
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("RESOURCE"), 0, 0, selectedImagePos.x, selectedImagePos.y);
-	selectedSubtitle = std::make_shared<CLabel>(selectedSubtitlePos.x, selectedSubtitlePos.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0);
 }
 
-ArtifactsPanel::ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles,
-	const std::vector<TradeItemBuy> & arts)
+ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
+	const UpdateSlotsFunctor & updateSubtitles, const std::vector<TradeItemBuy> & arts)
 {
 	assert(slotsForTrade == slotsPos.size());
 	assert(slotsForTrade == arts.size());
@@ -346,17 +302,16 @@ ArtifactsPanel::ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedC
 		if(artType != ArtifactID::NONE)
 		{
 			auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotIdx], slotDimension),
-				EType::ARTIFACT_TYPE, artType, false, slotIdx));
+				EType::ARTIFACT_TYPE, artType, slotIdx));
 			slot->clickPressedCallback = clickPressedCallback;
 			slot->setSelectionWidth(selectionWidth);
 		}
 	}
 	updateSlotsCallback = updateSubtitles;
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), 0, 0, selectedImagePos.x, selectedImagePos.y);
-	selectedSubtitle = std::make_shared<CLabel>(selectedSubtitlePos.x, selectedSubtitlePos.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
 }
 
-PlayersPanel::PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback)
+PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
 {
 	assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size() + 1);
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
@@ -372,17 +327,16 @@ PlayersPanel::PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallb
 	int slotNum = 0;
 	for(auto & slot : slots)
 	{
-		slot = std::make_shared<CTradeableItem>(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, false, slotNum);
+		slot = std::make_shared<CTradeableItem>(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, slotNum);
 		slot->clickPressedCallback = clickPressedCallback;
 		slot->setSelectionWidth(selectionWidth);
-		slot->subtitle = CGI->generaltexth->capColors[players[slotNum].num];
+		slot->subtitle->setText(CGI->generaltexth->capColors[players[slotNum].num]);
 		slotNum++;
 	}
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("CREST58"), 0, 0, selectedImagePos.x, selectedImagePos.y);
-	selectedSubtitle = std::make_shared<CLabel>(selectedSubtitlePos.x, selectedSubtitlePos.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::PLAYER, 0, 0);
 }
 
-CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots)
+CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const slotsData & initialSlots)
 {
 	assert(initialSlots.size() <= GameConstants::ARMY_SIZE);
 	assert(slotsPos.size() <= GameConstants::ARMY_SIZE);
@@ -391,17 +345,16 @@ CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedC
 	for(const auto & [creatureId, slotId, creaturesNum] : initialSlots)
 	{
 		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotId.num], slotDimension),
-			creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, true, slotId));
+			creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, slotId));
 		slot->clickPressedCallback = clickPressedCallback;
 		if(creaturesNum != 0)
-			slot->subtitle = std::to_string(creaturesNum);
+			slot->subtitle->setText(std::to_string(creaturesNum));
 		slot->setSelectionWidth(selectionWidth);
 	}
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), 0, 0, selectedImagePos.x, selectedImagePos.y);
-	selectedSubtitle = std::make_shared<CLabel>(selectedSubtitlePos.x, selectedSubtitlePos.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
 }
 
-CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
+CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
 	const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots)
 {
 	assert(slots.size() <= GameConstants::ARMY_SIZE);
@@ -410,11 +363,10 @@ CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedC
 	for(const auto & srcSlot : srcSlots)
 	{
 		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[srcSlot->serial], srcSlot->pos.dimensions()),
-			emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, true, srcSlot->serial));
+			emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, srcSlot->serial));
 		slot->clickPressedCallback = clickPressedCallback;
-		slot->subtitle = emptySlots ? "" : srcSlot->subtitle;
+		slot->subtitle->setText(emptySlots ? "" : srcSlot->subtitle->getText());
 		slot->setSelectionWidth(selectionWidth);
 	}
-	selectedImage = std::make_shared<CAnimImage>(AnimationPath::builtin("TWCRPORT"), 0, 0, selectedImagePos.x, selectedImagePos.y);
-	selectedSubtitle = std::make_shared<CLabel>(selectedSubtitlePos.x, selectedSubtitlePos.y, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
 }

+ 17 - 27
client/widgets/markets/TradePanels.h

@@ -31,8 +31,7 @@ public:
 	EType type;
 	int id;
 	const int serial;
-	const bool left;
-	std::string subtitle;
+	std::shared_ptr<CLabel> subtitle;
 	ClickPressedFunctor clickPressedCallback;
 
 	void setType(EType newType);
@@ -41,16 +40,10 @@ public:
 	const CArtifactInstance * getArtInstance() const;
 	void setArtInstance(const CArtifactInstance * art);
 
-	bool downSelection;
-
-	void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to);
-
 	void showPopupWindow(const Point & cursorPosition) override;
 	void hover(bool on) override;
-	void showAll(Canvas & to) override;
 	void clickPressed(const Point & cursorPosition) override;
-	std::string getName(int number = -1) const;
-	CTradeableItem(const Rect & area, EType Type, int ID, bool Left, int Serial);
+	CTradeableItem(const Rect & area, EType Type, int ID, int Serial);
 };
 
 class TradePanelBase : public CIntObject
@@ -64,14 +57,15 @@ public:
 	DeleteSlotsCheck deleteSlotsCheck;
 	std::shared_ptr<CTradeableItem> selected;
 	const int selectionWidth = 2;
-	std::shared_ptr<CAnimImage> selectedImage;
-	std::shared_ptr<CLabel> selectedSubtitle;
+	std::shared_ptr<CTradeableItem> selectedSlot;
 
 	virtual void updateSlots();
 	virtual void deselect();
 	virtual void clearSubtitles();
 	void updateOffer(CTradeableItem & slot, int, int);
-	void setSelectedFrameIndex(std::optional<size_t> index);
+	void setSelectedFrameIndex(const std::optional<size_t> & index);
+	void setSelectedSubtitleText(const std::string & text);
+	void clearSelectedSubtitleText();
 };
 
 class ResourcesPanel : public TradePanelBase
@@ -89,11 +83,10 @@ class ResourcesPanel : public TradePanelBase
 		Point(83, 158)
 	};
 	const Point slotDimension = Point(69, 66);
-	const Point selectedImagePos = Point(101, 276);
-	const Point selectedSubtitlePos = Point(118, 324);
+	const Point selectedPos = Point(83, 267);
 
 public:
-	ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles);
+	ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const UpdateSlotsFunctor & updateSubtitles);
 };
 
 class ArtifactsPanel : public TradePanelBase
@@ -106,12 +99,11 @@ class ArtifactsPanel : public TradePanelBase
 	};
 	const size_t slotsForTrade = 7;
 	const Point slotDimension = Point(69, 66);
-	const Point selectedImagePos = Point(96, 266);
-	const Point selectedSubtitlePos = Point(118, 324);
+	const Point selectedPos = Point(83, 266);
 
 public:
-	ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles,
-		const std::vector<TradeItemBuy> & arts);
+	ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
+		const UpdateSlotsFunctor & updateSubtitles, const std::vector<TradeItemBuy> & arts);
 };
 
 class PlayersPanel : public TradePanelBase
@@ -123,11 +115,10 @@ class PlayersPanel : public TradePanelBase
 		Point(83, 236)
 	};
 	const Point slotDimension = Point(58, 64);
-	const Point selectedImagePos = Point(83, 368);
-	const Point selectedSubtitlePos = Point(112, 443);
+	const Point selectedPos = Point(83, 367);
 
 public:
-	explicit PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback);
+	explicit PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
 };
 
 class CreaturesPanel : public TradePanelBase
@@ -138,14 +129,13 @@ class CreaturesPanel : public TradePanelBase
 		Point(0, 98), Point(83, 98), Point(166, 98),
 		Point(83, 196)
 	};
-	const Point slotDimension = Point(58, 64);
-	const Point selectedImagePos = Point(83, 327);
-	const Point selectedSubtitlePos = Point(113, 403);
+	const Point slotDimension = Point(59, 64);
+	const Point selectedPos = Point(83, 327);
 
 public:
 	using slotsData = std::vector<std::tuple<CreatureID, SlotID, int>>;
 
-	CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots);
-	CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
+	CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const slotsData & initialSlots);
+	CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
 		const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots = true);
 };

+ 2 - 11
client/windows/CMarketWindow.cpp

@@ -69,6 +69,8 @@ void CMarketWindow::updateGarrisons()
 {
 	if(guild)
 		guild->updateSlots();
+	if(altar)
+		altar->updateSlots();
 }
 
 void CMarketWindow::resourceChanged()
@@ -154,17 +156,6 @@ void CMarketWindow::createChangeModeButtons(EMarketMode currentMode, const IMark
 	}
 }
 
-void CMarketWindow::createInternals(EMarketMode mode, const IMarket * market, const CGHeroInstance * hero)
-{
-	background->center();
-	pos = background->pos;
-	this->market->setRedrawParent(true);
-	createChangeModeButtons(mode, market, hero);
-	quitButton = std::make_shared<CButton>(quitButtonPos, AnimationPath::builtin("IOK6432.DEF"),
-		CGI->generaltexth->zelp[600], [this]() {close(); }, EShortcut::GLOBAL_RETURN);
-	redraw();
-}
-
 void CMarketWindow::createArtifactsBuying(const IMarket * market, const CGHeroInstance * hero)
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);

+ 2 - 3
client/windows/CMarketWindow.h

@@ -9,7 +9,8 @@
  */
 #pragma once
 
-#include "CTradeWindow.h"
+#include "../widgets/markets/CTradeBase.h"
+#include "CWindowObject.h"
 #include "CAltarWindow.h"
 
 class CArtifactsBuying;
@@ -30,7 +31,6 @@ public:
 
 private:
 	void createChangeModeButtons(EMarketMode currentMode, const IMarket * market, const CGHeroInstance * hero);
-	void createInternals(EMarketMode mode, const IMarket * market, const CGHeroInstance * hero);
 
 	void createArtifactsBuying(const IMarket * market, const CGHeroInstance * hero);
 	void createArtifactsSelling(const IMarket * market, const CGHeroInstance * hero);
@@ -47,7 +47,6 @@ private:
 	std::function<void()> windowClosedCallback;
 	const Point quitButtonPos = Point(516, 520);
 
-	std::shared_ptr<CMarketplaceWindow> market;
 	std::shared_ptr<CFreelancerGuild> guild;
 	std::shared_ptr<CMarketResources> resRes;
 	std::shared_ptr<CTransferResources> trRes;

+ 0 - 574
client/windows/CTradeWindow.cpp

@@ -1,574 +0,0 @@
-/*
- * CTradeWindow.cpp, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#include "StdInc.h"
-#include "CTradeWindow.h"
-
-#include "../gui/CGuiHandler.h"
-#include "../gui/CursorHandler.h"
-#include "../render/Canvas.h"
-#include "../gui/Shortcut.h"
-#include "../gui/WindowHandler.h"
-#include "../widgets/Buttons.h"
-#include "../widgets/Slider.h"
-#include "../widgets/TextControls.h"
-
-#include "../CGameInfo.h"
-#include "../CPlayerInterface.h"
-
-#include "../../CCallback.h"
-
-#include "../../lib/CGeneralTextHandler.h"
-#include "../../lib/CHeroHandler.h"
-#include "../../lib/mapObjects/CGHeroInstance.h"
-#include "../../lib/mapObjects/CGTownInstance.h"
-#include "../../lib/mapObjects/CGMarket.h"
-
-CTradeWindow::CTradeWindow(const ImagePath & bgName, const IMarket *Market, const CGHeroInstance *Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode):
-	CTradeBase(Market, Hero),
-	CWindowObject(PLAYER_COLORED, bgName),
-	onWindowClosed(onWindowClosed),
-	readyToTrade(false)
-{
-	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-
-	mode = Mode;
-	initTypes();
-}
-
-void CTradeWindow::initTypes()
-{
-	switch(mode)
-	{
-	case EMarketMode::RESOURCE_RESOURCE:
-		itemsType[1] = EType::RESOURCE;
-		itemsType[0] = EType::RESOURCE;
-		break;
-	case EMarketMode::RESOURCE_PLAYER:
-		itemsType[1] = EType::RESOURCE;
-		itemsType[0] = EType::PLAYER;
-		break;
-	case EMarketMode::CREATURE_RESOURCE:
-		itemsType[1] = EType::CREATURE;
-		itemsType[0] = EType::RESOURCE;
-		break;
-	case EMarketMode::RESOURCE_ARTIFACT:
-		itemsType[1] = EType::RESOURCE;
-		itemsType[0] = EType::ARTIFACT_TYPE;
-		break;
-	case EMarketMode::ARTIFACT_RESOURCE:
-		itemsType[1] = EType::ARTIFACT_INSTANCE;
-		itemsType[0] = EType::RESOURCE;
-		break;
-	}
-}
-
-void CTradeWindow::initItems(bool Left)
-{
-	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
-
-	if(Left && (itemsType[1] == EType::ARTIFACT_TYPE || itemsType[1] == EType::ARTIFACT_INSTANCE))
-	{
-		if(mode == EMarketMode::ARTIFACT_RESOURCE)
-		{
-			auto item = std::make_shared<CTradeableItem>(Rect(Point(137, 469), Point()), itemsType[Left], -1, 1, 0);
-			item->recActions &= ~(UPDATE | SHOWALL);
-			items[Left].push_back(item);
-		}
-	}
-	else
-	{
-		auto updRightSub = [this](EMarketMode marketMode)
-		{
-			if(hLeft)
-				for(const auto & slot : offerTradePanel->slots)
-				{
-					int h1, h2; //hlp variables for getting offer
-					market->getOffer(hLeft->id, slot->id, h1, h2, marketMode);
-
-					offerTradePanel->updateOffer(*slot, h1, h2);
-				}
-			else
-				offerTradePanel->clearSubtitles();
-		};
-
-		auto clickPressedTradePanel = [this](const std::shared_ptr<CTradeableItem> & newSlot, bool left)
-		{
-			CTradeBase::onSlotClickPressed(newSlot, left ? hLeft : hRight);
-			selectionChanged(left);
-		};
-		if(Left && (mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER))
-		{
-			bidTradePanel = std::make_shared<ResourcesPanel>(
-				[clickPressedTradePanel](const std::shared_ptr<CTradeableItem> & newSlot)
-				{
-					clickPressedTradePanel(newSlot, true);
-				},
-				[this]()
-				{
-					for(const auto & slot : bidTradePanel->slots)
-						slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial)));
-				});
-			bidTradePanel->moveBy(Point(39, 182));
-			bidTradePanel->updateSlots();
-		}
-		else if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE))
-		{
-			offerTradePanel = std::make_shared<ResourcesPanel>(std::bind(clickPressedTradePanel, _1, false),
-				std::bind(updRightSub, EMarketMode::ARTIFACT_RESOURCE));
-			offerTradePanel->moveBy(Point(327, 181));
-		}
-		else if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT)
-		{
-			offerTradePanel = std::make_shared<ArtifactsPanel>(std::bind(clickPressedTradePanel, _1, false),
-				std::bind(updRightSub, EMarketMode::RESOURCE_ARTIFACT), market->availableItemsIds(mode));
-			offerTradePanel->moveBy(Point(327, 181));
-			offerTradePanel->deleteSlotsCheck = [this](const std::shared_ptr<CTradeableItem> & slot)
-			{
-				return vstd::contains(market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT), ArtifactID(slot->id)) ? false : true;
-			};
-		}
-	}
-}
-
-void CTradeWindow::initSubs(bool Left)
-{
-	if (itemsType[Left] == EType::RESOURCE || itemsType[Left] == EType::ARTIFACT_TYPE)
-	{ 
-		if(Left)
-			bidTradePanel->updateSlots();
-		else
-			offerTradePanel->updateSlots();
-		return;
-	}
-}
-
-void CTradeWindow::showAll(Canvas & to)
-{
-	CWindowObject::showAll(to);
-
-	if(readyToTrade)
-	{
-		if(hLeft)
-			hLeft->showAllAt(pos.topLeft() + selectionOffset(true), updateSlotSubtitle(true), to);
-		if(hRight)
-			hRight->showAllAt(pos.topLeft() + selectionOffset(false), updateSlotSubtitle(false), to);
-	}
-}
-
-void CTradeWindow::close()
-{
-	if (onWindowClosed)
-		onWindowClosed();
-
-	CWindowObject::close();
-}
-
-void CTradeWindow::setMode(EMarketMode Mode)
-{
-	const IMarket *m = market;
-	const CGHeroInstance *h = hero;
-	const auto functor = onWindowClosed;
-
-	onWindowClosed = nullptr; // don't call on closing of this window - pass it to next window
-	close();
-}
-
-void CTradeWindow::artifactSelected(CArtPlace * slot)
-{
-	assert(mode == EMarketMode::ARTIFACT_RESOURCE);
-	items[1][0]->setArtInstance(slot->getArt());
-	if(slot->getArt())
-		hLeft = items[1][0];
-	else
-		hLeft = nullptr;
-
-	selectionChanged(true);
-}
-
-ImagePath CMarketplaceWindow::getBackgroundForMode(EMarketMode mode)
-{
-	switch(mode)
-	{
-	case EMarketMode::RESOURCE_PLAYER:
-		return ImagePath::builtin("TPMRKPTS.bmp");
-	case EMarketMode::RESOURCE_ARTIFACT:
-		return ImagePath::builtin("TPMRKABS.bmp");
-	case EMarketMode::ARTIFACT_RESOURCE:
-		return ImagePath::builtin("TPMRKASS.bmp");
-	}
-	assert(0);
-	return {};
-}
-
-CMarketplaceWindow::CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode)
-	: CTradeWindow(getBackgroundForMode(Mode), Market, Hero, onWindowClosed, Mode)
-{
-	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-
-	madeTransaction = false;
-	bool sliderNeeded = (mode != EMarketMode::RESOURCE_ARTIFACT && mode != EMarketMode::ARTIFACT_RESOURCE);
-
-	std::string title;
-
-	if(auto * o = dynamic_cast<const CGTownInstance *>(market))
-	{
-		switch (mode)
-		{
-		case EMarketMode::CREATURE_RESOURCE:
-			title = (*CGI->townh)[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->getNameTranslated();
-			break;
-		case EMarketMode::RESOURCE_ARTIFACT:
-			title = (*CGI->townh)[o->getFaction()]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated();
-			break;
-		case EMarketMode::ARTIFACT_RESOURCE:
-			title = (*CGI->townh)[o->getFaction()]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->getNameTranslated();
-
-			// create image that copies part of background containing slot MISC_1 into position of slot MISC_5
-			// this is workaround for bug in H3 files where this slot for ragdoll on this screen is missing
-			images.push_back(std::make_shared<CPicture>(background->getSurface(), Rect(20, 187, 47, 47), 18, 339 ));
-			break;
-		default:
-			title = CGI->generaltexth->allTexts[158];
-			break;
-		}
-	}
-	else if(auto * o = dynamic_cast<const CGMarket *>(market))
-	{
-		title = o->title;
-	}
-
-	titleLabel = std::make_shared<CLabel>(300, 27, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, title);
-	if(mode == EMarketMode::ARTIFACT_RESOURCE)
-	{
-		//arts = std::make_shared<CArtifactsOfHeroMarket>(Point(-361, 46));
-		arts->selectArtCallback = std::bind(&CTradeWindow::artifactSelected, this, _1);
-		arts->setHero(hero);
-		addSetAndCallbacks(arts);
-	}
-	initItems(false);
-	initItems(true);
-
-	deal = std::make_shared<CButton>(Point(307, 520), AnimationPath::builtin("TPMRKB.DEF"), CGI->generaltexth->zelp[595], [&](){ makeDeal(); } );
-	deal->block(true);
-
-	if(sliderNeeded)
-	{
-		slider = std::make_shared<CSlider>(Point(231, 490), 137, std::bind(&CMarketplaceWindow::sliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
-		max = std::make_shared<CButton>(Point(229, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[596], [&](){ setMax(); });
-		max->block(true);
-	}
-	else
-	{
-		deal->moveBy(Point(-30, 0));
-	}
-
-	//left side
-	switch(Mode)
-	{
-	case EMarketMode::RESOURCE_RESOURCE:
-	case EMarketMode::RESOURCE_PLAYER:
-	case EMarketMode::RESOURCE_ARTIFACT:
-		labels.push_back(std::make_shared<CLabel>(154, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]));
-		break;
-	case EMarketMode::CREATURE_RESOURCE:
-		break;
-	case EMarketMode::ARTIFACT_RESOURCE:
-		//%s's Artifacts
-		labels.push_back(std::make_shared<CLabel>(152, 56, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, boost::str(boost::format(CGI->generaltexth->allTexts[271]) % hero->getNameTranslated())));
-		break;
-	}
-
-	Rect traderTextRect;
-
-	//right side
-	switch(Mode)
-	{
-	case EMarketMode::RESOURCE_RESOURCE:
-	case EMarketMode::CREATURE_RESOURCE:
-	case EMarketMode::RESOURCE_ARTIFACT:
-	case EMarketMode::ARTIFACT_RESOURCE:
-		labels.push_back(std::make_shared<CLabel>(445, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[168]));
-		traderTextRect = Rect(316, 48, 260, 75);
-		break;
-	case EMarketMode::RESOURCE_PLAYER:
-		labels.push_back(std::make_shared<CLabel>(445, 55, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[169]));
-		traderTextRect = Rect(28, 48, 260, 75);
-		break;
-	}
-
-	traderText = std::make_shared<CTextBox>("", traderTextRect, 0, FONT_SMALL, ETextAlignment::CENTER);
-	int specialOffset = mode == EMarketMode::ARTIFACT_RESOURCE ? 35 : 0; //in selling artifacts mode we need to move res-res and art-res buttons down
-
-	updateTraderText();
-}
-
-CMarketplaceWindow::~CMarketplaceWindow() = default;
-
-void CMarketplaceWindow::setMax()
-{
-	slider->scrollToMax();
-}
-
-void CMarketplaceWindow::makeDeal()
-{
-	int sliderValue = 0;
-	if(slider)
-		sliderValue = slider->getValue();
-	else
-		sliderValue = !deal->isBlocked(); //should always be 1
-
-	if(!sliderValue)
-		return;
-
-	bool allowDeal = true;
-	int leftIdToSend = hLeft->id;
-	switch (mode)
-	{
-		case EMarketMode::CREATURE_RESOURCE:
-			leftIdToSend = hLeft->serial;
-			break;
-		case EMarketMode::ARTIFACT_RESOURCE:
-			leftIdToSend = hLeft->getArtInstance()->getId().getNum();
-			break;
-		case EMarketMode::RESOURCE_ARTIFACT:
-			if(!ArtifactID(hRight->id).toArtifact()->canBePutAt(hero))
-			{
-				LOCPLINT->showInfoDialog(CGI->generaltexth->translate("core.genrltxt.326"));
-				allowDeal = false;
-			}
-			break;
-		default:
-			break;
-	}
-
-	if(allowDeal)
-	{
-		switch(mode)
-		{
-		case EMarketMode::RESOURCE_RESOURCE:
-			LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), GameResID(hRight->id), slider->getValue() * r1, hero);
-			slider->scrollTo(0);
-			break;
-		case EMarketMode::CREATURE_RESOURCE:
-			LOCPLINT->cb->trade(market, mode, SlotID(leftIdToSend), GameResID(hRight->id), slider->getValue() * r1, hero);
-			slider->scrollTo(0);
-			break;
-		case EMarketMode::RESOURCE_PLAYER:
-			LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), PlayerColor(hRight->id), slider->getValue() * r1, hero);
-			slider->scrollTo(0);
-			break;
-
-		case EMarketMode::RESOURCE_ARTIFACT:
-			LOCPLINT->cb->trade(market, mode, GameResID(leftIdToSend), ArtifactID(hRight->id), r2, hero);
-			break;
-		case EMarketMode::ARTIFACT_RESOURCE:
-			LOCPLINT->cb->trade(market, mode, ArtifactInstanceID(leftIdToSend), GameResID(hRight->id), r2, hero);
-			break;
-		}
-	}
-
-	madeTransaction = true;
-	hLeft = nullptr;
-	hRight = nullptr;
-	if(bidTradePanel)
-		bidTradePanel->deselect();
-	assert(offerTradePanel);
-	offerTradePanel->deselect();
-	selectionChanged(true);
-}
-
-void CMarketplaceWindow::sliderMoved( int to )
-{
-	redraw();
-}
-
-void CMarketplaceWindow::selectionChanged(bool side)
-{
-	readyToTrade = hLeft && hRight;
-	if(mode == EMarketMode::RESOURCE_RESOURCE)
-		readyToTrade = readyToTrade && (hLeft->id != hRight->id); //for resource trade, two DIFFERENT resources must be selected
-
-	if(mode == EMarketMode::ARTIFACT_RESOURCE && !hLeft)
-		arts->unmarkSlots();
-
-	if(readyToTrade)
-	{
-		int soldItemId = hLeft->id;
-		market->getOffer(soldItemId, hRight->id, r1, r2, mode);
-
-		if(slider)
-		{
-			int newAmount = -1;
-			if(itemsType[1] == EType::RESOURCE)
-				newAmount = LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId));
-			else if(itemsType[1] == EType::CREATURE)
-				newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1  &&  hero->needsLastStack());
-			else
-				assert(0);
-
-			slider->setAmount(newAmount / r1);
-			slider->scrollTo(0);
-			max->block(false);
-			deal->block(false);
-		}
-		else if(itemsType[1] == EType::RESOURCE) //buying -> check if we can afford transaction
-		{
-			deal->block(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId)) < r1);
-		}
-		else
-			deal->block(false);
-	}
-	else
-	{
-		if(slider)
-		{
-			max->block(true);
-			slider->setAmount(0);
-			slider->scrollTo(0);
-		}
-		deal->block(true);
-	}
-
-	if(side && itemsType[0] != EType::PLAYER) //items[1] selection changed, recalculate offers
-		initSubs(false);
-
-	updateTraderText();
-	redraw();
-}
-
-void CMarketplaceWindow::updateGarrison()
-{
-}
-
-void CMarketplaceWindow::artifactsChanged(bool Left)
-{
-}
-
-std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const
-{
-	if(Left)
-	{
-		switch(itemsType[1])
-		{
-		case EType::RESOURCE:
-		case EType::CREATURE:
-			{
-				int val = slider
-					? slider->getValue() * r1
-					: (((deal->isBlocked())) ? 0 : r1);
-
-				return std::to_string(val);
-			}
-		case EType::ARTIFACT_INSTANCE:
-			return ((deal->isBlocked()) ? "0" : "1");
-		}
-	}
-	else
-	{
-		switch(itemsType[0])
-		{
-		case EType::RESOURCE:
-			if(slider)
-				return std::to_string( slider->getValue() * r2 );
-			else
-				return std::to_string(r2);
-		case EType::ARTIFACT_TYPE:
-			return ((deal->isBlocked()) ? "0" : "1");
-		case EType::PLAYER:
-			return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
-		}
-	}
-
-	return "???";
-}
-
-Point CMarketplaceWindow::selectionOffset(bool Left) const
-{
-	if(Left)
-	{
-		switch(itemsType[1])
-		{
-		case EType::RESOURCE:
-			return Point(122, 448);
-		case EType::CREATURE:
-			return Point(128, 450);
-		case EType::ARTIFACT_INSTANCE:
-			return Point(134, 469);
-		}
-	}
-	else
-	{
-		switch(itemsType[0])
-		{
-		case EType::RESOURCE:
-			if(mode == EMarketMode::ARTIFACT_RESOURCE)
-				return Point(410, 471);
-			else
-				return Point(410, 448);
-		case EType::ARTIFACT_TYPE:
-			return Point(411, 449);
-		case EType::PLAYER:
-			return Point(417, 451);
-		}
-	}
-
-	assert(0);
-	return Point(0,0);
-}
-
-void CMarketplaceWindow::updateTraderText()
-{
-	if(readyToTrade)
-	{
-		if(mode == EMarketMode::RESOURCE_PLAYER)
-		{
-			//I can give %s to the %s player.
-			traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[165]) % hLeft->getName() % hRight->getName()));
-		}
-		else if(mode == EMarketMode::RESOURCE_ARTIFACT)
-		{
-			//I can offer you the %s for %d %s of %s.
-			traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[267]) % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
-		}
-		else if(mode == EMarketMode::RESOURCE_RESOURCE)
-		{
-			//I can offer you %d %s of %s for %d %s of %s.
-			traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[157]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
-		}
-		else if(mode == EMarketMode::CREATURE_RESOURCE)
-		{
-			//I can offer you %d %s of %s for %d %s.
-			traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[269]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % hLeft->getName(r1)));
-		}
-		else if(mode == EMarketMode::ARTIFACT_RESOURCE)
-		{
-			//I can offer you %d %s of %s for your %s.
-			traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[268]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % hLeft->getName(r1)));
-		}
-		return;
-	}
-
-	int gnrtxtnr = -1;
-	if(madeTransaction)
-	{
-		if(mode == EMarketMode::RESOURCE_PLAYER)
-			gnrtxtnr = 166; //Are there any other resources you'd like to give away?
-		else
-			gnrtxtnr = 162; //You have received quite a bargain.  I expect to make no profit on the deal.  Can I interest you in any of my other wares?
-	}
-	else
-	{
-		if(mode == EMarketMode::RESOURCE_PLAYER)
-			gnrtxtnr = 167; //If you'd like to give any of your resources to another player, click on the item you wish to give and to whom.
-		else
-			gnrtxtnr = 163; //Please inspect our fine wares.  If you feel like offering a trade, click on the items you wish to trade with and for.
-	}
-	traderText->setText(CGI->generaltexth->allTexts[gnrtxtnr]);
-}

+ 0 - 77
client/windows/CTradeWindow.h

@@ -1,77 +0,0 @@
-/*
- * CTradeWindow.h, part of VCMI engine
- *
- * Authors: listed in file AUTHORS in main folder
- *
- * License: GNU General Public License v2.0 or later
- * Full text of license available in license.txt file, in main folder
- *
- */
-#pragma once
-
-#include "../widgets/markets/CTradeBase.h"
-#include "../widgets/CWindowWithArtifacts.h"
-#include "CWindowObject.h"
-
-class CSlider;
-class CGStatusBar;
-
-class CTradeWindow : public CTradeBase, public CWindowObject, public CWindowWithArtifacts //base for markets and altar of sacrifice
-{
-public:
-	EType itemsType[2];
-
-	EMarketMode mode;
-	std::shared_ptr<CButton> ok;
-	std::shared_ptr<CButton> max;
-
-	std::shared_ptr<CSlider> slider; //for choosing amount to be exchanged
-	bool readyToTrade;
-
-	CTradeWindow(const ImagePath & bgName, const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode); //c
-
-	void showAll(Canvas & to) override;
-	void close() override;
-
-	void initSubs(bool Left);
-	void initTypes();
-	void initItems(bool Left);
-	void setMode(EMarketMode Mode); //mode setter
-
-	void artifactSelected(CArtPlace * slot); //used when selling artifacts -> called when user clicked on artifact slot
-	virtual void selectionChanged(bool side) = 0; //true == left
-	virtual Point selectionOffset(bool Left) const = 0;
-	virtual std::string updateSlotSubtitle(bool Left) const = 0;
-	virtual void updateGarrison() = 0;
-	virtual void artifactsChanged(bool left) = 0;
-protected:
-	std::function<void()> onWindowClosed;
-	std::shared_ptr<CGStatusBar> statusBar;
-	std::vector<std::shared_ptr<CPicture>> images;
-};
-
-class CMarketplaceWindow : public CTradeWindow
-{
-	std::shared_ptr<CLabel> titleLabel;
-	std::shared_ptr<CArtifactsOfHeroMarket> arts;
-
-	ImagePath getBackgroundForMode(EMarketMode mode);
-public:
-	int r1, r2; //suggested amounts of traded resources
-	bool madeTransaction; //if player made at least one transaction
-	std::shared_ptr<CTextBox> traderText;
-
-	void setMax();
-	void sliderMoved(int to);
-	void makeDeal() override;
-	void selectionChanged(bool side) override; //true == left
-	CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function<void()> & onWindowClosed, EMarketMode Mode);
-	~CMarketplaceWindow();
-
-	Point selectionOffset(bool Left) const override;
-	std::string updateSlotSubtitle(bool Left) const override;
-
-	void updateGarrison() override; //removes creatures with count 0 from the list (apparently whole stack has been sold)
-	void artifactsChanged(bool left) override;
-	void updateTraderText();
-};