1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-11 11:31:52 +02:00

Encapsulation of WindowHandler state

This commit is contained in:
Ivan Savenko 2023-05-16 16:07:03 +03:00
parent 7838190ef4
commit 051a4a3c17
10 changed files with 132 additions and 123 deletions

View File

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

View File

@ -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)

View File

@ -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.");

View File

@ -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()

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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;