aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/controls/Control.h13
-rw-r--r--include/cru/ui/controls/Window.h33
-rw-r--r--src/ui/controls/Control.cpp17
-rw-r--r--src/ui/controls/Window.cpp33
4 files changed, 73 insertions, 23 deletions
diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h
index 684bc960..94de4cdc 100644
--- a/include/cru/ui/controls/Control.h
+++ b/include/cru/ui/controls/Control.h
@@ -1,12 +1,14 @@
#pragma once
#include "../Base.h"
#include "../DeleteLater.h"
+#include "../events/KeyEventArgs.h"
+#include "../events/MouseWheelEventArgs.h"
#include "../events/UiEvents.h"
+#include "../render/MeasureRequirement.h"
#include "../render/RenderObject.h"
#include "../style/StyleRuleSet.h"
-#include "cru/ui/events/KeyEventArgs.h"
-#include "cru/ui/events/MouseWheelEventArgs.h"
-#include "cru/ui/render/MeasureRequirement.h"
+
+#include <cru/base/SelfResolvable.h>
namespace cru::ui::controls {
@@ -19,7 +21,9 @@ 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 DeleteLaterImpl {
+class CRU_UI_API Control : public Object,
+ public DeleteLaterImpl,
+ public SelfResolvable<Control> {
friend class RootControl;
CRU_DEFINE_CLASS_LOG_TAG("Control")
@@ -41,6 +45,7 @@ class CRU_UI_API Control : public Object, public DeleteLaterImpl {
Control* GetParent() const { return parent_; }
void SetParent(Control* parent);
+ bool HasAncestor(Control* control);
virtual void ForEachChild(const std::function<void(Control*)>& predicate) = 0;
diff --git a/include/cru/ui/controls/Window.h b/include/cru/ui/controls/Window.h
index e25694ba..88320219 100644
--- a/include/cru/ui/controls/Window.h
+++ b/include/cru/ui/controls/Window.h
@@ -13,6 +13,8 @@ namespace cru::ui::controls {
class CRU_UI_API Window
: public LayoutControl<render::StackLayoutRenderObject> {
CRU_DEFINE_CLASS_LOG_TAG("cru::ui::controls::Window")
+ friend Control;
+
public:
static constexpr std::string_view kControlType = "Window";
@@ -58,7 +60,6 @@ class CRU_UI_API Window
void SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor);
bool IsInEventHandling();
- void UpdateCursor();
CRU_DEFINE_EVENT(AfterLayout, std::nullptr_t)
@@ -104,7 +105,8 @@ class CRU_UI_API Window
if (original_sender == nullptr || original_sender == last_receiver) return;
std::string log = "Begin dispatching routed event " +
- (original_sender->*event_ptr)()->GetName() + ":\n\tTunnel:";
+ (original_sender->*event_ptr)()->GetName() +
+ ":\n\tTunnel:";
Guard logging_guard([&] {
log += "\nEnd dispatching routed event " +
@@ -112,11 +114,11 @@ class CRU_UI_API Window
CRU_LOG_TAG_DEBUG("{}", log);
});
- std::vector<Control*> receive_list;
+ std::vector<ObjectResolver<Control>> receive_list;
auto parent = original_sender;
while (parent != last_receiver) {
- receive_list.push_back(parent);
+ receive_list.push_back(parent->CreateResolver());
parent = parent->GetParent();
}
@@ -124,8 +126,12 @@ class CRU_UI_API Window
// tunnel
for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) {
- auto control = *i;
+ auto control = i->Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -140,8 +146,13 @@ class CRU_UI_API Window
// bubble
if (!handled) {
log += "\n\tBubble:";
- for (auto control : receive_list) {
+ for (auto resolver : receive_list) {
+ auto control = resolver.Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -155,8 +166,13 @@ class CRU_UI_API Window
log += "\n\tDirect:";
// direct
- for (auto control : receive_list) {
+ for (auto resolver : receive_list) {
+ auto control = resolver.Resolve();
log += " ";
+ if (!control) {
+ log += "(deleted)";
+ continue;
+ }
log += control->GetDebugId();
EventArgs event_args(control, original_sender,
std::forward<Args>(args)...);
@@ -164,6 +180,9 @@ class CRU_UI_API Window
}
}
+ void UpdateCursor();
+ void NotifyControlDestroyed(Control* control);
+
private:
int event_handling_count_;
diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp
index e903b5b3..9c0fc537 100644
--- a/src/ui/controls/Control.cpp
+++ b/src/ui/controls/Control.cpp
@@ -1,4 +1,5 @@
#include "cru/ui/controls/Control.h"
+#include "cru/base/log/Logger.h"
#include "cru/ui/controls/Window.h"
#include "cru/platform/gui/Cursor.h"
@@ -27,11 +28,14 @@ Control::Control() {
Control::~Control() {
if (auto window = GetWindow()) {
if (window->IsInEventHandling()) {
- // Don't delete control during event handling. Use DeleteLater.
- std::terminate();
+ CRU_LOG_TAG_WARN(
+ "Better use delete later to delete control during event handling.");
}
}
+ if (auto window = GetWindow()) {
+ window->NotifyControlDestroyed(this);
+ }
RemoveFromParent();
}
@@ -58,6 +62,15 @@ void Control::SetParent(Control* parent) {
OnParentChanged(old_parent, parent);
}
+bool Control::HasAncestor(Control* control) {
+ auto parent = this;
+ while (parent) {
+ if (parent == control) return true;
+ parent = parent->GetParent();
+ }
+ return false;
+}
+
void Control::RemoveFromParent() {
if (parent_) {
parent_->RemoveChild(this);
diff --git a/src/ui/controls/Window.cpp b/src/ui/controls/Window.cpp
index e6abc48d..c82b2485 100644
--- a/src/ui/controls/Window.cpp
+++ b/src/ui/controls/Window.cpp
@@ -265,16 +265,6 @@ void Window::SetOverrideCursor(std::shared_ptr<platform::gui::ICursor> cursor) {
bool Window::IsInEventHandling() { return event_handling_count_; }
-void Window::UpdateCursor() {
- if (override_cursor_) {
- native_window_->SetCursor(override_cursor_);
- } else {
- const auto capture = GetMouseCaptureControl();
- native_window_->SetCursor(
- (capture ? capture : GetMouseHoverControl())->GetInheritedCursor());
- }
-}
-
void Window::OnNativeDestroy(platform::gui::INativeWindow* window,
std::nullptr_t) {
CRU_UNUSED(window)
@@ -428,4 +418,27 @@ void Window::DispatchMouseHoverControlChangeEvent(Control* old_control,
}
}
+void Window::UpdateCursor() {
+ if (override_cursor_) {
+ native_window_->SetCursor(override_cursor_);
+ } else {
+ const auto capture = GetMouseCaptureControl();
+ native_window_->SetCursor(
+ (capture ? capture : GetMouseHoverControl())->GetInheritedCursor());
+ }
+}
+
+void Window::NotifyControlDestroyed(Control* control) {
+ if (focus_control_->HasAncestor(control)) {
+ focus_control_ = control->GetParent();
+ }
+
+ if (mouse_captured_control_->HasAncestor(control)) {
+ mouse_captured_control_ = control->GetParent();
+ }
+
+ if (mouse_hover_control_->HasAncestor(control)) {
+ mouse_hover_control_ = control->GetParent();
+ }
+}
} // namespace cru::ui::controls