/* * GUIClasses.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 "../lib/ResourceSet.h" #include "../widgets/CExchangeController.h" #include "../widgets/CWindowWithArtifacts.h" #include "../widgets/Images.h" VCMI_LIB_NAMESPACE_BEGIN class CGObjectInstance; class CGDwelling; class IMarket; VCMI_LIB_NAMESPACE_END class CreatureCostBox; class CCreaturePic; class MoraleLuckBox; class CHeroArea; class CSlider; class CComponentBox; class CTextInput; class CListBox; class CLabelGroup; class CGStatusBar; class CTextBox; class CGarrisonInt; class CGarrisonSlot; class CHeroArea; class CAnimImage; class CFilledTexture; class IImage; enum class EUserEvent; /// Recruitment window where you can recruit creatures class CRecruitmentWindow : public CStatusbarWindow { class CCreatureCard : public CIntObject, public std::enable_shared_from_this { CRecruitmentWindow * parent; std::shared_ptr animation; bool selected; public: const CCreature * creature; si32 amount; void select(bool on); CCreatureCard(CRecruitmentWindow * window, const CCreature * crea, int totalAmount); void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; void showAll(Canvas & to) override; }; std::function onRecruit; //void (int ID, int amount) <-- call to recruit creatures std::function onClose; int level; const CArmedInstance * dst; std::shared_ptr selected; std::vector> cards; std::shared_ptr slider; std::shared_ptr maxButton; std::shared_ptr buyButton; std::shared_ptr cancelButton; std::shared_ptr title; std::shared_ptr availableValue; std::shared_ptr toRecruitValue; std::shared_ptr availableTitle; std::shared_ptr toRecruitTitle; std::shared_ptr costPerTroopValue; std::shared_ptr totalCostValue; void select(std::shared_ptr card); void buy(); void sliderMoved(int to); void showAll(Canvas & to) override; public: const CGDwelling * const dwelling; CRecruitmentWindow(const CGDwelling * Dwelling, int Level, const CArmedInstance * Dst, const std::function & Recruit, const std::function & onClose, int y_offset = 0); void availableCreaturesChanged(); void close() override; }; /// Split window where creatures can be split up into two single unit stacks class CSplitWindow : public CWindowObject { std::function callback; int leftAmount; int rightAmount; int leftMin; int rightMin; std::shared_ptr title; std::shared_ptr slider; std::shared_ptr animLeft; std::shared_ptr animRight; std::shared_ptr ok; std::shared_ptr cancel; std::shared_ptr leftInput; std::shared_ptr rightInput; void setAmountText(std::string text, bool left); void setAmount(int value, bool left); void sliderMoved(int value); void apply(); public: /** * creature - displayed creature * callback(leftAmount, rightAmount) - function to call on close * leftMin, rightMin - minimal amount of creatures in each stack * leftAmount, rightAmount - amount of creatures in each stack */ CSplitWindow(const CCreature * creature, std::function callback, int leftMin, int rightMin, int leftAmount, int rightAmount); }; /// Raised up level window where you can select one out of two skills class CLevelWindow : public CWindowObject { std::shared_ptr portrait; std::shared_ptr ok; std::shared_ptr mainTitle; std::shared_ptr levelTitle; std::shared_ptr skillIcon; std::shared_ptr skillValue; std::shared_ptr box; //skills to select std::function cb; void selectionChanged(unsigned to); public: CLevelWindow(const CGHeroInstance *hero, PrimarySkill pskill, std::vector &skills, std::function callback); ~CLevelWindow(); }; /// Town portal, castle gate window class CObjectListWindow : public CWindowObject { class CItem : public CIntObject { CObjectListWindow * parent; std::shared_ptr text; std::shared_ptr border; std::shared_ptr icon; public: const size_t index; CItem(CObjectListWindow * parent, size_t id, std::string text); void select(bool on); void clickPressed(const Point & cursorPosition) override; void clickDouble(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; }; std::function onSelect;//called when OK button is pressed, returns id of selected item. std::shared_ptr titleWidget; std::shared_ptr title; std::shared_ptr descr; std::vector> images; std::shared_ptr list; std::shared_ptr ok; std::shared_ptr exit; std::vector< std::pair > items;//all items present in list void init(std::shared_ptr titleWidget_, std::string _title, std::string _descr); void exitPressed(); public: size_t selected;//index of currently selected item std::function onExit;//optional exit callback std::function onPopup;//optional popup callback std::function onClicked;//optional if clicked on item callback /// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item /// Image can be nullptr ///item names will be taken from map objects CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}); CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}); std::shared_ptr genItem(size_t index); void elementSelected();//call callback and close this window void changeSelection(size_t which); void keyPressed(EShortcut key) override; }; class CTavernWindow : public CStatusbarWindow { std::function onWindowClosed; public: class HeroPortrait : public CIntObject { public: std::string hoverName; std::string description; // "XXX is a level Y ZZZ with N artifacts" const CGHeroInstance * h; std::function onChoose; void clickPressed(const Point & cursorPosition) override; void clickDouble(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; void hover (bool on) override; HeroPortrait(int & sel, int id, int x, int y, const CGHeroInstance * H, std::function OnChoose = nullptr); private: int *_sel; const int _id; std::shared_ptr portrait; }; class HeroSelector : public CWindowObject { public: std::shared_ptr background; HeroSelector(std::map InviteableHeroes, std::function OnChoose); private: std::map inviteableHeroes; std::function onChoose; std::vector> portraits; std::vector> portraitAreas; }; //recruitable heroes std::shared_ptr h1; std::shared_ptr h2; //recruitable heroes int selected;//0 (left) or 1 (right) int oldSelected;//0 (left) or 1 (right) std::shared_ptr thiefGuild; std::shared_ptr cancel; std::shared_ptr recruit; const CGObjectInstance * tavernObj; std::shared_ptr title; std::shared_ptr cost; std::shared_ptr heroesForHire; std::shared_ptr heroDescription; std::shared_ptr rumor; std::shared_ptr inviteHero; std::shared_ptr inviteHeroImage; std::shared_ptr inviteHeroImageArea; std::map inviteableHeroes; CGHeroInstance* heroToInvite; void addInvite(); CTavernWindow(const CGObjectInstance * TavernObj, const std::function & onWindowClosed); ~CTavernWindow(); void close() override; void recruitb(); void thievesguildb(); void show(Canvas & to) override; }; class CExchangeWindow : public CStatusbarWindow, public IGarrisonHolder, public CWindowWithArtifacts { std::array, 2> titles; std::vector> primSkillImages;//shared for both heroes std::array>, 2> primSkillValues; std::array>, 2> secSkillIcons; std::array, 2> specImages; std::array, 2> expImages; std::array, 2> expValues; std::array, 2> manaImages; std::array, 2> manaValues; std::vector> primSkillAreas; std::array>, 2> secSkillAreas; std::array, 2> heroAreas; std::array, 2> specialtyAreas; std::array, 2> experienceAreas; std::array, 2> spellPointsAreas; std::array, 2> morale; std::array, 2> luck; std::shared_ptr quit; std::array, 2> questlogButton; std::shared_ptr garr; std::shared_ptr moveAllGarrButtonLeft; std::shared_ptr exchangeGarrButton; std::shared_ptr moveAllGarrButtonRight; std::shared_ptr moveArtifactsButtonLeft; std::shared_ptr exchangeArtifactsButton; std::shared_ptr moveArtifactsButtonRight; std::vector> moveStackLeftButtons; std::vector> moveStackRightButtons; std::shared_ptr backpackButtonLeft; std::shared_ptr backpackButtonRight; CExchangeController controller; public: std::array heroInst; std::array, 2> artifs; void updateGarrisons() override; bool holdsGarrison(const CArmedInstance * army) override; void questlog(int whichHero); //questlog button callback; whichHero: 0 - left, 1 - right void updateWidgets(); const CGarrisonSlot * getSelectedSlotID() const; CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID); }; /// Here you can buy ships class CShipyardWindow : public CStatusbarWindow { std::shared_ptr bgWater; std::shared_ptr bgShip; std::shared_ptr title; std::shared_ptr costLabel; std::shared_ptr woodPic; std::shared_ptr goldPic; std::shared_ptr woodCost; std::shared_ptr goldCost; std::shared_ptr build; std::shared_ptr quit; public: CShipyardWindow(const TResources & cost, int state, BoatId boatType, const std::function & onBuy); }; /// Creature transformer window class CTransformerWindow : public CStatusbarWindow, public IGarrisonHolder { class CItem : public CIntObject { public: int id;//position of creature in hero army bool left;//position of the item int size; //size of creature stack CTransformerWindow * parent; std::shared_ptr icon; std::shared_ptr count; void move(); void clickPressed(const Point & cursorPosition) override; void update(); CItem(CTransformerWindow * parent, int size, int id); }; const CArmedInstance * army;//object with army for transforming (hero or town) const CGHeroInstance * hero;//only if we have hero in town const IMarket * market;//market, town garrison is used if hero == nullptr std::shared_ptr titleLeft; std::shared_ptr titleRight; std::shared_ptr helpLeft; std::shared_ptr helpRight; std::vector> items; std::shared_ptr all; std::shared_ptr convert; std::shared_ptr cancel; std::function onWindowClosed; public: void makeDeal(); void addAll(); void close() override; void updateGarrisons() override; bool holdsGarrison(const CArmedInstance * army) override; CTransformerWindow(const IMarket * _market, const CGHeroInstance * _hero, const std::function & onWindowClosed); }; class CUniversityWindow : public CStatusbarWindow { class CItem : public CIntObject { std::shared_ptr icon; std::shared_ptr topBar; std::shared_ptr bottomBar; std::shared_ptr name; std::shared_ptr level; public: SecondarySkill ID;//id of selected skill CUniversityWindow * parent; void showAll(Canvas & to) override; void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; void hover(bool on) override; int state();//0=can't learn, 1=learned, 2=can learn CItem(CUniversityWindow * _parent, int _ID, int X, int Y); }; const CGHeroInstance * hero; const IMarket * market; std::shared_ptr bars; std::vector> items; std::shared_ptr cancel; std::shared_ptr titlePic; std::shared_ptr title; std::shared_ptr clerkSpeech; std::function onWindowClosed; public: CUniversityWindow(const CGHeroInstance * _hero, const IMarket * _market, const std::function & onWindowClosed); void makeDeal(SecondarySkill skill); void close(); }; /// Confirmation window for University class CUnivConfirmWindow : public CStatusbarWindow { std::shared_ptr clerkSpeech; std::shared_ptr name; std::shared_ptr level; std::shared_ptr icon; CUniversityWindow * owner; std::shared_ptr confirm; std::shared_ptr cancel; std::shared_ptr costIcon; std::shared_ptr cost; void makeDeal(SecondarySkill skill); public: CUnivConfirmWindow(CUniversityWindow * PARENT, SecondarySkill SKILL, bool available); }; /// Garrison window where you can take creatures out of the hero to place it on the garrison class CGarrisonWindow : public CWindowObject, public IGarrisonHolder { std::shared_ptr title; std::shared_ptr banner; std::shared_ptr portrait; std::shared_ptr garr; public: std::shared_ptr quit; CGarrisonWindow(const CArmedInstance * up, const CGHeroInstance * down, bool removableUnits); void updateGarrisons() override; bool holdsGarrison(const CArmedInstance * army) override; }; /// Hill fort is the building where you can upgrade units class CHillFortWindow : public CStatusbarWindow, public IGarrisonHolder { private: static const int slotsCount = 7; //todo: mithril support static const int resCount = 7; const CGObjectInstance * fort; const CGHeroInstance * hero; std::shared_ptr title; std::shared_ptr heroPic; std::array, resCount> totalIcons; std::array, resCount> totalLabels; std::array, slotsCount> upgrade;//upgrade single creature std::array currState;//current state of slot - to avoid calls to getState or updating buttons //there is a place for only 2 resources per slot std::array< std::array, 2>, slotsCount> slotIcons; std::array< std::array, 2>, slotsCount> slotLabels; std::shared_ptr upgradeAll; std::shared_ptr quit; std::shared_ptr garr; std::string getDefForSlot(SlotID slot); std::string getTextForSlot(SlotID slot); void makeDeal(SlotID slot);//-1 for upgrading all creatures int getState(SlotID slot); //-1 = no creature 0=can't upgrade, 1=upgraded, 2=can upgrade public: CHillFortWindow(const CGHeroInstance * visitor, const CGObjectInstance * object); void updateGarrisons() override;//update buttons after garrison changes bool holdsGarrison(const CArmedInstance * army) override; }; class CThievesGuildWindow : public CStatusbarWindow { const CGObjectInstance * owner; std::shared_ptr exitb; std::shared_ptr resdatabar; std::vector> rowHeaders; std::vector> columnBackgrounds; std::vector> columnHeaders; std::vector> cells; std::vector> banners; std::vector> bestHeroes; std::vector> primSkillHeaders; std::vector> primSkillValues; std::vector> bestCreatures; std::vector> personalities; public: CThievesGuildWindow(const CGObjectInstance * _owner); };