diff options
Diffstat (limited to 'src/ui/controls/Control.cpp')
| -rw-r--r-- | src/ui/controls/Control.cpp | 148 |
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 |
