diff options
-rw-r--r-- | CruUI-Generate/cru_ui.cpp | 49 | ||||
-rw-r--r-- | CruUI-Generate/cru_ui.hpp | 14 | ||||
-rw-r--r-- | src/ui/control.cpp | 26 | ||||
-rw-r--r-- | src/ui/control.hpp | 2 | ||||
-rw-r--r-- | src/ui/window.cpp | 23 | ||||
-rw-r--r-- | src/ui/window.hpp | 12 |
6 files changed, 58 insertions, 68 deletions
diff --git a/CruUI-Generate/cru_ui.cpp b/CruUI-Generate/cru_ui.cpp index f2cd94d3..ecfeec7d 100644 --- a/CruUI-Generate/cru_ui.cpp +++ b/CruUI-Generate/cru_ui.cpp @@ -1005,6 +1005,30 @@ namespace cru::ui return false; } + Control* Control::HitTest(const Point& point) + { + const auto point_inside = IsPointInside(point); + + if (!point_inside && IsClipToPadding()) + return nullptr; // if clip then don't test children. + + const auto& children = GetChildren(); + + for (auto i = children.crbegin(); i != children.crend(); ++i) + { + const auto&& lefttop = (*i)->GetPositionRelative(); + const auto&& coerced_point = Point(point.x - lefttop.x, point.y - lefttop.y); + const auto child_hit_test_result = (*i)->HitTest(coerced_point); + if (child_hit_test_result != nullptr) + return child_hit_test_result; + } + + if (!point_inside) + return nullptr; + + return this; + } + void Control::SetClipToPadding(const bool clip) { if (clip_to_padding_ == clip) @@ -1179,7 +1203,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnAttachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } @@ -1191,7 +1214,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnDetachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } @@ -2242,7 +2264,8 @@ namespace cru::ui return new Window(tag_popup_constructor{}, parent, caption); } - Window::Window(tag_overlapped_constructor) : Control(WindowConstructorTag{}, this), control_list_({ this }) { + Window::Window(tag_overlapped_constructor) : Control(WindowConstructorTag{}, this) + { const auto window_manager = WindowManager::GetInstance(); hwnd_ = CreateWindowEx(0, @@ -2258,7 +2281,7 @@ namespace cru::ui AfterCreateHwnd(window_manager); } - Window::Window(tag_popup_constructor, Window* parent, const bool caption) : Control(WindowConstructorTag{}, this), control_list_({ this }) + Window::Window(tag_popup_constructor, Window* parent, const bool caption) : Control(WindowConstructorTag{}, this) { if (parent != nullptr && !parent->IsWindowValid()) throw std::runtime_error("Parent window is not valid."); @@ -2616,24 +2639,6 @@ namespace cru::ui is_layout_invalid_ = false; } - void Window::RefreshControlList() { - control_list_.clear(); - TraverseDescendants([this](Control* control) { - this->control_list_.push_back(control); - }); - } - - Control * Window::HitTest(const Point & point) - { - for (auto i = control_list_.crbegin(); i != control_list_.crend(); ++i) { - auto control = *i; - if (control->IsPointInside(control->WindowToControl(point))) { - return control; - } - } - return nullptr; - } - bool Window::RequestFocusFor(Control * control) { if (control == nullptr) diff --git a/CruUI-Generate/cru_ui.hpp b/CruUI-Generate/cru_ui.hpp index ab070ba1..62a2158a 100644 --- a/CruUI-Generate/cru_ui.hpp +++ b/CruUI-Generate/cru_ui.hpp @@ -597,7 +597,6 @@ namespace cru //-------------------------------------------------------- #include <map> -#include <list> #include <memory> //-------------------------------------------------------- @@ -1619,6 +1618,8 @@ namespace cru::ui // fill and stroke with width of border. virtual bool IsPointInside(const Point& point); + // Get the top control among all descendants (including self) in local coordinate. + Control* HitTest(const Point& point); //*************** region: graphic *************** @@ -2165,15 +2166,6 @@ namespace cru::ui void SetSizeFitContent(const Size& max_size = Size(1000, 1000)); - //*************** region: functions *************** - - //Refresh control list. - //It should be invoked every time a control is added or removed from the tree. - void RefreshControlList(); - - //Get the most top control at "point". - Control* HitTest(const Point& point); - //*************** region: focus *************** @@ -2277,8 +2269,6 @@ namespace cru::ui Window* parent_window_ = nullptr; std::shared_ptr<graph::WindowRenderTarget> render_target_{}; - std::list<Control*> control_list_{}; - Control* mouse_hover_control_ = nullptr; bool window_focus_ = false; diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 9afa5497..91b5aea3 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -211,6 +211,30 @@ namespace cru::ui return false; } + Control* Control::HitTest(const Point& point) + { + const auto point_inside = IsPointInside(point); + + if (!point_inside && IsClipToPadding()) + return nullptr; // if clip then don't test children. + + const auto& children = GetChildren(); + + for (auto i = children.crbegin(); i != children.crend(); ++i) + { + const auto&& lefttop = (*i)->GetPositionRelative(); + const auto&& coerced_point = Point(point.x - lefttop.x, point.y - lefttop.y); + const auto child_hit_test_result = (*i)->HitTest(coerced_point); + if (child_hit_test_result != nullptr) + return child_hit_test_result; + } + + if (!point_inside) + return nullptr; + + return this; + } + void Control::SetClipToPadding(const bool clip) { if (clip_to_padding_ == clip) @@ -385,7 +409,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnAttachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } @@ -397,7 +420,6 @@ namespace cru::ui child->TraverseDescendants([window](Control* control) { control->OnDetachToWindow(window); }); - window->RefreshControlList(); InvalidateLayout(); } } diff --git a/src/ui/control.hpp b/src/ui/control.hpp index 4374983b..6de7f450 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -121,6 +121,8 @@ namespace cru::ui // fill and stroke with width of border. virtual bool IsPointInside(const Point& point); + // Get the top control among all descendants (including self) in local coordinate. + Control* HitTest(const Point& point); //*************** region: graphic *************** diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 87656cdc..ceabddef 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -132,7 +132,8 @@ namespace cru::ui return new Window(tag_popup_constructor{}, parent, caption); } - Window::Window(tag_overlapped_constructor) : Control(WindowConstructorTag{}, this), control_list_({ this }) { + Window::Window(tag_overlapped_constructor) : Control(WindowConstructorTag{}, this) + { const auto window_manager = WindowManager::GetInstance(); hwnd_ = CreateWindowEx(0, @@ -148,7 +149,7 @@ namespace cru::ui AfterCreateHwnd(window_manager); } - Window::Window(tag_popup_constructor, Window* parent, const bool caption) : Control(WindowConstructorTag{}, this), control_list_({ this }) + Window::Window(tag_popup_constructor, Window* parent, const bool caption) : Control(WindowConstructorTag{}, this) { if (parent != nullptr && !parent->IsWindowValid()) throw std::runtime_error("Parent window is not valid."); @@ -506,24 +507,6 @@ namespace cru::ui is_layout_invalid_ = false; } - void Window::RefreshControlList() { - control_list_.clear(); - TraverseDescendants([this](Control* control) { - this->control_list_.push_back(control); - }); - } - - Control * Window::HitTest(const Point & point) - { - for (auto i = control_list_.crbegin(); i != control_list_.crend(); ++i) { - auto control = *i; - if (control->IsPointInside(control->WindowToControl(point))) { - return control; - } - } - return nullptr; - } - bool Window::RequestFocusFor(Control * control) { if (control == nullptr) diff --git a/src/ui/window.hpp b/src/ui/window.hpp index d98e60e2..a3fba57a 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -2,7 +2,6 @@ #include "system_headers.hpp" #include <map> -#include <list> #include <memory> #include "control.hpp" @@ -208,15 +207,6 @@ namespace cru::ui void SetSizeFitContent(const Size& max_size = Size(1000, 1000)); - //*************** region: functions *************** - - //Refresh control list. - //It should be invoked every time a control is added or removed from the tree. - void RefreshControlList(); - - //Get the most top control at "point". - Control* HitTest(const Point& point); - //*************** region: focus *************** @@ -320,8 +310,6 @@ namespace cru::ui Window* parent_window_ = nullptr; std::shared_ptr<graph::WindowRenderTarget> render_target_{}; - std::list<Control*> control_list_{}; - Control* mouse_hover_control_ = nullptr; bool window_focus_ = false; |