TradePanels.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * TradePanels.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "TradePanels.h"
  12. #include "../../gui/CGuiHandler.h"
  13. #include "../../render/Canvas.h"
  14. #include "../../widgets/TextControls.h"
  15. #include "../../windows/InfoWindows.h"
  16. #include "../../CGameInfo.h"
  17. #include "../../CPlayerInterface.h"
  18. #include "../../../CCallback.h"
  19. #include "../../../lib/texts/CGeneralTextHandler.h"
  20. #include "../../../lib/mapObjects/CGHeroInstance.h"
  21. CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, int Serial)
  22. : SelectableSlot(area, Point(1, 1))
  23. , type(EType(-1)) // set to invalid, will be corrected in setType
  24. , id(ID)
  25. , serial(Serial)
  26. {
  27. OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
  28. addUsedEvents(LCLICK);
  29. addUsedEvents(HOVER);
  30. addUsedEvents(SHOW_POPUP);
  31. subtitle = std::make_shared<CLabel>(0, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
  32. setType(Type);
  33. this->pos.w = area.w;
  34. this->pos.h = area.h;
  35. }
  36. void CTradeableItem::setType(EType newType)
  37. {
  38. if(type != newType)
  39. {
  40. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  41. type = newType;
  42. if(getIndex() < 0)
  43. {
  44. image = std::make_shared<CAnimImage>(getFilename(), 0);
  45. image->disable();
  46. }
  47. else
  48. {
  49. image = std::make_shared<CAnimImage>(getFilename(), getIndex());
  50. }
  51. switch(type)
  52. {
  53. case EType::RESOURCE:
  54. subtitle->moveTo(pos.topLeft() + Point(35, 55));
  55. image->moveTo(pos.topLeft() + Point(19, 8));
  56. break;
  57. case EType::CREATURE_PLACEHOLDER:
  58. case EType::CREATURE:
  59. subtitle->moveTo(pos.topLeft() + Point(30, 77));
  60. break;
  61. case EType::PLAYER:
  62. subtitle->moveTo(pos.topLeft() + Point(31, 76));
  63. break;
  64. case EType::ARTIFACT_PLACEHOLDER:
  65. case EType::ARTIFACT_INSTANCE:
  66. image->moveTo(pos.topLeft() + Point(0, 1));
  67. subtitle->moveTo(pos.topLeft() + Point(21, 56));
  68. break;
  69. case EType::ARTIFACT_TYPE:
  70. subtitle->moveTo(pos.topLeft() + Point(35, 57));
  71. image->moveTo(pos.topLeft() + Point(13, 0));
  72. break;
  73. }
  74. }
  75. }
  76. void CTradeableItem::setID(int newID)
  77. {
  78. if(id != newID)
  79. {
  80. id = newID;
  81. if(image)
  82. {
  83. int index = getIndex();
  84. if(index < 0)
  85. image->disable();
  86. else
  87. {
  88. image->enable();
  89. image->setFrame(index);
  90. }
  91. }
  92. }
  93. }
  94. void CTradeableItem::clear()
  95. {
  96. setID(-1);
  97. image->setFrame(0);
  98. image->disable();
  99. subtitle->clear();
  100. }
  101. AnimationPath CTradeableItem::getFilename()
  102. {
  103. switch(type)
  104. {
  105. case EType::RESOURCE:
  106. return AnimationPath::builtin("RESOURCE");
  107. case EType::PLAYER:
  108. return AnimationPath::builtin("CREST58");
  109. case EType::ARTIFACT_TYPE:
  110. case EType::ARTIFACT_PLACEHOLDER:
  111. case EType::ARTIFACT_INSTANCE:
  112. return AnimationPath::builtin("artifact");
  113. case EType::CREATURE:
  114. return AnimationPath::builtin("TWCRPORT");
  115. default:
  116. return {};
  117. }
  118. }
  119. int CTradeableItem::getIndex()
  120. {
  121. if(id < 0)
  122. return -1;
  123. switch(type)
  124. {
  125. case EType::RESOURCE:
  126. case EType::PLAYER:
  127. return id;
  128. case EType::ARTIFACT_TYPE:
  129. case EType::ARTIFACT_INSTANCE:
  130. case EType::ARTIFACT_PLACEHOLDER:
  131. return CGI->artifacts()->getByIndex(id)->getIconIndex();
  132. case EType::CREATURE:
  133. return CGI->creatures()->getByIndex(id)->getIconIndex();
  134. default:
  135. return -1;
  136. }
  137. }
  138. void CTradeableItem::clickPressed(const Point & cursorPosition)
  139. {
  140. if(clickPressedCallback)
  141. clickPressedCallback(shared_from_this());
  142. }
  143. void CTradeableItem::hover(bool on)
  144. {
  145. if(!on || id == -1)
  146. {
  147. GH.statusbar()->clear();
  148. return;
  149. }
  150. switch(type)
  151. {
  152. case EType::CREATURE:
  153. case EType::CREATURE_PLACEHOLDER:
  154. GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated()));
  155. break;
  156. case EType::ARTIFACT_TYPE:
  157. case EType::ARTIFACT_PLACEHOLDER:
  158. if(id < 0)
  159. GH.statusbar()->write(CGI->generaltexth->zelp[582].first);
  160. else
  161. GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated());
  162. break;
  163. case EType::RESOURCE:
  164. GH.statusbar()->write(CGI->generaltexth->restypes[id]);
  165. break;
  166. case EType::PLAYER:
  167. GH.statusbar()->write(CGI->generaltexth->capColors[id]);
  168. break;
  169. }
  170. }
  171. void CTradeableItem::showPopupWindow(const Point & cursorPosition)
  172. {
  173. switch(type)
  174. {
  175. case EType::CREATURE:
  176. case EType::CREATURE_PLACEHOLDER:
  177. break;
  178. case EType::ARTIFACT_TYPE:
  179. case EType::ARTIFACT_PLACEHOLDER:
  180. //TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription.
  181. if (id >= 0)
  182. CRClickPopup::createAndPush(CGI->artifacts()->getByIndex(id)->getDescriptionTranslated());
  183. break;
  184. }
  185. }
  186. void TradePanelBase::update()
  187. {
  188. if(deleteSlotsCheck)
  189. slots.erase(std::remove_if(slots.begin(), slots.end(), deleteSlotsCheck), slots.end());
  190. if(updateSlotsCallback)
  191. updateSlotsCallback();
  192. }
  193. void TradePanelBase::deselect()
  194. {
  195. for(const auto & slot : slots)
  196. slot->selectSlot(false);
  197. }
  198. void TradePanelBase::clearSubtitles()
  199. {
  200. for(const auto & slot : slots)
  201. slot->subtitle->clear();
  202. }
  203. void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty)
  204. {
  205. std::string subtitle = std::to_string(qty);
  206. if(cost != 1)
  207. {
  208. subtitle.append("/");
  209. subtitle.append(std::to_string(cost));
  210. }
  211. slot.subtitle->setText(subtitle);
  212. }
  213. void TradePanelBase::setShowcaseSubtitle(const std::string & text)
  214. {
  215. showcaseSlot->subtitle->setText(text);
  216. }
  217. int TradePanelBase::getSelectedItemId() const
  218. {
  219. if(highlightedSlot)
  220. return highlightedSlot->id;
  221. else
  222. return -1;
  223. }
  224. void TradePanelBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot)
  225. {
  226. assert(vstd::contains(slots, newSlot));
  227. if(newSlot == highlightedSlot)
  228. return;
  229. if(highlightedSlot)
  230. highlightedSlot->selectSlot(false);
  231. highlightedSlot = newSlot;
  232. newSlot->selectSlot(true);
  233. }
  234. bool TradePanelBase::isHighlighted() const
  235. {
  236. return getSelectedItemId() != -1;
  237. }
  238. ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  239. const UpdateSlotsFunctor & updateSubtitles)
  240. {
  241. assert(resourcesForTrade.size() == slotsPos.size());
  242. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  243. for(const auto & res : resourcesForTrade)
  244. {
  245. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[res.num], slotDimension), EType::RESOURCE, res.num, res.num));
  246. slot->clickPressedCallback = clickPressedCallback;
  247. slot->setSelectionWidth(selectionWidth);
  248. }
  249. updateSlotsCallback = updateSubtitles;
  250. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0);
  251. }
  252. ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  253. const UpdateSlotsFunctor & updateSubtitles, const std::vector<TradeItemBuy> & arts)
  254. {
  255. assert(slotsForTrade == slotsPos.size());
  256. assert(slotsForTrade == arts.size());
  257. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  258. for(auto slotIdx = 0; slotIdx < slotsForTrade; slotIdx++)
  259. {
  260. auto artType = arts[slotIdx].getNum();
  261. if(artType != ArtifactID::NONE)
  262. {
  263. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotIdx], slotDimension),
  264. EType::ARTIFACT_TYPE, artType, slotIdx));
  265. slot->clickPressedCallback = clickPressedCallback;
  266. slot->setSelectionWidth(selectionWidth);
  267. }
  268. }
  269. updateSlotsCallback = updateSubtitles;
  270. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
  271. showcaseSlot->subtitle->moveBy(Point(0, 1));
  272. }
  273. PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
  274. {
  275. assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size() + 1);
  276. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  277. std::vector<PlayerColor> players;
  278. for(auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT_I; player++)
  279. {
  280. if(player != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(player) == EPlayerStatus::INGAME)
  281. players.emplace_back(player);
  282. }
  283. slots.resize(players.size());
  284. int slotNum = 0;
  285. for(auto & slot : slots)
  286. {
  287. slot = std::make_shared<CTradeableItem>(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, slotNum);
  288. slot->clickPressedCallback = clickPressedCallback;
  289. slot->setSelectionWidth(selectionWidth);
  290. slot->subtitle->setText(CGI->generaltexth->capColors[players[slotNum].num]);
  291. slotNum++;
  292. }
  293. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::PLAYER, 0, 0);
  294. }
  295. CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const slotsData & initialSlots)
  296. {
  297. assert(initialSlots.size() <= GameConstants::ARMY_SIZE);
  298. assert(slotsPos.size() <= GameConstants::ARMY_SIZE);
  299. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  300. for(const auto & [creatureId, slotId, creaturesNum] : initialSlots)
  301. {
  302. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotId.num], slotDimension),
  303. creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, slotId));
  304. slot->clickPressedCallback = clickPressedCallback;
  305. if(creaturesNum != 0)
  306. slot->subtitle->setText(std::to_string(creaturesNum));
  307. slot->setSelectionWidth(selectionWidth);
  308. }
  309. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
  310. }
  311. CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  312. const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots)
  313. {
  314. assert(slots.size() <= GameConstants::ARMY_SIZE);
  315. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  316. for(const auto & srcSlot : srcSlots)
  317. {
  318. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[srcSlot->serial], srcSlot->pos.dimensions()),
  319. emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, srcSlot->serial));
  320. slot->clickPressedCallback = clickPressedCallback;
  321. slot->subtitle->setText(emptySlots ? "" : srcSlot->subtitle->getText());
  322. slot->setSelectionWidth(selectionWidth);
  323. }
  324. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
  325. }
  326. ArtifactsAltarPanel::ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
  327. {
  328. OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
  329. int slotNum = 0;
  330. for(auto & altarSlotPos : slotsPos)
  331. {
  332. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, slotNum));
  333. slot->clickPressedCallback = clickPressedCallback;
  334. slot->subtitle->clear();
  335. slot->subtitle->moveBy(Point(0, -1));
  336. slotNum++;
  337. }
  338. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
  339. showcaseSlot->subtitle->moveBy(Point(0, 3));
  340. }