diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 8d75dc9e..446664fa 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -24,6 +24,9 @@ namespace nana { namespace detail { + void events_operation_register(event_handle); + void events_operation_cancel(event_handle); + class event_interface { public: @@ -38,8 +41,50 @@ namespace nana virtual event_interface* get_event() const = 0; }; - void events_operation_register(event_handle); - void events_operation_cancel(event_handle); + + struct docker_base + : public docker_interface + { + event_interface * event_ptr; + bool flag_deleted{ false }; + const bool unignorable; + + docker_base(event_interface*, bool unignorable_flag); + + detail::event_interface * get_event() const override; + }; + + class event_base + : public detail::event_interface + { + public: + ~event_base(); + + std::size_t length() const; + void clear() noexcept; + + void remove(event_handle evt) override; + protected: + //class emit_counter is a RAII helper for emitting count + //It is used for avoiding a try{}catch block which is required for some finial works when + //event handlers throw exceptions. + class emit_counter + { + public: + emit_counter(event_base*); + ~emit_counter(); + private: + event_base * const evt_; + }; + + //event_handle _m_emplace(::std::unique_ptr& docker_ptr, bool in_front); + event_handle _m_emplace(detail::docker_interface*, bool in_front); + protected: + unsigned emitting_count_{ 0 }; + bool deleted_flags_{ false }; + //std::unique_ptr>> dockers_; + std::vector * dockers_{ nullptr }; + }; }//end namespace detail /// base clase for all event argument types @@ -59,83 +104,32 @@ namespace nana /// the type of the members of general_events template - class basic_event : public detail::event_interface + class basic_event : public detail::event_base { public: using arg_reference = const typename std::remove_reference::type &; private: struct docker - : public detail::docker_interface + : public detail::docker_base { - basic_event * const event_ptr; std::function invoke; - bool flag_deleted{ false }; - bool unignorable{false}; - - docker(basic_event * s, std::function && ivk, bool unignorable_flag) - : event_ptr(s), invoke(std::move(ivk)), unignorable(unignorable_flag) + docker(basic_event * evt, std::function && ivk, bool unignorable_flag) + : docker_base(evt, unignorable_flag), invoke(std::move(ivk)) {} - docker(basic_event * s, const std::function & ivk, bool unignorable_flag) - : event_ptr(s), invoke(ivk), unignorable(unignorable_flag) + docker(basic_event * evt, const std::function & ivk, bool unignorable_flag) + : docker_base(evt, unignorable_flag), invoke(ivk) {} - - ~docker() - { - detail::events_operation_cancel(reinterpret_cast(this)); - } - - detail::event_interface * get_event() const override - { - return event_ptr; - } - }; - - //class emit_counter is a RAII helper for emitting count - //It is used for avoiding a try{}catch block which is required for some finial works when - //event handlers throw exceptions. - class emit_counter - { - public: - emit_counter(basic_event* evt) - : evt_{evt} - { - ++evt->emitting_count_; - } - - ~emit_counter() - { - if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_) - { - evt_->deleted_flags_ = false; - for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) - { - if (static_cast(i->get())->flag_deleted) - i = evt_->dockers_->erase(i); - else - ++i; - } - } - } - private: - basic_event * const evt_; }; public: - /// It will get called firstly, because it is set at the beginning of the chain. + /// Creates an event handler at the beginning of event chain template event_handle connect_front(Function && fn) - { - internal_scope_guard lock; - if (nullptr == dockers_) - dockers_.reset(new std::vector>); - + { using prototype = typename std::remove_reference::type; - std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), false)); - auto evt = reinterpret_cast(dck.get()); - dockers_->emplace(dockers_->begin(), std::move(dck)); - detail::events_operation_register(evt); - return evt; + + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), false), true); } event_handle connect(void (*fn)(arg_reference)) @@ -149,16 +143,9 @@ namespace nana template event_handle connect(Function && fn) { - internal_scope_guard lock; - if (nullptr == dockers_) - dockers_.reset(new std::vector>); - using prototype = typename std::remove_reference::type; - std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), false)); - auto evt = reinterpret_cast(dck.get()); - dockers_->emplace_back(std::move(dck)); - detail::events_operation_register(evt); - return evt; + + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), false), false); } /// It will not get called if stop_propagation() was called. @@ -171,26 +158,10 @@ namespace nana /// It will get called because it is unignorable. template event_handle connect_unignorable(Function && fn, bool in_front = false) - { - internal_scope_guard lock; - if (nullptr == dockers_) - dockers_.reset(new std::vector>); - + { using prototype = typename std::remove_reference::type; - std::unique_ptr dck(new docker(this, factory::value>::build(std::forward(fn)), true)); - auto evt = reinterpret_cast(dck.get()); - if (in_front) - dockers_->emplace(dockers_->begin(), std::move(dck)); - else - dockers_->emplace_back(std::move(dck)); - detail::events_operation_register(evt); - return evt; - } - std::size_t length() const - { - internal_scope_guard lock; - return (nullptr == dockers_ ? 0 : dockers_->size()); + return _m_emplace(new docker(this, factory::value>::build(std::forward(fn)), true), in_front); } void emit(arg_reference& arg) @@ -202,13 +173,13 @@ namespace nana emit_counter ec(this); auto& dockers = *dockers_; - const auto dockers_len = dockers.size(); + const auto dockers_len = dockers_->size(); //The dockers may resize when a new event handler is created by a calling handler. //Traverses with position can avaid crash error which caused by a iterator which becomes invalid. for (std::size_t pos = 0; pos < dockers_len; ++pos) { - auto docker_ptr = static_cast(dockers[pos].get()); + auto docker_ptr = static_cast(dockers[pos]); if (docker_ptr->flag_deleted) continue; @@ -217,7 +188,7 @@ namespace nana { for (++pos; pos < dockers_len; ++pos) { - auto docker_ptr = static_cast(dockers[pos].get()); + auto docker_ptr = static_cast(dockers[pos]); if (!docker_ptr->unignorable || docker_ptr->flag_deleted) continue; @@ -227,36 +198,6 @@ namespace nana } } } - - void clear() - { - internal_scope_guard lock; - if (dockers_) - dockers_.reset(); - } - - void remove(event_handle evt) override - { - internal_scope_guard lock; - if (dockers_) - { - for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) - { - if (reinterpret_cast(evt) == i->get()) - { - //Checks whether this event is working now. - if (emitting_count_ > 1) - { - static_cast(i->get())->flag_deleted = true; - deleted_flags_ = true; - } - else - dockers_->erase(i); - break; - } - } - } - } private: template struct factory @@ -413,10 +354,6 @@ namespace nana }; } }; - private: - unsigned emitting_count_{ 0 }; - bool deleted_flags_{ false }; - std::unique_ptr>> dockers_; }; struct arg_mouse @@ -427,12 +364,12 @@ namespace nana ::nana::point pos; ///< cursor position in the event window ::nana::mouse button; ///< indicates a button which triggers the event - bool left_button; ///< mouse left button is pressed? - bool mid_button; ///< mouse middle button is pressed? - bool right_button; ///< mouse right button is pressed? - bool alt; ///< keyboard alt is pressed? - bool shift; ///< keyboard Shift is pressed? - bool ctrl; ///< keyboard Ctrl is pressed? + bool left_button; ///< true if mouse left button is pressed + bool mid_button; ///< true if mouse middle button is pressed + bool right_button; ///< true if mouse right button is pressed + bool alt; ///< true if keyboard alt is pressed + bool shift; ///< true if keyboard Shift is pressed + bool ctrl; ///< true if keyboard Ctrl is pressed /// Checks if left button is operated, bool is_left_button() const @@ -481,7 +418,7 @@ namespace nana event_code evt_code; ///< it is event_code::key_press in current event ::nana::window window_handle; ///< A handle to the event window mutable wchar_t key; ///< the key corresponding to the key pressed - mutable bool ignore; ///< this member is not used + mutable bool ignore; ///< this member is only available for key_char event, set 'true' to ignore the input. bool ctrl; ///< keyboard Ctrl is pressed? bool shift; ///< keyboard Shift is pressed }; diff --git a/source/gui/detail/events_operation.cpp b/source/gui/detail/events_operation.cpp index 8877ebd1..bff546ca 100644 --- a/source/gui/detail/events_operation.cpp +++ b/source/gui/detail/events_operation.cpp @@ -42,5 +42,112 @@ namespace nana } } //end namespace events_operation + + + //class docker_base + docker_base::docker_base(event_interface* evt, bool unignorable_flag) + : event_ptr(evt), unignorable(unignorable_flag) + {} + + detail::event_interface * docker_base::get_event() const + { + return event_ptr; + } + //end class docker_base + + //class event_base + event_base::~event_base() + { + clear(); + } + + std::size_t event_base::length() const + { + internal_scope_guard lock; + return (nullptr == dockers_ ? 0 : dockers_->size()); + } + + void event_base::clear() noexcept + { + internal_scope_guard lock; + if (dockers_) + { + for (auto p : *dockers_) + { + detail::events_operation_cancel(reinterpret_cast(p)); + delete p; + } + dockers_->clear(); + + delete dockers_; + dockers_ = nullptr; + } + } + + void event_base::remove(event_handle evt) + { + internal_scope_guard lock; + if (dockers_) + { + + for (auto i = dockers_->begin(), end = dockers_->end(); i != end; ++i) + { + if (reinterpret_cast(evt) == *i) + { + //Checks whether this event is working now. + if (emitting_count_ > 1) + { + static_cast(*i)->flag_deleted = true; + deleted_flags_ = true; + } + else + dockers_->erase(i); + break; + } + } + } + } + + event_handle event_base::_m_emplace(detail::docker_interface* docker_ptr, bool in_front) + { + internal_scope_guard lock; + if (nullptr == dockers_) + dockers_ = new std::vector; + + auto evt = reinterpret_cast(docker_ptr); + + if (in_front) + dockers_->emplace(dockers_->begin(), docker_ptr); + else + dockers_->emplace_back(docker_ptr); + + detail::events_operation_register(evt); + return evt; + } + + //class emit_counter + event_base::emit_counter::emit_counter(event_base* evt) + : evt_{ evt } + { + ++evt->emitting_count_; + } + + event_base::emit_counter::~emit_counter() + { + if ((0 == --evt_->emitting_count_) && evt_->deleted_flags_) + { + evt_->deleted_flags_ = false; + for (auto i = evt_->dockers_->begin(); i != evt_->dockers_->end();) + { + if (static_cast(*i)->flag_deleted) + i = evt_->dockers_->erase(i); + else + ++i; + } + } + } + //end class emit_counter + //end class event_base + }//end namespace detail }//end namespace nana \ No newline at end of file