aboutsummaryrefslogtreecommitdiff
path: root/src/ui/controls/Control.cpp
diff options
context:
space:
mode:
authorYuqian Yang <crupest@crupest.life>2025-11-18 00:46:27 +0800
committerYuqian Yang <crupest@crupest.life>2025-11-18 00:46:27 +0800
commit6b4edc9be8ec556147c195cf2047d92b9439efd7 (patch)
treea1d7b7d1e821b4e1911fd00761f77a24ee483f4a /src/ui/controls/Control.cpp
parentf7c4d19df66c602d74795e98ce2ee4390d06fbb4 (diff)
downloadcru-6b4edc9be8ec556147c195cf2047d92b9439efd7.tar.gz
cru-6b4edc9be8ec556147c195cf2047d92b9439efd7.tar.bz2
cru-6b4edc9be8ec556147c195cf2047d92b9439efd7.zip
Bring back ControlHost and refactor tree management of control.
Diffstat (limited to 'src/ui/controls/Control.cpp')
-rw-r--r--src/ui/controls/Control.cpp148
1 files changed, 94 insertions, 54 deletions
diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp
index 9c0fc537..02148b72 100644
--- a/src/ui/controls/Control.cpp
+++ b/src/ui/controls/Control.cpp
@@ -1,11 +1,12 @@
#include "cru/ui/controls/Control.h"
+#include "cru/base/Base.h"
#include "cru/base/log/Logger.h"
-#include "cru/ui/controls/Window.h"
-
#include "cru/platform/gui/Cursor.h"
#include "cru/platform/gui/UiApplication.h"
+#include "cru/ui/controls/ControlHost.h"
#include "cru/ui/style/StyleRuleSet.h"
+#include <algorithm>
#include <format>
namespace cru::ui::controls {
@@ -17,25 +18,14 @@ Control::Control() {
style_rule_set_ = std::make_shared<style::StyleRuleSet>();
style_rule_set_bind_ =
std::make_unique<style::StyleRuleSetBind>(this, style_rule_set_);
-
- MouseEnterEvent()->Direct()->AddHandler(
- [this](events::MouseEventArgs&) { this->is_mouse_over_ = true; });
-
- MouseLeaveEvent()->Direct()->AddHandler(
- [this](events::MouseEventArgs&) { this->is_mouse_over_ = false; });
}
Control::~Control() {
- if (auto window = GetWindow()) {
- if (window->IsInEventHandling()) {
- CRU_LOG_TAG_WARN(
- "Better use delete later to delete control during event handling.");
- }
+ if (host_ && host_->IsInEventHandling()) {
+ CRU_LOG_TAG_WARN(
+ "Better use delete later to delete control during event handling.");
}
- if (auto window = GetWindow()) {
- window->NotifyControlDestroyed(this);
- }
RemoveFromParent();
}
@@ -44,23 +34,9 @@ std::string Control::GetDebugId() const {
static_cast<const void*>(this));
}
-Window* Control::GetWindow() {
- auto parent = this;
- while (parent) {
- if (auto window = dynamic_cast<Window*>(parent)) {
- return window;
- }
- parent = parent->GetParent();
- }
- return nullptr;
-}
+ControlHost* Control::GetControlHost() { return host_; }
-void Control::SetParent(Control* parent) {
- if (parent_ == parent) return;
- auto old_parent = parent_;
- parent_ = parent;
- OnParentChanged(old_parent, parent);
-}
+Control* Control::GetParent() { return parent_; }
bool Control::HasAncestor(Control* control) {
auto parent = this;
@@ -71,6 +47,21 @@ bool Control::HasAncestor(Control* control) {
return false;
}
+const std::vector<Control*>& Control::GetChildren() { return children_; }
+
+void Control::RemoveChild(Control* child) {
+ auto iter = std::ranges::find(children_, child);
+ if (iter != children_.cend()) {
+ RemoveChildAt(iter - children_.cbegin());
+ }
+}
+
+void Control::RemoveAllChild() {
+ while (!GetChildren().empty()) {
+ RemoveChildAt(GetChildren().size() - 1);
+ }
+}
+
void Control::RemoveFromParent() {
if (parent_) {
parent_->RemoveChild(this);
@@ -87,39 +78,85 @@ controls::Control* Control::HitTest(const Point& point) {
return nullptr;
}
-bool Control::HasFocus() {
- auto window = GetWindow();
- if (window == nullptr) return false;
+void Control::InsertChildAt(Control* control, Index index) {
+ if (index < 0 || index > children_.size()) {
+ throw Exception("Child control index out of range.");
+ }
+
+ if (control->parent_) {
+ throw Exception("Control already has a parent.");
+ }
+
+ children_.insert(children_.cbegin() + index, control);
+ control->parent_ = this;
+
+ TraverseDescendents([this](Control* control) { control->host_ = host_; },
+ false);
+ if (host_) {
+ host_->NotifyControlParentChange(control, nullptr, this);
+ }
+ control->OnParentChanged(nullptr, this);
+ OnChildInserted(control, index);
- return window->GetFocusControl() == this;
+ if (host_) {
+ host_->InvalidateLayout();
+ }
}
-bool Control::CaptureMouse() {
- auto window = GetWindow();
- if (window == nullptr) return false;
+void Control::RemoveChildAt(Index index) {
+ if (index < 0 || index >= children_.size()) {
+ throw Exception("Child control index out of range.");
+ }
+
+ auto control = children_[index];
+ children_.erase(children_.cbegin() + index);
+ control->parent_ = nullptr;
+ TraverseDescendents([this](Control* control) { control->host_ = nullptr; },
+ false);
+ if (host_) {
+ host_->NotifyControlParentChange(control, this, nullptr);
+ }
+ control->OnParentChanged(this, nullptr);
+ OnChildRemoved(control, index);
- return window->SetMouseCaptureControl(this);
+ if (host_) {
+ host_->InvalidateLayout();
+ }
+}
+
+void Control::AddChild(Control* control) {
+ InsertChildAt(control, GetChildren().size());
+}
+
+bool Control::HasFocus() {
+ if (!host_) return false;
+ return host_->GetFocusControl() == this;
}
void Control::SetFocus() {
- auto window = GetWindow();
- if (window == nullptr) return;
+ if (!host_) return;
+ host_->SetFocusControl(this);
+}
- window->SetFocusControl(this);
+bool Control::IsMouseOver() {
+ if (!host_) return false;
+ return host_->GetMouseHoverControl() == this;
+}
+
+bool Control::CaptureMouse() {
+ if (!host_) return false;
+ return host_->SetMouseCaptureControl(this);
}
bool Control::ReleaseMouse() {
- auto window = GetWindow();
- if (window == nullptr) return false;
- if (window->GetMouseCaptureControl() != this) return false;
- return window->SetMouseCaptureControl(nullptr);
+ if (!host_) return false;
+ if (!IsMouseCaptured()) return false;
+ return host_->SetMouseCaptureControl(nullptr);
}
bool Control::IsMouseCaptured() {
- auto window = GetWindow();
- if (window == nullptr) return false;
-
- return window->GetMouseCaptureControl() == this;
+ if (!host_) return false;
+ return host_->GetMouseCaptureControl() == this;
}
std::shared_ptr<ICursor> Control::GetCursor() { return cursor_; }
@@ -137,13 +174,16 @@ std::shared_ptr<ICursor> Control::GetInheritedCursor() {
void Control::SetCursor(std::shared_ptr<ICursor> cursor) {
cursor_ = std::move(cursor);
- const auto window = GetWindow();
- if (window != nullptr) {
- window->UpdateCursor();
+ if (host_) {
+ host_->UpdateCursor();
}
}
std::shared_ptr<style::StyleRuleSet> Control::GetStyleRuleSet() {
return style_rule_set_;
}
+
+void Control::OnParentChanged(Control* old_parent, Control* new_parent) {}
+void Control::OnChildInserted(Control* control, Index index) {}
+void Control::OnChildRemoved(Control* control, Index index) {}
} // namespace cru::ui::controls