| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 | /* * InfoWindows.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 "InfoWindows.h"#include "../CGameInfo.h"#include "../CPlayerInterface.h"#include "../PlayerLocalState.h"#include "../adventureMap/AdventureMapInterface.h"#include "../gui/CGuiHandler.h"#include "../gui/CursorHandler.h"#include "../gui/Shortcut.h"#include "../gui/WindowHandler.h"#include "../widgets/Buttons.h"#include "../widgets/CComponent.h"#include "../widgets/Images.h"#include "../widgets/MiscWidgets.h"#include "../widgets/TextControls.h"#include "../windows/CMessage.h"#include "../../CCallback.h"#include "../../lib/CConfigHandler.h"#include "../ConditionalWait.h"#include "../../lib/gameState/InfoAboutArmy.h"#include "../../lib/mapObjects/CGCreature.h"#include "../../lib/mapObjects/CGHeroInstance.h"#include "../../lib/mapObjects/CGTownInstance.h"#include "../../lib/mapObjects/MiscObjects.h"CSelWindow::CSelWindow( const std::string & Text, PlayerColor player, int charperline, const std::vector<std::shared_ptr<CSelectableComponent>> & comps, const std::vector<std::pair<AnimationPath, CFunctionList<void()>>> & Buttons, QueryID askID){	OBJECT_CONSTRUCTION;	backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DiBoxBck"), pos);	ID = askID;	for(int i = 0; i < Buttons.size(); i++)	{		buttons.push_back(std::make_shared<CButton>(Point(0, 0), Buttons[i].first, CButton::tooltip(), Buttons[i].second));		if(!i && askID.getNum() >= 0)			buttons.back()->addCallback(std::bind(&CSelWindow::madeChoice, this));		buttons[i]->addCallback(std::bind(&CInfoWindow::close, this)); //each button will close the window apart from call-defined actions	}	text = std::make_shared<CTextBox>(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE);	if(buttons.size() > 1 && askID.getNum() >= 0) //cancel button functionality		buttons.back()->addCallback([askID](){LOCPLINT->cb->selectionMade(0, askID);});	if(buttons.size() == 1)		buttons.front()->assignedKey = EShortcut::GLOBAL_RETURN;	if(buttons.size() == 2)	{		buttons.front()->assignedKey = EShortcut::GLOBAL_ACCEPT;		buttons.back()->assignedKey = EShortcut::GLOBAL_CANCEL;	}	if(!comps.empty())	{		components = std::make_shared<CComponentBox>(comps, Rect(0,0,0,0));		for (auto & comp : comps)			comp->onChoose = [this](){ madeChoiceAndClose(); };	}	CMessage::drawIWindow(this, Text, player);}void CSelWindow::madeChoice(){	if(ID.getNum() < 0)		return;	int ret = -1;	if(components)		ret = components->selectedIndex();	LOCPLINT->cb->selectionMade(ret + 1, ID);}void CSelWindow::madeChoiceAndClose(){	madeChoice();	close();}CInfoWindow::CInfoWindow(const std::string & Text, PlayerColor player, const TCompsInfo & comps, const TButtonsInfo & Buttons){	OBJECT_CONSTRUCTION;	backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DiBoxBck"), pos);	ID = QueryID(-1);	for(const auto & Button : Buttons)	{		auto button = std::make_shared<CButton>(Point(0, 0), Button.first, CButton::tooltip(), std::bind(&CInfoWindow::close, this));		button->setBorderColor(Colors::METALLIC_GOLD);		button->addCallback(Button.second); //each button will close the window apart from call-defined actions		buttons.push_back(button);	}	text = std::make_shared<CTextBox>(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, ETextAlignment::CENTER, Colors::WHITE);	if(!text->slider)	{		int finalWidth = std::min(250, text->label->textSize.x + 32);		int finalHeight = text->label->textSize.y;		text->resize(Point(finalWidth, finalHeight));	}	if(buttons.size() == 1)		buttons.front()->assignedKey = EShortcut::GLOBAL_RETURN;	if(buttons.size() == 2)	{		buttons.front()->assignedKey = EShortcut::GLOBAL_ACCEPT;		buttons.back()->assignedKey = EShortcut::GLOBAL_CANCEL;	}	if(!comps.empty())		components = std::make_shared<CComponentBox>(comps, Rect(0,0,0,0));	CMessage::drawIWindow(this, Text, player);}CInfoWindow::CInfoWindow(){	ID = QueryID(-1);}void CInfoWindow::close(){	WindowBase::close();	if(LOCPLINT)		LOCPLINT->showingDialog->setFree();}void CInfoWindow::showAll(Canvas & to){	CIntObject::showAll(to);	CMessage::drawBorder(LOCPLINT ? LOCPLINT->playerID : PlayerColor(1), to, pos.w+28, pos.h+29, pos.x-14, pos.y-15);}CInfoWindow::~CInfoWindow() = default;void CInfoWindow::showInfoDialog(const std::string & text, const TCompsInfo & components, PlayerColor player){	GH.windows().pushWindow(CInfoWindow::create(text, player, components));}void CInfoWindow::showYesNoDialog(const std::string & text, const TCompsInfo & components, const CFunctionList<void()> & onYes, const CFunctionList<void()> & onNo, PlayerColor player){	assert(!LOCPLINT || LOCPLINT->showingDialog->isBusy());	std::vector<std::pair<AnimationPath, CFunctionList<void()>>> pom;	pom.emplace_back(AnimationPath::builtin("IOKAY.DEF"), nullptr);	pom.emplace_back(AnimationPath::builtin("ICANCEL.DEF"), nullptr);	auto temp = std::make_shared<CInfoWindow>(text, player, components, pom);	temp->buttons[0]->addCallback(onYes);	temp->buttons[1]->addCallback(onNo);	GH.windows().pushWindow(temp);}std::shared_ptr<CInfoWindow> CInfoWindow::create(const std::string & text, PlayerColor playerID, const TCompsInfo & components){	std::vector<std::pair<AnimationPath, CFunctionList<void()>>> pom;	pom.emplace_back(AnimationPath::builtin("IOKAY.DEF"), nullptr);	return std::make_shared<CInfoWindow>(text, playerID, components, pom);}std::string CInfoWindow::genText(const std::string & title, const std::string & description){	return std::string("{") + title + "}" + "\n\n" + description;}bool CRClickPopup::isPopupWindow() const{	return true;}void CRClickPopup::createAndPush(const std::string & txt, const CInfoWindow::TCompsInfo & comps){	PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue	if(settings["session"]["spectate"].Bool()) //TODO: there must be better way to implement this		player = PlayerColor(1);	auto temp = std::make_shared<CInfoWindow>(txt, player, comps);	temp->center(GH.getCursorPosition()); //center on mouse#ifdef VCMI_MOBILE	temp->moveBy({0, -temp->pos.h / 2});#endif	temp->fitToScreen(10);	GH.windows().createAndPushWindow<CRClickPopupInt>(temp);}void CRClickPopup::createAndPush(const std::string & txt, const std::shared_ptr<CComponent> & component){	CInfoWindow::TCompsInfo intComps;	intComps.push_back(component);	createAndPush(txt, intComps);}void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p, ETextAlignment alignment){	auto iWin = createCustomInfoWindow(p, obj); //try get custom infowindow for this obj	if(iWin)	{		GH.windows().pushWindow(iWin);	}	else	{		std::vector<Component> components;		if(settings["general"]["enableUiEnhancements"].Bool())		{			if(LOCPLINT->localState->getCurrentHero())				components = obj->getPopupComponents(LOCPLINT->localState->getCurrentHero());			else				components = obj->getPopupComponents(LOCPLINT->playerID);		}		std::vector<std::shared_ptr<CComponent>> guiComponents;		for(auto & component : components)			guiComponents.push_back(std::make_shared<CComponent>(component));		if(LOCPLINT->localState->getCurrentHero())			CRClickPopup::createAndPush(obj->getPopupText(LOCPLINT->localState->getCurrentHero()), guiComponents);		else			CRClickPopup::createAndPush(obj->getPopupText(LOCPLINT->playerID), guiComponents);	}}CRClickPopupInt::CRClickPopupInt(const std::shared_ptr<CIntObject> & our) :	dragDistance(Point(0, 0)){	addUsedEvents(DRAG_POPUP);	CCS->curh->hide();	inner = our;	addChild(our.get(), false);}CRClickPopupInt::~CRClickPopupInt(){	CCS->curh->show();}void CRClickPopupInt::mouseDraggedPopup(const Point & cursorPosition, const Point & lastUpdateDistance){	if(!settings["adventure"]["rightButtonDrag"].Bool())		return;		dragDistance += lastUpdateDistance;		if(dragDistance.length() > 16)		close();}Point CInfoBoxPopup::toScreen(Point p){	auto bounds = adventureInt->terrainAreaPixels();	vstd::abetween(p.x, bounds.top() + 100, bounds.bottom() - 100);	vstd::abetween(p.y, bounds.left() + 100, bounds.right() - 100);	return p;}void CInfoBoxPopup::mouseDraggedPopup(const Point & cursorPosition, const Point & lastUpdateDistance){	if(!settings["adventure"]["rightButtonDrag"].Bool())		return;		dragDistance += lastUpdateDistance;		if(dragDistance.length() > 16)		close();}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("TOWNQVBK"), toScreen(position)){	InfoAboutTown iah;	LOCPLINT->cb->getTownInfo(town, iah, LOCPLINT->localState->getCurrentArmy()); //todo: should this be nearest hero?	OBJECT_CONSTRUCTION;	tooltip = std::make_shared<CTownTooltip>(Point(9, 10), iah);	addUsedEvents(DRAG_POPUP);}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("HEROQVBK"), toScreen(position)){	InfoAboutHero iah;	LOCPLINT->cb->getHeroInfo(hero, iah, LOCPLINT->localState->getCurrentArmy()); //todo: should this be nearest hero?	OBJECT_CONSTRUCTION;	tooltip = std::make_shared<CHeroTooltip>(Point(9, 10), iah);		addUsedEvents(DRAG_POPUP);}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, ImagePath::builtin("TOWNQVBK"), toScreen(position)){	InfoAboutTown iah;	LOCPLINT->cb->getTownInfo(garr, iah);	OBJECT_CONSTRUCTION;	tooltip = std::make_shared<CArmyTooltip>(Point(9, 10), iah);		addUsedEvents(DRAG_POPUP);}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGCreature * creature)	: CWindowObject(RCLICK_POPUP | BORDERED, ImagePath::builtin("DIBOXBCK"), toScreen(position)){	OBJECT_CONSTRUCTION;	tooltip = std::make_shared<CreatureTooltip>(Point(9, 10), creature);		addUsedEvents(DRAG_POPUP);}std::shared_ptr<WindowBase>CRClickPopup::createCustomInfoWindow(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero{	if(nullptr == specific)		specific = LOCPLINT->localState->getCurrentArmy();	if(nullptr == specific)	{		logGlobal->error("createCustomInfoWindow: no object to describe");		return nullptr;	}	switch(specific->ID)	{		case Obj::HERO:			return std::make_shared<CInfoBoxPopup>(position, dynamic_cast<const CGHeroInstance *>(specific));		case Obj::TOWN:			return std::make_shared<CInfoBoxPopup>(position, dynamic_cast<const CGTownInstance *>(specific));		case Obj::MONSTER:			return std::make_shared<CInfoBoxPopup>(position, dynamic_cast<const CGCreature *>(specific));		case Obj::GARRISON:		case Obj::GARRISON2:			return std::make_shared<CInfoBoxPopup>(position, dynamic_cast<const CGGarrison *>(specific));		default:			return std::shared_ptr<WindowBase>();	}}
 |