From cbf76a312a3cda00a758a38c46f8ba6223b6c9c7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 6 May 2017 07:24:21 +0800 Subject: [PATCH] refactor menu for menu::insert that would break internal states --- include/nana/gui/widgets/menu.hpp | 11 ++- source/gui/widgets/menu.cpp | 146 +++++++++++++++--------------- 2 files changed, 83 insertions(+), 74 deletions(-) diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 662b84a5..f468e13a 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -19,6 +19,8 @@ namespace nana { + class menu; + namespace drawerbase { namespace menu @@ -69,7 +71,12 @@ namespace nana bool checked:1; }flags; - menu_type *sub_menu{nullptr}; + struct + { + bool own_creation; //Indicates the menu_ptr is created by create_sub_menu + menu_type* menu_ptr; + }linked; + std::string text; event_fn_t event_handler; checks style{checks::none}; @@ -149,7 +156,7 @@ namespace nana bool enabled(std::size_t pos) const; void erase(std::size_t pos); ///< Removes the item bool link(std::size_t pos, menu& menu_obj);///< Link a menu to the item as a sub menu. - menu * link(std::size_t pos); ///< Retrieves a linked sub menu of the item. + menu * link(std::size_t pos) const; ///< Retrieves a linked sub menu of the item. menu *create_sub_menu(std::size_t pos); void popup(window owner, int x, int y); ///< Popup the menu at the owner window. void popup_await(window owner, int x, int y); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index dc78e98f..60c4fb9e 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -21,7 +21,6 @@ #include #include #include //introduces tolower -#include #include namespace nana @@ -37,7 +36,8 @@ namespace nana using item_container = std::vector>; using iterator = item_container::iterator; - std::vector owner; + ::nana::menu* owner; + std::vector links; item_container items; unsigned max_pixels; unsigned item_pixels; @@ -103,6 +103,9 @@ namespace nana flags.enabled = true; flags.splitter = true; flags.checked = false; + + linked.own_creation = false; + linked.menu_ptr = nullptr; } menu_item_type::menu_item_type(std::string text, const event_fn_t& fn) @@ -111,6 +114,9 @@ namespace nana flags.enabled = true; flags.splitter = false; flags.checked = false; + + linked.own_creation = false; + linked.menu_ptr = nullptr; } //end class menu_item_type @@ -209,8 +215,9 @@ namespace nana using event_fn_t = item_type::event_fn_t; using iterator = menu_type::item_container::iterator; - menu_builder() + menu_builder(::nana::menu* owner) { + root_.owner = owner; root_.max_pixels = screen::primary_monitor_size().width * 2 / 3; root_.item_pixels = 24; renderer_ = pat::cloneable(internal_renderer()); @@ -218,7 +225,37 @@ namespace nana ~menu_builder() { - this->destroy(); + //Disconnects the link. + + //Clears the all links which are parent of mine + for (auto link : root_.links) + { + for (auto & m : link->items) + { + if (m->linked.menu_ptr == &root_) + { + m->linked.own_creation = false; + m->linked.menu_ptr = nullptr; + } + } + } + + for (auto & m : root_.items) + { + if (m->linked.menu_ptr) + { + for (auto i = m->linked.menu_ptr->links.begin(); i != m->linked.menu_ptr->links.end();) + { + if ((*i) == &root_) + i = m->linked.menu_ptr->links.erase(i); + else + ++i; + } + + if (m->linked.own_creation) + delete m->linked.menu_ptr->owner; + } + } } void check_style(std::size_t index, checks s) @@ -270,41 +307,19 @@ namespace nana return root_; } - bool set_sub_menu(std::size_t pos, menu_type &sub) + //Returns false if the linked menu is already existing + bool set_linkage(std::size_t pos, menu_type &linked, bool own_creation) { - if(root_.items.size() > pos) - { - auto & item = *(root_.items[pos]); - if(!item.sub_menu) - { - item.sub_menu = ⊂ - sub.owner.emplace_back(&root_); - return true; - } - } - return false; - } + auto mi = root_.items.at(pos).get(); - void destroy() - { - for(auto i : root_.owner) - for(auto & m : i->items) - { - if(m->sub_menu == &root_) - m->sub_menu = nullptr; - } + if (mi->linked.menu_ptr) + return false; - for(auto & m : root_.items) - { - if(m->sub_menu) - for(auto i = m->sub_menu->owner.begin(); i != m->sub_menu->owner.end();) - { - if((*i) == &root_) - i = m->sub_menu->owner.erase(i); - else - ++i; - } - } + mi->linked.menu_ptr = &linked; + mi->linked.own_creation = own_creation; + linked.links.emplace_back(&root_); + + return true; } pat::cloneable& renderer() @@ -438,7 +453,7 @@ namespace nana } } - if (item_ptr->sub_menu) + if (item_ptr->linked.menu_ptr) renderer->sub_arrow(graph, nana::point(graph_->width() - 20, item_r.y), item_h_px, attr); item_r.y += item_r.height + 1; @@ -522,7 +537,7 @@ namespace nana std::size_t index = _m_get_index_by_pos(pos.x, pos.y); if (index != state_.active) { - if ((index == npos) && items.at(state_.active)->sub_menu && state_.sub_window) + if ((index == npos) && items.at(state_.active)->linked.menu_ptr && state_.sub_window) return false; state_.active = (index != npos && items.at(index)->flags.splitter) ? npos : index; @@ -550,7 +565,7 @@ namespace nana return nullptr; auto & items = menu_->items; - auto sub = items.at(state_.active)->sub_menu; + auto sub = items.at(state_.active)->linked.menu_ptr; if (sub) { pos.x = static_cast(graph_->width()) - 2; @@ -593,7 +608,7 @@ namespace nana if (!item_ptr->flags.splitter) { - if (item_ptr->sub_menu) + if (item_ptr->linked.menu_ptr) { state_.active = index; state_.active_timestamp = nana::system::timestamp(); @@ -901,7 +916,7 @@ namespace nana menu_item_type & item = *(menu->items.at(active)); - if ((!item.flags.enabled) || item.flags.splitter || item.sub_menu) + if ((!item.flags.enabled) || item.flags.splitter || item.linked.menu_ptr) return; if (checks::highlight == item.style) @@ -1109,11 +1124,15 @@ namespace nana drawerbase::menu::menu_builder mbuilder; drawerbase::menu::menu_window * window_ptr; std::function destroy_answer; - std::map sub_container; + + implement(menu* self): + mbuilder{self} + { + } }; menu::menu() - :impl_(new implement) + :impl_(new implement(this)) { impl_->window_ptr = nullptr; } @@ -1121,11 +1140,6 @@ namespace nana menu::~menu() { this->close(); - for(auto i = impl_->sub_container.rbegin(); i != impl_->sub_container.rend(); ++i) - { - if(i->second.kill) - delete i->second.handle; - } delete impl_; } @@ -1198,37 +1212,25 @@ namespace nana bool menu::link(std::size_t index, menu& menu_obj) { - if(impl_->mbuilder.set_sub_menu(index, menu_obj.impl_->mbuilder.data())) - { - auto& minfo = impl_->sub_container[index]; - minfo.handle = &menu_obj; - minfo.kill = false; - return true; - } - return false; + return impl_->mbuilder.set_linkage(index, menu_obj.impl_->mbuilder.data(), false); } - menu* menu::link(std::size_t index) + menu* menu::link(std::size_t index) const { - auto i = impl_->sub_container.find(index); - if(i == impl_->sub_container.end()) - return nullptr; - return i->second.handle; + auto mi = impl_->mbuilder.data().items.at(index).get(); + + if (mi && mi->linked.menu_ptr) + return mi->linked.menu_ptr->owner; + + return nullptr; } menu *menu::create_sub_menu(std::size_t index) { - menu * sub = new menu; - - if (this->link(index, *sub)) - { - auto& minfo = impl_->sub_container[index]; - minfo.handle = sub; - minfo.kill = true; - return sub; - } - - delete sub; + std::unique_ptr guard{new menu}; + if (impl_->mbuilder.set_linkage(index, guard->impl_->mbuilder.data(), true)) + return guard.release(); + return nullptr; }