From 7de5c06c7a18eb1004f142d429280bc147513b88 Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Fri, 20 Apr 2018 17:00:04 +0200 Subject: [PATCH] [xswiftbus] Fix destroying of removed menu items --- src/xswiftbus/menus.cpp | 53 ++++++++++++++++++++++++++------------- src/xswiftbus/menus.h | 21 ++++++++++------ src/xswiftbus/traffic.cpp | 14 ++++++++++- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/xswiftbus/menus.cpp b/src/xswiftbus/menus.cpp index 0e1f6906c..2a0d0c1c1 100644 --- a/src/xswiftbus/menus.cpp +++ b/src/xswiftbus/menus.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace XSwiftBus { @@ -53,20 +54,40 @@ namespace XSwiftBus { assert(! name.empty()); m_data->items->emplace_back( - CMenuItem { m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), voidptr_cast(m_data->items->size() + 1), false), false, false }, - [callback](bool){ callback(); } + CMenuItem { m_data->id, 0, false, false, [callback](bool) { callback(); } } ); - return m_data->items->back().first; + auto &menuItem = m_data->items->back(); + menuItem.setIndex(XPLMAppendMenuItem(m_data->id, name.c_str(), &menuItem, false)); + return menuItem; } CMenuItem CMenu::checkableItem(const std::string &name, bool checked, std::function callback) { - assert(! name.empty()); + assert(!name.empty()); m_data->items->emplace_back( - CMenuItem { m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), voidptr_cast(m_data->items->size() + 1), false), true, checked }, - callback + CMenuItem{ m_data->id, 0, true, checked, callback } ); - return m_data->items->back().first; + auto &menuItem = m_data->items->back(); + menuItem.setIndex(XPLMAppendMenuItem(m_data->id, name.c_str(), voidptr_cast(m_data->items->size() + 1), false)); + return menuItem; + } + + void CMenu::removeItem(const CMenuItem &item) + { + auto it = std::find_if(m_data->items->begin(), m_data->items->end(), [ = ](const auto & i) + { + return i.m_data->index == item.m_data->index; + }); + + XPLMRemoveMenuItem(m_data->id, it->m_data->index); + it = m_data->items->erase(it); + + // Decrement the index of all below menu items + while (it != m_data->items->end()) + { + it->m_data->index--; + ++it; + } } void CMenu::sep() @@ -77,6 +98,7 @@ namespace XSwiftBus CMenu CMenu::subMenu(const std::string &name) { assert(! name.empty()); + // auto items = std::make_unique(); auto items = std::make_unique(); auto itemsVoidPtr = static_cast(&*items); return { XPLMCreateMenu(name.c_str(), m_data->id, XPLMAppendMenuItem(m_data->id, name.c_str(), nullptr, false), handler, itemsVoidPtr), false, std::move(items) }; @@ -86,16 +108,13 @@ namespace XSwiftBus { if (menuRef && itemRef) { - auto items = static_cast(menuRef); - auto itemIdx = intptr_cast(itemRef) - 1; - assert(itemIdx >= 0); - - (*items)[itemIdx].second((*items)[itemIdx].first.getChecked()); + CMenuItem *menuItem = static_cast(itemRef); + menuItem->m_data->callback(menuItem->getChecked()); } } - CMenuItem::CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked) - : m_data(std::make_shared(parent, item, checkable)) + CMenuItem::CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked, std::function callback) + : m_data(std::make_shared(parent, item, checkable, callback)) { if (checkable) { @@ -106,18 +125,18 @@ namespace XSwiftBus bool CMenuItem::getChecked() const { XPLMMenuCheck check = xplm_Menu_NoCheck; - XPLMCheckMenuItemState(m_data->parent, m_data->item, &check); + XPLMCheckMenuItemState(m_data->parent, m_data->index, &check); return check == xplm_Menu_Checked; } void CMenuItem::setChecked(bool checked) { - XPLMCheckMenuItem(m_data->parent, m_data->item, checked); + XPLMCheckMenuItem(m_data->parent, m_data->index, checked); } void CMenuItem::setEnabled(bool enabled) { - XPLMEnableMenuItem(m_data->parent, m_data->item, enabled); + XPLMEnableMenuItem(m_data->parent, m_data->index, enabled); } } diff --git a/src/xswiftbus/menus.h b/src/xswiftbus/menus.h index f52907b6f..b65eeff34 100644 --- a/src/xswiftbus/menus.h +++ b/src/xswiftbus/menus.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include namespace XSwiftBus @@ -43,14 +43,17 @@ namespace XSwiftBus private: friend class CMenu; - CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked); + CMenuItem(XPLMMenuID parent, int item, bool checkable, bool checked, std::function callback); + + void setIndex(int index) { m_data->index = index; } struct Data { - Data(XPLMMenuID parent_, int item_, bool checkable_) : parent(parent_), item(item_), checkable(checkable_) {} + Data(XPLMMenuID parent_, int index_, bool checkable_, std::function callback_) : parent(parent_), index(index_), checkable(checkable_), callback(callback_) {} XPLMMenuID parent; - int item; + int index; bool checkable; + std::function callback; }; std::shared_ptr m_data; }; @@ -73,6 +76,9 @@ namespace XSwiftBus //! Appends a checkbox item to the menu and returns it. CMenuItem checkableItem(const std::string &name, bool checked, std::function callback); + //! Removes item from the menu + void removeItem(const CMenuItem &item); + //! Appends a separator to the menu. void sep(); @@ -80,9 +86,11 @@ namespace XSwiftBus CMenu subMenu(const std::string &name); private: - typedef std::vector>> ItemList; + // Using std::list, since it does not invalidate pointers. + using ItemList = std::list; - CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr callbacks); + // CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr callbacks); + CMenu(XPLMMenuID id, bool isMainMenu, std::unique_ptr items); static void handler(void *menuRef, void *itemRef); @@ -93,7 +101,6 @@ namespace XSwiftBus XPLMMenuID id; bool isMainMenu; std::unique_ptr items; - std::vector subMenus; ~Data(); Data(const Data &) = delete; Data &operator =(const Data &) = delete; diff --git a/src/xswiftbus/traffic.cpp b/src/xswiftbus/traffic.cpp index 67abc5ff1..9312b2a2a 100644 --- a/src/xswiftbus/traffic.cpp +++ b/src/xswiftbus/traffic.cpp @@ -233,7 +233,12 @@ namespace XSwiftBus void CTraffic::removePlane(const std::string &callsign) { - m_planeViewMenuItems.erase(callsign); + auto menuItemIt = m_planeViewMenuItems.find(callsign); + if (menuItemIt != m_planeViewMenuItems.end()) + { + m_planeViewSubMenu.removeItem(menuItemIt->second); + m_planeViewMenuItems.erase(menuItemIt); + } auto planeIt = m_planesByCallsign.find(callsign); if (planeIt == m_planesByCallsign.end()) { return; } @@ -254,6 +259,13 @@ namespace XSwiftBus XPMPDestroyPlane(plane->id); delete plane; } + + for (const auto &kv : m_planeViewMenuItems) + { + CMenuItem item = kv.second; + m_planeViewSubMenu.removeItem(item); + } + m_planesByCallsign.clear(); m_planesById.clear(); m_planeViewMenuItems.clear();