diff options
| -rw-r--r-- | include/cru/base/Event.h | 19 | ||||
| -rw-r--r-- | include/cru/base/SelfResolvable.h | 153 | ||||
| -rw-r--r-- | include/cru/ui/components/Component.h | 5 | ||||
| -rw-r--r-- | include/cru/ui/controls/Control.h | 5 | ||||
| -rw-r--r-- | include/cru/ui/host/WindowHost.h | 2 | ||||
| -rw-r--r-- | src/platform/gui/win/Window.cpp | 5 | ||||
| -rw-r--r-- | src/ui/components/Menu.cpp | 5 | ||||
| -rw-r--r-- | src/ui/controls/Control.cpp | 4 | ||||
| -rw-r--r-- | src/ui/helper/ClickDetector.cpp | 4 | ||||
| -rw-r--r-- | src/ui/host/RoutedEventDispatch.h | 20 | ||||
| -rw-r--r-- | test/base/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | test/base/SelfResolvableTest.cpp | 110 |
12 files changed, 20 insertions, 313 deletions
diff --git a/include/cru/base/Event.h b/include/cru/base/Event.h index 226c2ea4..276c313f 100644 --- a/include/cru/base/Event.h +++ b/include/cru/base/Event.h @@ -1,8 +1,6 @@ #pragma once #include "Base.h" -#include "SelfResolvable.h" - #include <algorithm> #include <cassert> #include <functional> @@ -13,7 +11,7 @@ namespace cru { class EventHandlerRevoker; -class EventBase : public Object, public SelfResolvable<EventBase> { +class EventBase : public Object { friend EventHandlerRevoker; public: @@ -36,28 +34,23 @@ class EventHandlerRevoker { friend EventBase; private: - EventHandlerRevoker(ObjectResolver<EventBase>&& resolver, - EventBase::EventHandlerToken token) - : resolver_(std::move(resolver)), token_(token) {} + EventHandlerRevoker(EventBase* event, EventBase::EventHandlerToken token) + : event_(event), token_(token) {} public: /** * Revoke the registered handler. If the event has already been destroyed or * the handler is already revoked, nothing will be done. */ - void operator()() const { - if (const auto event = resolver_.Resolve()) { - event->RemoveHandler(token_); - } - } + void operator()() const { event_->RemoveHandler(token_); } private: - ObjectResolver<EventBase> resolver_; + EventBase* event_; EventBase::EventHandlerToken token_; }; inline EventHandlerRevoker EventBase::CreateRevoker(EventHandlerToken token) { - return EventHandlerRevoker(CreateResolver(), token); + return EventHandlerRevoker(this, token); } struct IBaseEvent : public virtual Interface { diff --git a/include/cru/base/SelfResolvable.h b/include/cru/base/SelfResolvable.h deleted file mode 100644 index 84fa54f6..00000000 --- a/include/cru/base/SelfResolvable.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -#include <cassert> -#include <functional> -#include <memory> -#include <type_traits> - -namespace cru { -template <typename T> -class SelfResolvable; - -template <typename T> -class ObjectResolver { - friend SelfResolvable<T>; - template <typename U> - friend class ObjectResolver; - - private: - template <typename U> - using Accessor_ = std::function<U*(const std::shared_ptr<void*>&)>; - using ThisAccessor_ = Accessor_<T>; - - explicit ObjectResolver(T* o) - : shared_object_ptr_(new void*(o)), - accessor_([](const std::shared_ptr<void*>& ptr) { - return static_cast<T*>(*ptr); - }) {} - explicit ObjectResolver(std::shared_ptr<void*> ptr, ThisAccessor_ accessor) - : shared_object_ptr_(std::move(ptr)), accessor_(std::move(accessor)) {} - - template <typename U> - static ThisAccessor_ CreateAccessor(Accessor_<U> parent_accessor) { - return [parent_accessor = - std::move(parent_accessor)](const std::shared_ptr<void*>& ptr) { - return static_cast<T*>(parent_accessor(ptr)); - }; - } - - public: - template <typename U, - typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> - ObjectResolver(const ObjectResolver<U>& other) - : shared_object_ptr_(other.shared_object_ptr_), - accessor_(CreateAccessor(other.accessor_)) {} - - template <typename U, - typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> - ObjectResolver(ObjectResolver<U>&& other) - : shared_object_ptr_(std::move(other.shared_object_ptr_)), - accessor_(CreateAccessor(std::move(other.accessor_))) {} - - ObjectResolver(const ObjectResolver&) = default; - ObjectResolver& operator=(const ObjectResolver&) = default; - ObjectResolver(ObjectResolver&&) = default; - ObjectResolver& operator=(ObjectResolver&&) = default; - ~ObjectResolver() = default; - - template <typename U, - typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> - ObjectResolver& operator=(const ObjectResolver<U>& other) { - if (this != &other) { - this->shared_object_ptr_ = other.shared_object_ptr_; - this->accessor_ = CreateAccessor(other.accessor_); - } - return *this; - } - - template <typename U, - typename = std::enable_if_t<std::is_convertible_v<U*, T*>>> - ObjectResolver& operator=(ObjectResolver<U>&& other) { - if (this != &other) { - this->shared_object_ptr_ = std::move(other.shared_object_ptr_); - this->accessor_ = CreateAccessor(std::move(other.shared_object_ptr_)); - } - return *this; - } - - bool IsValid() const { return this->shared_object_ptr_ != nullptr; } - - T* Resolve() const { - assert(IsValid()); - return this->accessor_(this->shared_object_ptr_); - } - - /** - * @remarks So this class can be used as a functor. - */ - T* operator()() const { return Resolve(); } - - template <typename U, - typename = std::enable_if_t<std::is_convertible_v<T*, U*>>> - operator ObjectResolver<U>() const { - return ObjectResolver<U>(*this); - } - - private: - void SetResolvedObject(T* o) { - assert(IsValid()); - *this->shared_object_ptr_ = o; - } - - private: - std::shared_ptr<void*> shared_object_ptr_; - std::function<T*(const std::shared_ptr<void*>&)> accessor_; -}; - -/** - * @remarks - * This class is not copyable and movable since subclass is polymorphic and - * copying is then nonsense. However, you can even delete move capability in - * subclass because it may also be nonsense for subclass. The move capability is - * optional. - * - * Whether this class needs to be thread-safe still has to be considered. - */ -template <typename T> -class SelfResolvable { - public: - SelfResolvable() : resolver_(CastToSubClass()) {} - SelfResolvable(const SelfResolvable&) = delete; - SelfResolvable& operator=(const SelfResolvable&) = delete; - - // Resolvers to old object will resolve to new object. - SelfResolvable(SelfResolvable&& other) - : resolver_(std::move(other.resolver_)) { - this->resolver_.SetResolvedObject(CastToSubClass()); - } - - // Old resolvers for this object will resolve to nullptr. - // Other's resolvers will now resolve to this. - SelfResolvable& operator=(SelfResolvable&& other) { - if (this != &other) { - this->resolver_ = std::move(other.resolver_); - this->resolver_.SetResolvedObject(CastToSubClass()); - } - return *this; - } - - virtual ~SelfResolvable() { - if (this->resolver_.IsValid()) { - this->resolver_.SetResolvedObject(nullptr); - } - } - - ObjectResolver<T> CreateResolver() { return resolver_; } - - private: - T* CastToSubClass() { return static_cast<T*>(this); } - - private: - ObjectResolver<T> resolver_; -}; -} // namespace cru diff --git a/include/cru/ui/components/Component.h b/include/cru/ui/components/Component.h index d44e6728..627e2d3c 100644 --- a/include/cru/ui/components/Component.h +++ b/include/cru/ui/components/Component.h @@ -1,7 +1,6 @@ #pragma once #include "../Base.h" #include "../DeleteLater.h" -#include "cru/base/SelfResolvable.h" namespace cru::ui::components { /** @@ -9,9 +8,7 @@ namespace cru::ui::components { * \remarks Component should respect children's Component::IsDeleteByParent * value and decide whether to delete it. */ -class CRU_UI_API Component : public Object, - public SelfResolvable<Component>, - public DeleteLaterImpl { +class CRU_UI_API Component : public Object, public DeleteLaterImpl { public: Component() = default; ~Component() = default; diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h index d70854fe..77f5f392 100644 --- a/include/cru/ui/controls/Control.h +++ b/include/cru/ui/controls/Control.h @@ -4,7 +4,6 @@ #include "../events/UiEvents.h" #include "../render/RenderObject.h" #include "../style/StyleRuleSet.h" -#include "cru/base/SelfResolvable.h" #include "cru/ui/render/MeasureRequirement.h" namespace cru::ui::controls { @@ -18,9 +17,7 @@ namespace cru::ui::controls { * - RemoveChild(Control* child) * The last two methods are totally for convenient control tree management. */ -class CRU_UI_API Control : public Object, - public SelfResolvable<Control>, - public DeleteLaterImpl { +class CRU_UI_API Control : public Object, public DeleteLaterImpl { friend class RootControl; CRU_DEFINE_CLASS_LOG_TAG("Control") diff --git a/include/cru/ui/host/WindowHost.h b/include/cru/ui/host/WindowHost.h index 58fd120d..13b06b07 100644 --- a/include/cru/ui/host/WindowHost.h +++ b/include/cru/ui/host/WindowHost.h @@ -16,7 +16,7 @@ class LayoutPaintCycler; struct AfterLayoutEventArgs {}; // The bridge between control tree and native window. -class CRU_UI_API WindowHost : public Object, public SelfResolvable<WindowHost> { +class CRU_UI_API WindowHost : public Object { friend controls::Control; CRU_DEFINE_CLASS_LOG_TAG("WindowHost") diff --git a/src/platform/gui/win/Window.cpp b/src/platform/gui/win/Window.cpp index 95c840c3..5046868e 100644 --- a/src/platform/gui/win/Window.cpp +++ b/src/platform/gui/win/Window.cpp @@ -210,9 +210,8 @@ Point WinNativeWindow::GetMousePosition() { POINT p; if (!::GetCursorPos(&p)) throw Win32Error(::GetLastError(), "Failed to get cursor position."); - if (!::ScreenToClient(hwnd_, &p)) - throw Win32Error(::GetLastError(), "Failed to call ScreenToClient."); - return PixelToDip(p); + auto point = PixelToDip(p); + return point - client_rect_.GetLeftTop(); } bool WinNativeWindow::CaptureMouse() { diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp index fa594399..65c1e810 100644 --- a/src/ui/components/Menu.cpp +++ b/src/ui/components/Menu.cpp @@ -79,10 +79,7 @@ void Menu::AddTextItemAt(std::string text, Index index, PopupMenu::PopupMenu(controls::Control* attached_control) : attached_control_(attached_control), popup_(attached_control) { - menu_.SetOnItemClick([resolver = CreateResolver()](Index) { - auto t = static_cast<PopupMenu*>(resolver.Resolve()); - if (t) t->popup_.GetNativeWindow()->Close(); - }); + menu_.SetOnItemClick([this](Index) { popup_.GetNativeWindow()->Close(); }); popup_.AddChildAt(menu_.GetRootControl(), 0); } diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp index 14397fa7..cf0cc11f 100644 --- a/src/ui/controls/Control.cpp +++ b/src/ui/controls/Control.cpp @@ -27,10 +27,6 @@ Control::Control() { } Control::~Control() { - if (host::WindowHost::IsInEventHandling()) { - std::terminate(); - } - in_destruction_ = true; RemoveFromParent(); } diff --git a/src/ui/helper/ClickDetector.cpp b/src/ui/helper/ClickDetector.cpp index cf219db0..796c3ad4 100644 --- a/src/ui/helper/ClickDetector.cpp +++ b/src/ui/helper/ClickDetector.cpp @@ -77,12 +77,10 @@ ClickDetector::ClickDetector(controls::Control* control) { button == button_) { if (this->state_ == ClickState::Press) { this->SetState(ClickState::Hover); - auto resolver = this->control_->CreateResolver(); this->event_.Raise(ClickEventArgs{this->control_, this->down_point_, args.GetPoint(), button}); - auto c = resolver.Resolve(); - if (c) c->ReleaseMouse(); + this->control_->ReleaseMouse(); } else if (this->state_ == ClickState::PressInactive) { this->SetState(ClickState::None); this->control_->ReleaseMouse(); diff --git a/src/ui/host/RoutedEventDispatch.h b/src/ui/host/RoutedEventDispatch.h index 0729d176..6e8b4af1 100644 --- a/src/ui/host/RoutedEventDispatch.h +++ b/src/ui/host/RoutedEventDispatch.h @@ -1,5 +1,4 @@ #pragma once -#include "cru/base/SelfResolvable.h" #include "cru/base/log/Logger.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" @@ -43,11 +42,11 @@ void DispatchEvent( WindowHost::EnterEventHandling(); - std::vector<ObjectResolver<controls::Control>> receive_list; + std::vector<controls::Control*> receive_list; auto parent = original_sender; while (parent != last_receiver) { - receive_list.push_back(parent->CreateResolver()); + receive_list.push_back(parent); auto p = parent->GetParent(); assert(!(p == nullptr && last_receiver != nullptr)); parent = p; @@ -60,10 +59,10 @@ void DispatchEvent( auto i = receive_list.crbegin(); const auto end = --receive_list.crend(); for (; i != end; ++i) { - log += i->Resolve()->GetControlType(); + log += (*i)->GetControlType(); log += " -> "; } - log += i->Resolve()->GetControlType(); + log += (*i)->GetControlType(); CRU_LOG_TAG_DEBUG("{}", log); } @@ -74,8 +73,7 @@ void DispatchEvent( // tunnel for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { count++; - auto control = i->Resolve(); - if (!control) continue; + auto control = *i; EventArgs event_args(control, original_sender, std::forward<Args>(args)...); static_cast<Event<EventArgs&>*>((control->*event_ptr)()->Tunnel()) ->Raise(event_args); @@ -92,10 +90,8 @@ void DispatchEvent( // bubble if (!handled) { - for (const auto& resolver : receive_list) { + for (auto control : receive_list) { count--; - auto control = resolver.Resolve(); - if (!control) continue; EventArgs event_args(control, original_sender, std::forward<Args>(args)...); static_cast<Event<EventArgs&>*>((control->*event_ptr)()->Bubble()) @@ -112,9 +108,7 @@ void DispatchEvent( } // direct - for (auto resolver : receive_list) { - auto control = resolver.Resolve(); - if (!control) continue; + for (auto control : receive_list) { EventArgs event_args(control, original_sender, std::forward<Args>(args)...); static_cast<Event<EventArgs&>*>((control->*event_ptr)()->Direct()) ->Raise(event_args); diff --git a/test/base/CMakeLists.txt b/test/base/CMakeLists.txt index 52f61a8c..6bae85d7 100644 --- a/test/base/CMakeLists.txt +++ b/test/base/CMakeLists.txt @@ -1,7 +1,6 @@ add_executable(CruBaseTest EventTest.cpp PropertyTreeTest.cpp - SelfResolvableTest.cpp StringUtilTest.cpp SubProcessTest.cpp TimerTest.cpp diff --git a/test/base/SelfResolvableTest.cpp b/test/base/SelfResolvableTest.cpp deleted file mode 100644 index c214bd77..00000000 --- a/test/base/SelfResolvableTest.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "cru/base/Base.h" -#include "cru/base/SelfResolvable.h" - -#include <catch2/catch_test_macros.hpp> - -#include <memory> - -namespace { -class SelfResolvableTestClassBase { - public: - SelfResolvableTestClassBase() = default; - CRU_DELETE_COPY(SelfResolvableTestClassBase) - CRU_DEFAULT_MOVE(SelfResolvableTestClassBase) - virtual ~SelfResolvableTestClassBase() = default; -}; - -class SelfResolvableTestClass - : public SelfResolvableTestClassBase, - public cru::SelfResolvable<SelfResolvableTestClass> { - public: - SelfResolvableTestClass() : ptr_(new int(123)) {} - CRU_DELETE_COPY(SelfResolvableTestClass) - CRU_DEFAULT_MOVE(SelfResolvableTestClass) - ~SelfResolvableTestClass() override = default; - - private: - std::shared_ptr<int> ptr_; -}; -} // namespace - -TEST_CASE("SelfResolvable resolver should work.", "[self-resolvable]") { - SelfResolvableTestClass test_object; - - auto resolver = test_object.CreateResolver(); - REQUIRE(resolver.Resolve() == &test_object); - - auto resolver_copy = resolver; - REQUIRE(resolver.Resolve() == &test_object); - REQUIRE(resolver.Resolve() == &test_object); - - auto resolver_move = std::move(resolver_copy); - REQUIRE(resolver.Resolve() == &test_object); - REQUIRE(resolver_copy.IsValid() == false); - REQUIRE(resolver_move.Resolve() == &test_object); -} - -TEST_CASE("SelfResolvable object destructed should work.", - "[self-resolvable]") { - SelfResolvableTestClass* test_object = new SelfResolvableTestClass(); - - auto resolver = test_object->CreateResolver(); - auto resolver_copy = resolver; - - delete test_object; - - REQUIRE(resolver.Resolve() == nullptr); - REQUIRE(resolver_copy.Resolve() == nullptr); - - auto resolver_copy2 = resolver_copy; - REQUIRE(resolver_copy2.Resolve() == nullptr); - - auto resolver_move = std::move(resolver_copy); - REQUIRE(resolver_copy.IsValid() == false); - REQUIRE(resolver_move.Resolve() == nullptr); -} - -TEST_CASE("SelfResolvable object moved should work.", "[self-resolvable]") { - SelfResolvableTestClass test_object; - - auto resolver = test_object.CreateResolver(); - auto resolver_copy = resolver; - - SelfResolvableTestClass moved_object = std::move(test_object); - - REQUIRE(resolver.Resolve() == &moved_object); - REQUIRE(resolver_copy.Resolve() == &moved_object); - - auto resolver_copy2 = resolver_copy; - REQUIRE(resolver_copy2.Resolve() == &moved_object); - - auto resolver_move = std::move(resolver_copy); - REQUIRE(resolver_copy.IsValid() == false); - REQUIRE(resolver_move.Resolve() == &moved_object); -} - -TEST_CASE("SelfResolvable should work for casted type.", "[self-resolvable]") { - auto test_object = new SelfResolvableTestClass(); - - cru::ObjectResolver<SelfResolvableTestClassBase> base_resolver = - test_object->CreateResolver(); - - REQUIRE(base_resolver.Resolve() == test_object); - - auto base_resolver2 = base_resolver; - REQUIRE(base_resolver2.Resolve() == test_object); - - auto base_resolver3 = std::move(base_resolver2); - REQUIRE(base_resolver3.Resolve() == test_object); - - auto moved_object = new SelfResolvableTestClass(std::move(*test_object)); - delete test_object; - - REQUIRE(base_resolver.Resolve() == moved_object); - REQUIRE(base_resolver3.Resolve() == moved_object); - - delete moved_object; - - REQUIRE(base_resolver.Resolve() == nullptr); - REQUIRE(base_resolver3.Resolve() == nullptr); -} |
