| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424 | /* * 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 "CAdvmapInterface.h"#include "../CBitmapHandler.h"#include "../Graphics.h"#include "../CGameInfo.h"#include "../CPlayerInterface.h"#include "../CMessage.h"#include "../CMusicHandler.h"#include "../widgets/CComponent.h"#include "../widgets/MiscWidgets.h"#include "../gui/SDL_Pixels.h"#include "../gui/SDL_Extensions.h"#include "../gui/CGuiHandler.h"#include "../gui/CCursorHandler.h"#include "../battle/CBattleInterface.h"#include "../battle/CBattleInterfaceClasses.h"#include "../../CCallback.h"#include "../../lib/CGameState.h"#include "../../lib/CConfigHandler.h"#include "../../lib/CondSh.h"#include "../../lib/CGeneralTextHandler.h" //for Unicode related stuff#include "../../lib/mapObjects/CGHeroInstance.h"#include "../../lib/mapObjects/CGTownInstance.h"#include "../../lib/mapObjects/MiscObjects.h"void CSimpleWindow::show(SDL_Surface * to){	if(bitmap)		blitAt(bitmap,pos.x,pos.y,to);}CSimpleWindow::~CSimpleWindow(){	if (bitmap)	{		SDL_FreeSurface(bitmap);		bitmap=nullptr;	}}void CSelWindow::selectionChange(unsigned to){	for (unsigned i=0;i<components.size();i++)	{		auto pom = std::dynamic_pointer_cast<CSelectableComponent>(components[i]);		if (!pom)			continue;		pom->select(i==to);	}	redraw();}CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<std::shared_ptr<CSelectableComponent>> & comps, const std::vector<std::pair<std::string, CFunctionList<void()> > > &Buttons, QueryID askID){	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);	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, CENTER, Colors::WHITE);	buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter	buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape	if (buttons.size() > 1 && askID.getNum() >= 0) //cancel button functionality	{		buttons.back()->addCallback([askID]() {			LOCPLINT->cb.get()->selectionMade(0, askID);		});		//buttons.back()->addCallback(std::bind(&CCallback::selectionMade, LOCPLINT->cb.get(), 0, askID));	}	for(int i=0;i<comps.size();i++)	{		comps[i]->recActions = 255-DISPOSE;		addChild(comps[i].get());		components.push_back(comps[i]);		comps[i]->onSelect = std::bind(&CSelWindow::selectionChange,this,i);		if(i<9)			comps[i]->assignedKeys.insert(SDLK_1+i);	}	CMessage::drawIWindow(this, Text, player);}void CSelWindow::madeChoice(){	if(ID.getNum() < 0)		return;	int ret = -1;	for (int i=0;i<components.size();i++)	{		if(std::dynamic_pointer_cast<CSelectableComponent>(components[i])->selected)		{			ret = i;		}	}	LOCPLINT->cb->selectionMade(ret+1,ID);}CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo & comps, const TButtonsInfo & Buttons){	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);	type |= BLOCK_ADV_HOTKEYS;	ID = QueryID(-1);	for(auto & Button : Buttons)	{		std::shared_ptr<CButton> 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, CENTER, Colors::WHITE);	if(!text->slider)	{		text->resize(text->label->textSize);	}	if(buttons.size())	{		buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter		buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape	}	for(auto & comp : comps)	{		comp->recActions = 0xff & ~DISPOSE;		addChild(comp.get());		comp->recActions &= ~(SHOWALL | UPDATE);		components.push_back(comp);	}	CMessage::drawIWindow(this,Text,player);}CInfoWindow::CInfoWindow(){	ID = QueryID(-1);}void CInfoWindow::close(){	WindowBase::close();	if(LOCPLINT)		LOCPLINT->showingDialog->setn(false);}void CInfoWindow::show(SDL_Surface * to){	CIntObject::show(to);}CInfoWindow::~CInfoWindow() = default;void CInfoWindow::showAll(SDL_Surface * to){	CSimpleWindow::show(to);	CIntObject::showAll(to);}void CInfoWindow::showInfoDialog(const std::string &text, const TCompsInfo & components, PlayerColor player){	GH.pushInt(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->get());	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));	pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));	std::shared_ptr<CInfoWindow> temp =  std::make_shared<CInfoWindow>(text, player, components, pom);	temp->buttons[0]->addCallback( onYes );	temp->buttons[1]->addCallback( onNo );	GH.pushInt(temp);}std::shared_ptr<CInfoWindow> CInfoWindow::create(const std::string &text, PlayerColor playerID, const TCompsInfo & components){	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));	return std::make_shared<CInfoWindow>(text, playerID, components, pom);}std::string CInfoWindow::genText(std::string title, std::string description){	return std::string("{") + title + "}" + "\n\n" + description;}CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free) :free(Free),bitmap(Bitmap){	init(x, y);}CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free) : free(Free),bitmap(Bitmap){	switch(alignment)	{	case BOTTOMRIGHT:		init(p.x - Bitmap->w, p.y - Bitmap->h);		break;	case CENTER:		init(p.x - Bitmap->w/2, p.y - Bitmap->h/2);		break;	case TOPLEFT:		init(p.x, p.y);		break;	default:		assert(0); //not implemented	}}CInfoPopup::CInfoPopup(SDL_Surface *Bitmap, bool Free){	CCS->curh->hide();	free=Free;	bitmap=Bitmap;	if(bitmap)	{		pos.x = screen->w/2 - bitmap->w/2;		pos.y = screen->h/2 - bitmap->h/2;		pos.h = bitmap->h;		pos.w = bitmap->w;	}}void CInfoPopup::close(){	if(free)		SDL_FreeSurface(bitmap);	WindowBase::close();}void CInfoPopup::show(SDL_Surface * to){	blitAt(bitmap,pos.x,pos.y,to);}CInfoPopup::~CInfoPopup(){	CCS->curh->show();}void CInfoPopup::init(int x, int y){	CCS->curh->hide();	pos.x = x;	pos.y = y;	pos.h = bitmap->h;	pos.w = bitmap->w;	// Put the window back on screen if necessary	vstd::amax(pos.x, 0);	vstd::amax(pos.y, 0);	vstd::amin(pos.x, screen->w - bitmap->w);	vstd::amin(pos.y, screen->h - bitmap->h);}void CRClickPopup::clickRight(tribool down, bool previousState){	if(down)		return;	close();}void CRClickPopup::close(){	WindowBase::close();}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(Point(GH.current->motion)); //center on mouse	temp->fitToScreen(10);	GH.pushIntT<CRClickPopupInt>(temp);}void CRClickPopup::createAndPush(const std::string & txt, std::shared_ptr<CComponent> component){	CInfoWindow::TCompsInfo intComps;	intComps.push_back(component);	createAndPush(txt, intComps);}void CRClickPopup::createAndPush(const CGObjectInstance * obj, const Point & p, EAlignment alignment){	auto iWin = createInfoWin(p, obj); //try get custom infowindow for this obj	if(iWin)	{		GH.pushInt(iWin);	}	else	{		if(adventureInt->curHero())			CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));		else			CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));	}}CRClickPopup::CRClickPopup(){	addUsedEvents(RCLICK);}CRClickPopup::~CRClickPopup(){}CRClickPopupInt::CRClickPopupInt(std::shared_ptr<CIntObject> our){	CCS->curh->hide();	defActions = SHOWALL | UPDATE;	our->recActions = defActions;	inner = our;	addChild(our.get(), false);}CRClickPopupInt::~CRClickPopupInt(){	CCS->curh->show();}Point CInfoBoxPopup::toScreen(Point p){	vstd::abetween(p.x, adventureInt->terrain.pos.x + 100, adventureInt->terrain.pos.x + adventureInt->terrain.pos.w - 100);	vstd::abetween(p.y, adventureInt->terrain.pos.y + 100, adventureInt->terrain.pos.y + adventureInt->terrain.pos.h - 100);	return p;}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position)){	InfoAboutTown iah;	LOCPLINT->cb->getTownInfo(town, iah, adventureInt->selection); //todo: should this be nearest hero?	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);	tooltip = std::make_shared<CTownTooltip>(Point(9, 10), iah);}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position)){	InfoAboutHero iah;	LOCPLINT->cb->getHeroInfo(hero, iah, adventureInt->selection);//todo: should this be nearest hero?	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);	tooltip = std::make_shared<CHeroTooltip>(Point(9, 10), iah);}CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr)	: CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position)){	InfoAboutTown iah;	LOCPLINT->cb->getTownInfo(garr, iah);	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);	tooltip = std::make_shared<CArmyTooltip>(Point(9, 10), iah);}std::shared_ptr<WindowBase> CRClickPopup::createInfoWin(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero{	if(nullptr == specific)		specific = adventureInt->selection;	if(nullptr == specific)	{		logGlobal->error("createInfoWin: 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::GARRISON:	case Obj::GARRISON2:		return std::make_shared<CInfoBoxPopup>(position, dynamic_cast<const CGGarrison *>(specific));	default:		return std::shared_ptr<WindowBase>();	}}
 |