1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Workaround for false double-clicking of elements in hero/town lists

This commit is contained in:
Ivan Savenko
2023-07-17 17:40:28 +03:00
parent 6fd3c0f8bc
commit 64a22d8590
2 changed files with 53 additions and 4 deletions

View File

@@ -287,8 +287,28 @@ void CHeroList::updateElement(const CGHeroInstance * hero)
void CHeroList::updateWidget() void CHeroList::updateWidget()
{ {
listBox->resize(LOCPLINT->localState->getWanderingHeroes().size()); auto & heroes = LOCPLINT->localState->getWanderingHeroes();
listBox->reset();
listBox->resize(heroes.size());
for (size_t i = 0; i < heroes.size(); ++i)
{
auto item = std::dynamic_pointer_cast<CHeroItem>(listBox->getItem(i));
if (!item)
continue;
if (item->hero == heroes[i])
{
item->update();
}
else
{
listBox->reset();
break;
}
}
if (LOCPLINT->localState->getCurrentHero()) if (LOCPLINT->localState->getCurrentHero())
select(LOCPLINT->localState->getCurrentHero()); select(LOCPLINT->localState->getCurrentHero());
@@ -364,8 +384,28 @@ void CTownList::updateElement(const CGTownInstance * town)
void CTownList::updateWidget() void CTownList::updateWidget()
{ {
listBox->resize(LOCPLINT->localState->getOwnedTowns().size()); auto & towns = LOCPLINT->localState->getOwnedTowns();
listBox->reset();
listBox->resize(towns.size());
for (size_t i = 0; i < towns.size(); ++i)
{
auto item = std::dynamic_pointer_cast<CTownItem>(listBox->getItem(i));
if (!item)
continue;
if (item->town == towns[i])
{
item->update();
}
else
{
listBox->reset();
break;
}
}
if (LOCPLINT->localState->getCurrentTown()) if (LOCPLINT->localState->getCurrentTown())
select(LOCPLINT->localState->getCurrentTown()); select(LOCPLINT->localState->getCurrentTown());

View File

@@ -172,6 +172,15 @@ void EventDispatcher::dispatchClosePopup(const Point & position)
void EventDispatcher::handleLeftButtonClick(const Point & position, bool isPressed) void EventDispatcher::handleLeftButtonClick(const Point & position, bool isPressed)
{ {
// WARNING: this approach is NOT SAFE
// 1) We allow (un)registering elements when list itself is being processed/iterated
// 2) To avoid iterator invalidation we create a copy of this list for processing
// HOWEVER it is completely possible (as in, actually happen, no just theory) to:
// 1) element gets unregistered and deleted from lclickable
// 2) element is completely deleted, as in - destructor called, memory freed
// 3) new element is created *with exactly same address(!)
// 4) new element is registered and code will incorrectly assume that this element is still registered
// POSSIBLE SOLUTION: make EventReceivers inherit from create_shared_from this and store weak_ptr's in lists
auto hlp = lclickable; auto hlp = lclickable;
for(auto & i : hlp) for(auto & i : hlp)
{ {