From 93bd5566aea4227ea9d41191f0c375c6c4a79afd Mon Sep 17 00:00:00 2001 From: qPCR4vir Date: Tue, 2 May 2017 12:22:43 +0200 Subject: [PATCH 1/9] clone branch=hotfix-1.5 qPCR4vir/nana-demo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ba037042..04816719 100644 --- a/.travis.yml +++ b/.travis.yml @@ -56,7 +56,7 @@ matrix: - llvm-toolchain-precise before_install: - - git clone --depth=1 --branch=hotfix-1.4 https://github.com/qPCR4vir/nana-demo.git ../nana-demo + - git clone --depth=1 --branch=hotfix-1.5 https://github.com/qPCR4vir/nana-demo.git ../nana-demo - export PATH="$HOME/bin:$PATH" - mkdir ~/bin - wget --no-check-certificate --no-clobber -O /tmp/tools/cmake https://cmake.org/files/v3.4/cmake-3.4.0-rc3-Linux-x86_64.sh || true From 526f3d6d6baa581261acc93064004cbf5ad92543 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Wed, 3 May 2017 07:37:24 +0800 Subject: [PATCH 2/9] fix issue that listbox::erase(item_proxy) wouldn't erase item --- source/gui/widgets/listbox.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 53555952..1a3325ec 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -5376,6 +5376,8 @@ namespace nana if (start_pos < origin.y) origin.y -= ess->item_height(); + ess->lister.erase(_where); + ess->calc_content_size(false); ess->content_view->change_position(origin.y, false, false); ess->content_view->sync(false); From aab3686037b41a8f3807166e9d5b4581adcb4c67 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 4 May 2017 04:00:19 +0800 Subject: [PATCH 3/9] fix issue that basic_window may be leaked --- source/gui/detail/window_register.hpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/gui/detail/window_register.hpp b/source/gui/detail/window_register.hpp index 65ac0fa8..40b2fae6 100644 --- a/source/gui/detail/window_register.hpp +++ b/source/gui/detail/window_register.hpp @@ -111,6 +111,15 @@ namespace nana public: using window_handle_type = basic_window*; + ~window_register() + { + //Deleting a basic_window if thread never called exec(), the basic_window object + //will always stay in trash. + // + //Empty the trash before destructs window register + delete_trash(0); + } + void insert(window_handle_type wd) { if (wd) From abda8e55ecdafae446c4abf90d4c9669230f30af Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 4 May 2017 05:08:07 +0800 Subject: [PATCH 4/9] fix issue that selection box appears in single selection listbox(#204) --- source/gui/widgets/skeletons/content_view.cpp | 10 ++++++---- source/gui/widgets/skeletons/content_view.hpp | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index 4dfc49a0..df53bcd7 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -164,11 +164,9 @@ namespace nana { speed_horz = (std::min)(5, (std::max)(speed_horz, -5)); speed_vert = (std::min)(5, (std::max)(speed_vert, -5)); - view.move_origin({ + return view.move_origin({ speed_horz, speed_vert }); - - return true; } void size_changed(bool try_update) @@ -435,10 +433,12 @@ namespace nana { } } - void content_view::move_origin(const point& skew) + bool content_view::move_origin(const point& skew) { auto imd_area = this->view_area(); + auto pre_origin = impl_->origin; + impl_->origin.x += skew.x; if (impl_->origin.x + imd_area.width > impl_->content_size.width) impl_->origin.x = static_cast(impl_->content_size.width) - static_cast(imd_area.width); @@ -451,6 +451,8 @@ namespace nana { impl_->origin.y = static_cast(impl_->content_size.height) - static_cast(imd_area.height); if (impl_->origin.y < 0) impl_->origin.y = 0; + + return (pre_origin != impl_->origin); } void content_view::sync(bool try_update) diff --git a/source/gui/widgets/skeletons/content_view.hpp b/source/gui/widgets/skeletons/content_view.hpp index 2575fe29..6d4b2d40 100644 --- a/source/gui/widgets/skeletons/content_view.hpp +++ b/source/gui/widgets/skeletons/content_view.hpp @@ -70,7 +70,8 @@ namespace skeletons void change_position(int pos, bool aligned, bool horz); - void move_origin(const point& skew); + /// Returns true if the origin is moved + bool move_origin(const point& skew); void sync(bool try_update); From 74707820bf0591678d1123702c8ed82fc331f9dc Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 4 May 2017 05:32:09 +0800 Subject: [PATCH 5/9] improve content_view for dragging --- source/gui/widgets/skeletons/content_view.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index df53bcd7..438ce4ea 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -92,14 +92,15 @@ namespace nana { auto mouse_evt = [this](const arg_mouse& arg) { - if (event_code::mouse_move == arg.evt_code) + if (event_code::mouse_down == arg.evt_code) { if (!arg.is_left_button()) return; - if ((!this->drag_started) && this->view.view_area().is_hit(arg.pos)) - this->drag_started = true; - + this->drag_started = this->view.view_area().is_hit(arg.pos); + } + else if (event_code::mouse_move == arg.evt_code) + { if (this->drag_started && this->drive(arg.pos)) { tmr.interval(16); @@ -113,6 +114,7 @@ namespace nana { } }; + API::events(handle).mouse_down.connect_unignorable(mouse_evt); API::events(handle).mouse_move.connect_unignorable(mouse_evt); API::events(handle).mouse_up.connect_unignorable(mouse_evt); From bbaf59927207550635b7bac7e51e0862047bb7a0 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Thu, 4 May 2017 06:10:54 +0800 Subject: [PATCH 6/9] remove member type menu::item_type --- include/nana/gui/widgets/menu.hpp | 5 ++--- source/gui/widgets/menu.cpp | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/nana/gui/widgets/menu.hpp b/include/nana/gui/widgets/menu.hpp index 693310a2..662b84a5 100644 --- a/include/nana/gui/widgets/menu.hpp +++ b/include/nana/gui/widgets/menu.hpp @@ -117,9 +117,8 @@ namespace nana typedef drawerbase::menu::checks checks; typedef drawerbase::menu::renderer_interface renderer_interface; - typedef drawerbase::menu::menu_item_type item_type; - typedef item_type::item_proxy item_proxy; - typedef item_type::event_fn_t event_fn_t; ///< A callback functor type. Prototype: `void(item_proxy&)` + typedef drawerbase::menu::menu_item_type::item_proxy item_proxy; + typedef drawerbase::menu::menu_item_type::event_fn_t event_fn_t; ///< A callback functor type. Prototype: `void(item_proxy&)` menu(); ///< The default constructor. NO OTHER CONSTRUCTOR. ~menu(); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 78f842bc..76f367e0 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1128,6 +1128,8 @@ namespace nana delete impl_; } + using item_type = drawerbase::menu::menu_item_type; + auto menu::append(std::string text_utf8, const menu::event_fn_t& handler) -> item_proxy { std::unique_ptr item{ new item_type{ std::move(text_utf8), handler } }; From d386400d1c302450ac20f25ec46192b123d04a9c Mon Sep 17 00:00:00 2001 From: Jinhao Date: Fri, 5 May 2017 04:47:43 +0800 Subject: [PATCH 7/9] fix issue that place may break the visibility of tab panels --- source/gui/place.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index ff446802..c0a4f972 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -632,13 +632,16 @@ namespace nana API::umake_event(e.evt_destroy); } - void visible(bool vsb) + void visible(bool vsb, bool sync_fastened = true) { for (auto & e : elements) API::show_window(e.handle, vsb); - for (auto & e : fastened) - API::show_window(e.handle, vsb); + if (sync_fastened) + { + for (auto & e : fastened) + API::show_window(e.handle, vsb); + } } static event_handle erase_element(std::vector& elements, window handle) noexcept @@ -2571,7 +2574,10 @@ namespace nana } } - field.second->visible(is_show); + //Collocate doesn't sync the visiblity of fastened windows. + //This is a feature that allows tabbar panels to be fastened to a same field, the collocate() + //shouldn't break the visibility of panels that are maintained by tabbar. + field.second->visible(is_show, false); } } } From 017630b22aa32d3829dfe88e92c42b0f25c646c4 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 6 May 2017 04:40:49 +0800 Subject: [PATCH 8/9] fix issue that menu wouldn't close window when destructs the menu --- source/gui/widgets/menu.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 76f367e0..dc78e98f 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1120,6 +1120,7 @@ namespace nana menu::~menu() { + this->close(); for(auto i = impl_->sub_container.rbegin(); i != impl_->sub_container.rend(); ++i) { if(i->second.kill) @@ -1141,7 +1142,7 @@ namespace nana { impl_->mbuilder.data().items.emplace_back(new item_type); } - + auto menu::insert(std::size_t pos, std::string text_utf8, const event_fn_t& handler) -> item_proxy { auto & items = impl_->mbuilder.data().items; From cbf76a312a3cda00a758a38c46f8ba6223b6c9c7 Mon Sep 17 00:00:00 2001 From: Jinhao Date: Sat, 6 May 2017 07:24:21 +0800 Subject: [PATCH 9/9] 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; }