Преглед изворни кода

Encapsulation of WindowHandler state

Ivan Savenko пре 2 година
родитељ
комит
051a4a3c17

+ 1 - 2
client/CMT.cpp

@@ -623,8 +623,7 @@ static void quitApplication()
 			CSH->endGameplay();
 	}
 
-	GH.windows().listInt.clear();
-	GH.windows().objsToBlit.clear();
+	GH.windows().clear();
 
 	CMM.reset();
 

+ 35 - 55
client/CPlayerInterface.cpp

@@ -169,15 +169,16 @@ void CPlayerInterface::initGameInterface(std::shared_ptr<Environment> ENV, std::
 void CPlayerInterface::playerStartsTurn(PlayerColor player)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	if (!vstd::contains (GH.windows().listInt, adventureInt))
+
+	if(GH.windows().findInts<AdventureMapInterface>().empty())
 	{
 		// after map load - remove all active windows and replace them with adventure map
-		GH.windows().popInts ((int)GH.windows().listInt.size());
-		GH.windows().pushInt (adventureInt);
+		GH.windows().clear();
+		GH.windows().pushInt(adventureInt);
 	}
 
 	// remove all dialogs that do not expect query answer
-	while (GH.windows().listInt.front() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.windows().listInt.front().get()))
+	while (GH.windows().topInt() != adventureInt && !dynamic_cast<CInfoWindow*>(GH.windows().topInt().get()))
 		GH.windows().popInts(1);
 
 	if (player != playerID && LOCPLINT == this)
@@ -538,17 +539,15 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 		castleInt->heroes->update();
 		castleInt->redraw();
 	}
-	for (auto isa : GH.windows().listInt)
+
+	for (auto ki : GH.windows().findInts<CKingdomInterface>())
 	{
-		CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa.get());
-		if (ki)
-		{
-			ki->townChanged(town);
-			ki->updateGarrisons();
-			ki->redraw();
-		}
+		ki->townChanged(town);
+		ki->updateGarrisons();
+		ki->redraw();
 	}
 }
+
 void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
@@ -590,17 +589,13 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> ob
 			adventureInt->onTownChanged(town);
 	}
 
-	for (auto & elem : GH.windows().listInt)
-	{
-		CGarrisonHolder *cgh = dynamic_cast<CGarrisonHolder*>(elem.get());
-		if (cgh)
-			cgh->updateGarrisons();
+	for (auto cgh : GH.windows().findInts<CGarrisonHolder>())
+		cgh->updateGarrisons();
 
-		if (CTradeWindow *cmw = dynamic_cast<CTradeWindow*>(elem.get()))
-		{
-			if (vstd::contains(objs, cmw->hero))
-				cmw->garrisonChanged();
-		}
+	for (auto cmw : GH.windows().findInts<CTradeWindow>())
+	{
+		if (vstd::contains(objs, cmw->hero))
+			cmw->garrisonChanged();
 	}
 
 	GH.windows().totalRedraw();
@@ -1016,7 +1011,7 @@ void CPlayerInterface::showInfoDialog(EInfoWindowMode type, const std::string &t
 		waitWhileDialog(); //Fix for mantis #98
 		adventureInt->showInfoBoxMessage(components, text, timer);
 
-		if (makingTurn && GH.windows().listInt.size() && LOCPLINT == this)
+		if (makingTurn && GH.windows().count() > 0 && LOCPLINT == this)
 			CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 		return;
 	}
@@ -1057,7 +1052,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 	}
 	std::shared_ptr<CInfoWindow> temp = CInfoWindow::create(text, playerID, components);
 
-	if (makingTurn && GH.windows().listInt.size() && LOCPLINT == this)
+	if (makingTurn && GH.windows().count() > 0 && LOCPLINT == this)
 	{
 		CCS->soundh->playSound(static_cast<soundBase::soundID>(soundID));
 		showingDialog->set(true);
@@ -1206,14 +1201,11 @@ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town )
 		else if(castleInterface)
 			castleInterface->creaturesChangedEventHandler();
 
-		for(auto isa : GH.windows().listInt)
-		{
-			CKingdomInterface *ki = dynamic_cast<CKingdomInterface*>(isa.get());
-			if (ki && townObj)
+		if (townObj)
+			for (auto ki : GH.windows().findInts<CKingdomInterface>())
 				ki->townChanged(townObj);
-		}
 	}
-	else if(town && GH.windows().listInt.size() && (town->ID == Obj::CREATURE_GENERATOR1
+	else if(town && GH.windows().count() > 0 && (town->ID == Obj::CREATURE_GENERATOR1
 		||  town->ID == Obj::CREATURE_GENERATOR4  ||  town->ID == Obj::WAR_MACHINE_FACTORY))
 	{
 		CRecruitmentWindow *crw = dynamic_cast<CRecruitmentWindow*>(GH.windows().topInt().get());
@@ -1594,7 +1586,7 @@ void CPlayerInterface::gameOver(PlayerColor player, const EVictoryLossCheckResul
 			if(adventureInt)
 			{
 				GH.terminate_cond->setn(true);
-				GH.windows().popInts(GH.windows().listInt.size());
+				GH.windows().popInts(GH.windows().count());
 				adventureInt.reset();
 			}
 		}
@@ -1809,12 +1801,9 @@ void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.windows().listInt)
-	{
-		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
-		if (artWin)
-			artWin->artifactRemoved(al);
-	}
+
+	for(auto artWin : GH.windows().findInts<CArtifactHolder>())
+		artWin->artifactRemoved(al);
 
 	waitWhileDialog();
 }
@@ -1834,12 +1823,9 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
 			redraw = false;
 	}
 
-	for(auto isa : GH.windows().listInt)
-	{
-		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
-		if (artWin)
-			artWin->artifactMoved(src, dst, redraw);
-	}
+	for(auto artWin : GH.windows().findInts<CArtifactHolder>())
+		artWin->artifactMoved(src, dst, redraw);
+
 	waitWhileDialog();
 }
 
@@ -1853,12 +1839,9 @@ void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.windows().listInt)
-	{
-		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
-		if (artWin)
-			artWin->artifactAssembled(al);
-	}
+
+	for(auto artWin : GH.windows().findInts<CArtifactHolder>())
+		artWin->artifactAssembled(al);
 }
 
 void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
@@ -1866,12 +1849,9 @@ void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	adventureInt->onHeroChanged(hero);
-	for(auto isa : GH.windows().listInt)
-	{
-		auto artWin = dynamic_cast<CArtifactHolder*>(isa.get());
-		if (artWin)
-			artWin->artifactDisassembled(al);
-	}
+
+	for(auto artWin : GH.windows().findInts<CArtifactHolder>())
+		artWin->artifactDisassembled(al);
 }
 
 void CPlayerInterface::waitForAllDialogs(bool unlockPim)

+ 1 - 2
client/Client.cpp

@@ -770,8 +770,7 @@ void CClient::removeGUI()
 	if(GH.windows().topInt())
 		GH.windows().topInt()->deactivate();
 	adventureInt.reset();
-	GH.windows().listInt.clear();
-	GH.windows().objsToBlit.clear();
+	GH.windows().clear();
 	GH.statusbar.reset();
 	logGlobal->info("Removed GUI.");
 

+ 2 - 8
client/ClientCommandManager.cpp

@@ -196,14 +196,8 @@ void ClientCommandManager::handleNotDialogCommand()
 
 void ClientCommandManager::handleGuiCommand()
 {
-	for(const auto & child : GH.windows().listInt)
-	{
-		const auto childPtr = child.get();
-		if(const CIntObject * obj = dynamic_cast<const CIntObject*>(childPtr))
-			printInfoAboutInterfaceObject(obj, 0);
-		else
-			printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
-	}
+	for(const auto & child : GH.windows().findInts<CIntObject>())
+		printInfoAboutInterfaceObject(child.get(), 0);
 }
 
 void ClientCommandManager::handleConvertTextCommand()

+ 1 - 1
client/NetPacksLobbyClient.cpp

@@ -57,7 +57,7 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClient
 
 void ApplyOnLobbyScreenNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
 {
-	if(GH.windows().listInt.size())
+	if(GH.windows().count() > 0)
 		GH.windows().popInts(1);
 }
 

+ 36 - 28
client/gui/WindowHandler.cpp

@@ -21,30 +21,29 @@
 
 void WindowHandler::popInt(std::shared_ptr<IShowActivatable> top)
 {
-	assert(listInt.front() == top);
+	assert(windowsStack.back() == top);
 	top->deactivate();
 	disposed.push_back(top);
-	listInt.pop_front();
-	objsToBlit -= top;
-	if(!listInt.empty())
-		listInt.front()->activate();
+	windowsStack.pop_back();
+	if(!windowsStack.empty())
+		windowsStack.back()->activate();
+
 	totalRedraw();
 }
 
 void WindowHandler::pushInt(std::shared_ptr<IShowActivatable> newInt)
 {
 	assert(newInt);
-	assert(!vstd::contains(listInt, newInt)); // do not add same object twice
+	assert(!vstd::contains(windowsStack, newInt)); // do not add same object twice
 
 	//a new interface will be present, we'll need to use buffer surface (unless it's advmapint that will alter screenBuf on activate anyway)
 	screenBuf = screen2;
 
-	if(!listInt.empty())
-		listInt.front()->deactivate();
-	listInt.push_front(newInt);
+	if(!windowsStack.empty())
+		windowsStack.back()->deactivate();
+	windowsStack.push_back(newInt);
 	CCS->curh->set(Cursor::Map::POINTER);
 	newInt->activate();
-	objsToBlit.push_back(newInt);
 	totalRedraw();
 }
 
@@ -53,36 +52,35 @@ void WindowHandler::popInts(int howMany)
 	if(!howMany)
 		return; //senseless but who knows...
 
-	assert(listInt.size() >= howMany);
-	listInt.front()->deactivate();
+	assert(windowsStack.size() >= howMany);
+	windowsStack.back()->deactivate();
 	for(int i = 0; i < howMany; i++)
 	{
-		objsToBlit -= listInt.front();
-		disposed.push_back(listInt.front());
-		listInt.pop_front();
+		disposed.push_back(windowsStack.back());
+		windowsStack.pop_back();
 	}
 
-	if(!listInt.empty())
+	if(!windowsStack.empty())
 	{
-		listInt.front()->activate();
+		windowsStack.back()->activate();
 		totalRedraw();
 	}
 	GH.fakeMouseMove();
 }
 
-std::shared_ptr<IShowActivatable> WindowHandler::topInt()
+std::shared_ptr<IShowActivatable> WindowHandler::topInt() const
 {
-	if(listInt.empty())
-		return std::shared_ptr<IShowActivatable>();
-	else
-		return listInt.front();
+	if(windowsStack.empty())
+		return nullptr;
+
+	return windowsStack.back();
 }
 
 void WindowHandler::totalRedraw()
 {
 	CSDL_Ext::fillSurface(screen2, Colors::BLACK);
 
-	for(auto & elem : objsToBlit)
+	for(auto & elem : windowsStack)
 		elem->showAll(screen2);
 	CSDL_Ext::blitAt(screen2, 0, 0, screen);
 }
@@ -90,22 +88,21 @@ void WindowHandler::totalRedraw()
 void WindowHandler::simpleRedraw()
 {
 	//update only top interface and draw background
-	if(objsToBlit.size() > 1)
+	if(windowsStack.size() > 1)
 		CSDL_Ext::blitAt(screen2, 0, 0, screen); //blit background
-	if(!objsToBlit.empty())
-		objsToBlit.back()->show(screen); //blit active interface/window
+	if(!windowsStack.empty())
+		windowsStack.back()->show(screen); //blit active interface/window
 }
 
 void WindowHandler::onScreenResize()
 {
-	for(const auto & entry : listInt)
+	for(const auto & entry : windowsStack)
 	{
 		auto intObject = std::dynamic_pointer_cast<CIntObject>(entry);
 
 		if(intObject)
 			intObject->onScreenResize();
 	}
-
 	totalRedraw();
 }
 
@@ -113,3 +110,14 @@ void WindowHandler::onFrameRendered()
 {
 	disposed.clear();
 }
+
+size_t WindowHandler::count() const
+{
+	return windowsStack.size();
+}
+
+void WindowHandler::clear()
+{
+	windowsStack.clear();
+	disposed.clear();
+}

+ 43 - 13
client/gui/WindowHandler.h

@@ -13,15 +13,14 @@ class IShowActivatable;
 
 class WindowHandler
 {
-public:
-	/// list of interfaces - front=foreground; back = background (includes adventure map, window interfaces, all kind of active dialogs, and so on)
-	std::list<std::shared_ptr<IShowActivatable>> listInt;
+	/// list of interfaces. front = bottom-most (background), back = top-most (foreground)
+	/// (includes adventure map, window interfaces, all kind of active dialogs, and so on)
+	std::vector<std::shared_ptr<IShowActivatable>> windowsStack;
 
+	/// Temporary list of recently popped windows
 	std::vector<std::shared_ptr<IShowActivatable>> disposed;
 
-	// objs to blit
-	std::vector<std::shared_ptr<IShowActivatable>> objsToBlit;
-
+public:
 	/// forces total redraw (using showAll), sets a flag, method gets called at the end of the rendering
 	void totalRedraw();
 
@@ -33,12 +32,10 @@ public:
 
 	/// deactivate old top interface, activates this one and pushes to the top
 	void pushInt(std::shared_ptr<IShowActivatable> newInt);
+
+	/// creates window of class T and pushes it to the top
 	template <typename T, typename ... Args>
-	void pushIntT(Args && ... args)
-	{
-		auto newInt = std::make_shared<T>(std::forward<Args>(args)...);
-		pushInt(newInt);
-	}
+	void pushIntT(Args && ... args);
 
 	/// pops one or more interfaces - deactivates top, deletes and removes given number of interfaces, activates new front
 	void popInts(int howMany);
@@ -47,8 +44,41 @@ public:
 	void popInt(std::shared_ptr<IShowActivatable> top);
 
 	/// returns top interface
-	std::shared_ptr<IShowActivatable> topInt();
-
+	std::shared_ptr<IShowActivatable> topInt() const;
 
+	/// should be called after frame has been rendered to screen
 	void onFrameRendered();
+
+	/// returns current number of windows in the stack
+	size_t count() const;
+
+	/// erases all currently existing windows from the stacl
+	void clear();
+
+	/// returns all existing windows of selected type
+	template <typename T>
+	std::vector<std::shared_ptr<T>> findInts() const;
 };
+
+template <typename T, typename ... Args>
+void WindowHandler::pushIntT(Args && ... args)
+{
+	auto newInt = std::make_shared<T>(std::forward<Args>(args)...);
+	pushInt(newInt);
+}
+
+template <typename T>
+std::vector<std::shared_ptr<T>> WindowHandler::findInts() const
+{
+	std::vector<std::shared_ptr<T>> result;
+
+	for (auto const & window : windowsStack)
+	{
+		std::shared_ptr<T> casted = std::dynamic_pointer_cast<T>(window);
+
+		if (casted)
+			result.push_back(casted);
+	}
+
+	return result;
+}

+ 3 - 3
client/mainmenu/CMainMenu.cpp

@@ -325,7 +325,7 @@ void CMainMenu::update()
 	if(CMM != this->shared_from_this()) //don't update if you are not a main interface
 		return;
 
-	if(GH.windows().listInt.empty())
+	if(GH.windows().count() == 0)
 	{
 		GH.windows().pushInt(CMM);
 		GH.windows().pushInt(menu);
@@ -523,7 +523,7 @@ void CSimpleJoinScreen::leaveScreen()
 		textTitle->setText("Closing...");
 		CSH->state = EClientState::CONNECTION_CANCELLED;
 	}
-	else if(GH.windows().listInt.size() && GH.windows().listInt.front().get() == this)
+	else if(GH.windows().topInt().get() == this)
 	{
 		close();
 	}
@@ -553,7 +553,7 @@ void CSimpleJoinScreen::connectThread(const std::string & addr, ui16 port)
 	else
 		CSH->justConnectToServer(addr, port);
 
-	if(GH.windows().listInt.size() && GH.windows().listInt.front().get() == this)
+	if(GH.windows().topInt().get() == this)
 	{
 		close();
 	}

+ 1 - 1
client/renderSDL/ScreenHandler.cpp

@@ -271,7 +271,7 @@ void ScreenHandler::initializeScreenBuffers()
 		throw std::runtime_error("Unable to copy surface\n");
 	}
 
-	if (GH.windows().listInt.size() > 1)
+	if (GH.windows().count() > 1)
 		screenBuf = screen2;
 	else
 		screenBuf = screen;

+ 9 - 10
client/windows/CHeroWindow.cpp

@@ -314,18 +314,17 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 
 	//if we have exchange window with this curHero open
 	bool noDismiss=false;
-	for(auto isa : GH.windows().listInt)
-	{
-		if(CExchangeWindow * cew = dynamic_cast<CExchangeWindow*>(isa.get()))
-		{
-			for(int g=0; g < cew->heroInst.size(); ++g)
-				if(cew->heroInst[g] == curHero)
-					noDismiss = true;
-		}
 
-		if(dynamic_cast<CKingdomInterface*>(isa.get()))
-			noDismiss = true;
+	for(auto cew : GH.windows().findInts<CExchangeWindow>())
+	{
+		for(int g=0; g < cew->heroInst.size(); ++g)
+			if(cew->heroInst[g] == curHero)
+				noDismiss = true;
 	}
+
+	for(auto ki : GH.windows().findInts<CKingdomInterface>())
+		noDismiss = true;
+
 	//if player only have one hero and no towns
 	if(!LOCPLINT->cb->howManyTowns() && LOCPLINT->cb->howManyHeroes() == 1)
 		noDismiss = true;