aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/base/Event.h19
-rw-r--r--include/cru/base/SelfResolvable.h153
-rw-r--r--include/cru/ui/components/Component.h5
-rw-r--r--include/cru/ui/controls/Control.h5
-rw-r--r--include/cru/ui/host/WindowHost.h2
-rw-r--r--src/platform/gui/win/Window.cpp5
-rw-r--r--src/ui/components/Menu.cpp5
-rw-r--r--src/ui/controls/Control.cpp4
-rw-r--r--src/ui/helper/ClickDetector.cpp4
-rw-r--r--src/ui/host/RoutedEventDispatch.h20
-rw-r--r--test/base/CMakeLists.txt1
-rw-r--r--test/base/SelfResolvableTest.cpp110
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);
-}