diff options
author | crupest <crupest@outlook.com> | 2019-03-20 17:31:22 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-03-20 17:31:22 +0800 |
commit | 62080f78c900aa41e456aa37a1825310121de881 (patch) | |
tree | 531bac647b55ac084fc18f3037f988540d251dcb | |
parent | 1e3cad155a234d2e3e9b6aca650d4d1c4c9e8d4e (diff) | |
download | cru-62080f78c900aa41e456aa37a1825310121de881.tar.gz cru-62080f78c900aa41e456aa37a1825310121de881.tar.bz2 cru-62080f78c900aa41e456aa37a1825310121de881.zip |
...
-rw-r--r-- | CruUI.vcxproj | 4 | ||||
-rw-r--r-- | CruUI.vcxproj.filters | 12 | ||||
-rw-r--r-- | src/ui/border_property.cpp | 23 | ||||
-rw-r--r-- | src/ui/border_property.hpp | 87 | ||||
-rw-r--r-- | src/ui/control.cpp | 402 | ||||
-rw-r--r-- | src/ui/control.hpp | 564 | ||||
-rw-r--r-- | src/ui/controls/linear_layout.cpp | 10 | ||||
-rw-r--r-- | src/ui/d2d_util.hpp | 2 | ||||
-rw-r--r-- | src/ui/layout_base.cpp | 6 | ||||
-rw-r--r-- | src/ui/layout_base.hpp | 102 | ||||
-rw-r--r-- | src/ui/render/render_object.cpp | 19 | ||||
-rw-r--r-- | src/ui/render/render_object.hpp | 20 | ||||
-rw-r--r-- | src/ui/window.hpp | 377 |
13 files changed, 560 insertions, 1068 deletions
diff --git a/CruUI.vcxproj b/CruUI.vcxproj index bd321715..f4fada4d 100644 --- a/CruUI.vcxproj +++ b/CruUI.vcxproj @@ -127,7 +127,6 @@ <ClCompile Include="src\timer.cpp" /> <ClCompile Include="src\ui\animations\animation.cpp" /> <ClCompile Include="src\ui\control.cpp" /> - <ClCompile Include="src\ui\border_property.cpp" /> <ClCompile Include="src\ui\controls\button.cpp" /> <ClCompile Include="src\ui\controls\frame_layout.cpp" /> <ClCompile Include="src\ui\controls\linear_layout.cpp" /> @@ -141,7 +140,6 @@ <ClInclude Include="src\util\any_map.hpp" /> <ClInclude Include="src\util\format.hpp" /> <ClInclude Include="src\util\math_util.hpp" /> - <ClInclude Include="src\ui\border_property.hpp" /> <ClInclude Include="src\ui\controls\frame_layout.hpp" /> <ClInclude Include="src\ui\controls\list_item.hpp" /> <ClInclude Include="src\ui\controls\popup_menu.hpp" /> @@ -151,7 +149,6 @@ <ClCompile Include="src\ui\cursor.cpp" /> <ClCompile Include="src\ui\events\ui_event.cpp" /> <ClCompile Include="src\ui\input_util.cpp" /> - <ClCompile Include="src\ui\layout_base.cpp" /> <ClCompile Include="src\ui\render\flex_layout_render_object.cpp" /> <ClCompile Include="src\ui\render\render_object.cpp" /> <ClCompile Include="src\ui\ui_manager.cpp" /> @@ -180,7 +177,6 @@ <ClInclude Include="src\ui\cursor.hpp" /> <ClInclude Include="src\ui\events\ui_event.hpp" /> <ClInclude Include="src\ui\input_util.hpp" /> - <ClInclude Include="src\ui\layout_base.hpp" /> <ClInclude Include="src\ui\render\flex_layout_render_object.hpp" /> <ClInclude Include="src\ui\render\render_object.hpp" /> <ClInclude Include="src\ui\ui_manager.hpp" /> diff --git a/CruUI.vcxproj.filters b/CruUI.vcxproj.filters index 25923c76..1b7038d2 100644 --- a/CruUI.vcxproj.filters +++ b/CruUI.vcxproj.filters @@ -33,9 +33,6 @@ <ClCompile Include="src\ui\control.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\ui\layout_base.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="src\ui\window.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -60,9 +57,6 @@ <ClCompile Include="src\ui\events\ui_event.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="src\ui\border_property.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="src\ui\cursor.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -131,18 +125,12 @@ <ClInclude Include="src\ui\events\ui_event.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="src\ui\border_property.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="src\ui\control.hpp"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="src\ui\cursor.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="src\ui\layout_base.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="src\ui\ui_base.hpp"> <Filter>Header Files</Filter> </ClInclude> diff --git a/src/ui/border_property.cpp b/src/ui/border_property.cpp deleted file mode 100644 index b79bb482..00000000 --- a/src/ui/border_property.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "border_property.hpp" - -#include "ui_manager.hpp" - -namespace cru::ui -{ - BorderProperty::BorderProperty(): BorderProperty(UiManager::GetInstance()->GetPredefineResources()->border_property_brush) - { - - } - - BorderProperty::BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush): brush_(std::move(brush)) - { - - } - - BorderProperty::BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush, const float width, const float radius_x, - const float radius_y, Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style) : - brush_(std::move(brush)), stroke_width_(width), radius_x_(radius_x), radius_y_(radius_y), stroke_style_(std::move(stroke_style)) - { - - } -} diff --git a/src/ui/border_property.hpp b/src/ui/border_property.hpp deleted file mode 100644 index 4dee0e0f..00000000 --- a/src/ui/border_property.hpp +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "system_headers.hpp" - -#include "base.hpp" - - -namespace cru::ui -{ - class BorderProperty final - { - public: - BorderProperty(); - explicit BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush); - BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush, float width, float radius_x, float radius_y, Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style = nullptr); - BorderProperty(const BorderProperty& other) = default; - BorderProperty(BorderProperty&& other) = default; - BorderProperty& operator=(const BorderProperty& other) = default; - BorderProperty& operator=(BorderProperty&& other) = default; - ~BorderProperty() = default; - - - Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const - { - return brush_; - } - - float GetStrokeWidth() const - { - return stroke_width_; - } - - Microsoft::WRL::ComPtr<ID2D1StrokeStyle> GetStrokeStyle() const - { - return stroke_style_; - } - - float GetRadiusX() const - { - return radius_x_; - } - - float GetRadiusY() const - { - return radius_y_; - } - - void SetBrush(Microsoft::WRL::ComPtr<ID2D1Brush> brush) - { - Require(brush == nullptr, "Brush of BorderProperty mustn't be null."); - brush_ = std::move(brush); - } - - void SetStrokeWidth(const float stroke_width) - { - Require(stroke_width >= 0.0f, "Stroke width must be no less than 0."); - stroke_width_ = stroke_width; - } - - void SetStrokeStyle(Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style) - { - stroke_style_ = std::move(stroke_style); - } - - void SetRadiusX(const float radius_x) - { - Require(radius_x >= 0.0f, "Radius-x must be no less than 0."); - radius_x_ = radius_x; - } - - void SetRadiusY(const float radius_y) - { - Require(radius_y >= 0.0f, "Radius-y must be no less than 0."); - radius_y_ = radius_y; - } - - private: - Microsoft::WRL::ComPtr<ID2D1Brush> brush_; - float stroke_width_ = 1.0f; - float radius_x_ = 0.0f; - float radius_y_ = 0.0f; - Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style_ = nullptr; - }; -} diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 617c50c7..ee2abad0 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -3,292 +3,192 @@ #include <algorithm> #include <cassert> -#include "window.hpp" #include "application.hpp" -#include "graph/graph.hpp" -#include "exception.hpp" #include "cru_debug.hpp" #include "d2d_util.hpp" +#include "exception.hpp" +#include "graph/graph.hpp" #include "math_util.hpp" +#include "window.hpp" #ifdef CRU_DEBUG_LAYOUT #include "ui_manager.hpp" #endif -namespace cru::ui -{ - - void Control::SetParent(Control* parent) - { - const auto old_parent = GetParent(); - parent_ = parent; - const auto new_parent = GetParent(); - if (old_parent != new_parent) - OnParentChanged(old_parent, new_parent); - } - - void Control::SetDescendantWindow(Window* window) - { - if (window == nullptr && window_ == nullptr) - return; - - //You can only attach or detach window. - assert((window != nullptr && window_ == nullptr) || (window == nullptr && window_ != nullptr)); - - if (window == nullptr) - { - const auto old = window_; - TraverseDescendants([old](Control* control) - { - control->window_ = nullptr; - control->OnDetachToWindow(old); - }); - } - else - TraverseDescendants([window](Control* control) - { - control->window_ = window; - control->OnAttachToWindow(window); - }); - } - - void Control::TraverseDescendants(const std::function<void(Control*)>& predicate) - { - TraverseDescendantsInternal(this, predicate); - } - - void Control::TraverseDescendantsInternal(Control * control, const std::function<void(Control*)>& predicate) - { - predicate(control); - for (auto c: control->GetInternalChildren()) - TraverseDescendantsInternal(c, predicate); - } - - - Point Control::ControlToWindow(const Point& point) const - { - const auto position = GetPositionInWindow(); - return Point(point.x + position.x, point.y + position.y); - } - - Point Control::WindowToControl(const Point & point) const - { - const auto position = GetPositionInWindow(); - return Point(point.x - position.x, point.y - position.y); - } - - bool Control::RequestFocus() - { - auto window = GetWindow(); - if (window == nullptr) - return false; - - return window->RequestFocusFor(this); - } - - bool Control::HasFocus() - { - auto window = GetWindow(); - if (window == nullptr) - return false; - - return window->GetFocusControl() == this; - } - - void Control::SetCursor(const Cursor::Ptr& cursor) - { - if (cursor != cursor_) - { - cursor_ = cursor; - const auto window = GetWindow(); - if (window && window->GetMouseHoverControl() == this) - window->UpdateCursor(); - } - } - - void Control::OnParentChanged(Control* old_parent, Control* new_parent) - { - - } - - void Control::OnAttachToWindow(Window* window) - { - - } - - void Control::OnDetachToWindow(Window * window) - { - - } - - void Control::OnMouseClickBegin(MouseButton button) - { - - } - - void Control::OnMouseClickEnd(MouseButton button) - { - - } - - - const std::vector<Control*> NoChildControl::empty_control_vector{}; +namespace cru::ui { +void Control::_SetParent(Control* parent) { + const auto old_parent = GetParent(); + parent_ = parent; + const auto new_parent = GetParent(); + if (old_parent != new_parent) OnParentChanged(old_parent, new_parent); +} - ContentControl::ContentControl() : child_vector_{nullptr}, child_(child_vector_[0]) - { +void Control::_SetDescendantWindow(Window* window) { + if (window == nullptr && window_ == nullptr) return; + + // You can only attach or detach window. + assert((window != nullptr && window_ == nullptr) || + (window == nullptr && window_ != nullptr)); + + if (window == nullptr) { + const auto old = window_; + TraverseDescendants([old](Control* control) { + control->window_ = nullptr; + control->OnDetachToWindow(old); + }); + } else + TraverseDescendants([window](Control* control) { + control->window_ = window; + control->OnAttachToWindow(window); + }); +} - } +void Control::TraverseDescendants( + const std::function<void(Control*)>& predicate) { + TraverseDescendantsInternal(this, predicate); +} - ContentControl::~ContentControl() - { - delete child_; - } +void Control::TraverseDescendantsInternal( + Control* control, const std::function<void(Control*)>& predicate) { + predicate(control); + for (auto c : control->GetChildren()) + TraverseDescendantsInternal(c, predicate); +} +bool Control::RequestFocus() { + auto window = GetWindow(); + if (window == nullptr) return false; - void ContentControl::SetChild(Control* child) - { - if (child == child_) - return; + return window->RequestFocusFor(this); +} - const auto window = GetWindow(); - const auto old_child = child_; - child_ = child; - if (old_child) - { - old_child->SetParent(nullptr); - old_child->SetDescendantWindow(nullptr); - } - if (child) - { - child->SetParent(this); - child->SetDescendantWindow(window); - } - OnChildChanged(old_child, child); - } +bool Control::HasFocus() { + auto window = GetWindow(); + if (window == nullptr) return false; - void ContentControl::OnChildChanged(Control* old_child, Control* new_child) - { + return window->GetFocusControl() == this; +} - } +void Control::SetCursor(const Cursor::Ptr& cursor) { + if (cursor != cursor_) { + cursor_ = cursor; + const auto window = GetWindow(); + if (window && window->GetMouseHoverControl() == this) + window->UpdateCursor(); + } +} - void ControlAddChildCheck(Control* control) - { - if (control->GetParent() != nullptr) - throw std::invalid_argument("The control already has a parent."); +void Control::OnParentChanged(Control* old_parent, Control* new_parent) {} - if (dynamic_cast<Window*>(control)) - throw std::invalid_argument("Can't add a window as child."); - } +void Control::OnAttachToWindow(Window* window) {} - MultiChildControl::~MultiChildControl() - { - for (const auto child : children_) - delete child; - } +void Control::OnDetachToWindow(Window* window) {} - void MultiChildControl::AddChild(Control* control) - { - ControlAddChildCheck(control); +void Control::OnMouseClickBegin(MouseButton button) {} - children_.push_back(control); +void Control::OnMouseClickEnd(MouseButton button) {} - control->SetParent(this); - control->SetDescendantWindow(GetWindow()); +const std::vector<Control*> NoChildControl::empty_control_vector{}; - OnAddChild(control); - } +ContentControl::ContentControl() + : child_vector_{nullptr}, child_(child_vector_[0]) {} - void MultiChildControl::AddChild(Control* control, const int position) - { - ControlAddChildCheck(control); +ContentControl::~ContentControl() { delete child_; } - if (position < 0 || static_cast<decltype(children_.size())>(position) > this->children_.size()) - throw std::invalid_argument("The position is out of range."); +void ContentControl::SetChild(Control* child) { + if (child == child_) return; - children_.insert(this->children_.cbegin() + position, control); + const auto window = GetWindow(); + const auto old_child = child_; + child_ = child; + if (old_child) { + old_child->_SetParent(nullptr); + old_child->_SetDescendantWindow(nullptr); + } + if (child) { + child->_SetParent(this); + child->_SetDescendantWindow(window); + } + OnChildChanged(old_child, child); +} - control->SetParent(this); - control->SetDescendantWindow(GetWindow()); +void ContentControl::OnChildChanged(Control* old_child, Control* new_child) {} - OnAddChild(control); - } +void ControlAddChildCheck(Control* control) { + if (control->GetParent() != nullptr) + throw std::invalid_argument("The control already has a parent."); - void MultiChildControl::RemoveChild(Control* child) - { - const auto i = std::find(this->children_.cbegin(), this->children_.cend(), child); - if (i == this->children_.cend()) - throw std::invalid_argument("The argument child is not a child of this control."); + if (dynamic_cast<Window*>(control)) + throw std::invalid_argument("Can't add a window as child."); +} + +MultiChildControl::~MultiChildControl() { + for (const auto child : children_) delete child; +} + +void MultiChildControl::AddChild(Control* control, const int position) { + ControlAddChildCheck(control); - children_.erase(i); + if (position < 0 || static_cast<decltype(children_.size())>(position) > + this->children_.size()) + throw std::invalid_argument("The position is out of range."); - child->SetParent(nullptr); - child->SetDescendantWindow(nullptr); + children_.insert(this->children_.cbegin() + position, control); + + control->_SetParent(this); + control->_SetDescendantWindow(GetWindow()); + + OnAddChild(control); +} - OnRemoveChild(child); - } +void MultiChildControl::RemoveChild(const int position) { + if (position < 0 || static_cast<decltype(this->children_.size())>(position) >= + this->children_.size()) + throw std::invalid_argument("The position is out of range."); - void MultiChildControl::RemoveChild(const int position) - { - if (position < 0 || static_cast<decltype(this->children_.size())>(position) >= this->children_.size()) - throw std::invalid_argument("The position is out of range."); - - const auto i = children_.cbegin() + position; - const auto child = *i; - - children_.erase(i); - - child->SetParent(nullptr); - child->SetDescendantWindow(nullptr); - - OnRemoveChild(child); - } - - void MultiChildControl::OnAddChild(Control* child) - { - - } - - void MultiChildControl::OnRemoveChild(Control* child) - { - - } - - std::list<Control*> GetAncestorList(Control* control) - { - std::list<Control*> l; - while (control != nullptr) - { - l.push_front(control); - control = control->GetParent(); - } - return l; - } + const auto i = children_.cbegin() + position; + const auto child = *i; - Control* FindLowestCommonAncestor(Control * left, Control * right) - { - if (left == nullptr || right == nullptr) - return nullptr; + children_.erase(i); - auto&& left_list = GetAncestorList(left); - auto&& right_list = GetAncestorList(right); - - // the root is different - if (left_list.front() != right_list.front()) - return nullptr; + child->_SetParent(nullptr); + child->_SetDescendantWindow(nullptr); + + OnRemoveChild(child); +} + +void MultiChildControl::OnAddChild(Control* child) {} + +void MultiChildControl::OnRemoveChild(Control* child) {} + +std::list<Control*> GetAncestorList(Control* control) { + std::list<Control*> l; + while (control != nullptr) { + l.push_front(control); + control = control->GetParent(); + } + return l; +} - // find the last same control or the last control (one is ancestor of the other) - auto left_i = left_list.cbegin(); - auto right_i = right_list.cbegin(); - while (true) - { - if (left_i == left_list.cend()) - return *(--left_i); - if (right_i == right_list.cend()) - return *(--right_i); - if (*left_i != *right_i) - return *(--left_i); - ++left_i; - ++right_i; - } - } +Control* FindLowestCommonAncestor(Control* left, Control* right) { + if (left == nullptr || right == nullptr) return nullptr; + + auto&& left_list = GetAncestorList(left); + auto&& right_list = GetAncestorList(right); + + // the root is different + if (left_list.front() != right_list.front()) return nullptr; + + // find the last same control or the last control (one is ancestor of the + // other) + auto left_i = left_list.cbegin(); + auto right_i = right_list.cbegin(); + while (true) { + if (left_i == left_list.cend()) return *(--left_i); + if (right_i == right_list.cend()) return *(--right_i); + if (*left_i != *right_i) return *(--left_i); + ++left_i; + ++right_i; + } } +} // namespace cru::ui diff --git a/src/ui/control.hpp b/src/ui/control.hpp index 8e69fb07..e85d0e6d 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -1,357 +1,243 @@ #pragma once - -// ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" -#include "system_headers.hpp" -#include <unordered_map> #include <any> +#include <unordered_map> #include <utility> +#include "system_headers.hpp" #include "base.hpp" -#include "ui_base.hpp" -#include "layout_base.hpp" -#include "events/ui_event.hpp" #include "cursor.hpp" -#include "any_map.hpp" +#include "events/ui_event.hpp" #include "input_util.hpp" +#include "ui_base.hpp" -namespace cru::ui -{ - class Window; - - - class Control : public Object - { - friend class Window; - - protected: - Control() = default; - public: - Control(const Control& other) = delete; - Control(Control&& other) = delete; - Control& operator=(const Control& other) = delete; - Control& operator=(Control&& other) = delete; - ~Control() override = default; - - public: - virtual StringView GetControlType() const = 0; - - - //*************** region: tree *************** - public: - //Get the window if attached, otherwise, return nullptr. - Window* GetWindow() const - { - return window_; - } - - Control* GetParent() const - { - return parent_; - } - - void SetParent(Control* parent); - - void SetDescendantWindow(Window* window); - - //Traverse the tree rooted the control including itself. - void TraverseDescendants(const std::function<void(Control*)>& predicate); - - private: - static void TraverseDescendantsInternal(Control* control, const std::function<void(Control*)>& predicate); - - //*************** region: position *************** - public: - virtual Point GetPositionInWindow() const = 0; - - //Local point to absolute point. - Point ControlToWindow(const Point& point) const; - - //Absolute point to local point. - Point WindowToControl(const Point& point) const; - - - - //*************** region: focus *************** - public: - bool RequestFocus(); - - bool HasFocus(); - - - //*************** region: cursor *************** - // If cursor is set to null, then it uses parent's cursor. - // Window's cursor can't be null. - public: - Cursor::Ptr GetCursor() const - { - return cursor_; - } - - void SetCursor(const Cursor::Ptr& cursor); - - - //*************** region: additional properties *************** - public: - AnyMap* GetAdditionalPropertyMap() - { - return &additional_property_map_; - } - - - //*************** region: events *************** - public: - //Raised when mouse enter the control. - events::RoutedEvent<events::MouseEventArgs> mouse_enter_event; - //Raised when mouse is leave the control. - events::RoutedEvent<events::MouseEventArgs> mouse_leave_event; - //Raised when mouse is move in the control. - events::RoutedEvent<events::MouseEventArgs> mouse_move_event; - //Raised when a mouse button is pressed in the control. - events::RoutedEvent<events::MouseButtonEventArgs> mouse_down_event; - //Raised when a mouse button is released in the control. - events::RoutedEvent<events::MouseButtonEventArgs> mouse_up_event; - //Raised when a mouse button is pressed in the control and released in the control with mouse not leaving it between two operations. - events::RoutedEvent<events::MouseButtonEventArgs> mouse_click_event; - - events::RoutedEvent<events::MouseWheelEventArgs> mouse_wheel_event; - - events::RoutedEvent<events::KeyEventArgs> key_down_event; - events::RoutedEvent<events::KeyEventArgs> key_up_event; - events::RoutedEvent<events::CharEventArgs> char_event; - - events::RoutedEvent<events::FocusChangeEventArgs> get_focus_event; - events::RoutedEvent<events::FocusChangeEventArgs> lose_focus_event; - - - //*************** region: tree *************** - protected: - virtual const std::vector<Control*>& GetInternalChildren() const = 0; - - virtual void OnParentChanged(Control* old_parent, Control* new_parent); - virtual void OnAttachToWindow(Window* window); - virtual void OnDetachToWindow(Window* window); - - - //*************** region: additional mouse event *************** - protected: - virtual void OnMouseClickBegin(MouseButton button); - virtual void OnMouseClickEnd(MouseButton button); - - - private: - Window * window_ = nullptr; - Control* parent_ = nullptr; - - Cursor::Ptr cursor_{}; - - AnyMap additional_property_map_{}; - }; +namespace cru::ui { +class Window; +class Control : public Object { + friend class Window; - - class NoChildControl : public Control - { - private: - // used in GetInternalChildren. - static const std::vector<Control*> empty_control_vector; + protected: + Control() = default; - protected: - NoChildControl() = default; - public: - NoChildControl(const NoChildControl& other) = delete; - NoChildControl(NoChildControl&& other) = delete; - NoChildControl& operator=(const NoChildControl& other) = delete; - NoChildControl& operator=(NoChildControl&& other) = delete; - ~NoChildControl() override = default; - - protected: - const std::vector<Control*>& GetInternalChildren() const override final - { - return empty_control_vector; - } - }; - - - class ContentControl : public Control - { - protected: - ContentControl(); - public: - ContentControl(const ContentControl& other) = delete; - ContentControl(ContentControl&& other) = delete; - ContentControl& operator=(const ContentControl& other) = delete; - ContentControl& operator=(ContentControl&& other) = delete; - ~ContentControl() override; - - Control* GetChild() const - { - return child_; - } - - void SetChild(Control* child); - - protected: - const std::vector<Control*>& GetInternalChildren() const override final - { - return child_vector_; - } - - // Override should call base. - virtual void OnChildChanged(Control* old_child, Control* new_child); - - private: - std::vector<Control*> child_vector_; - Control*& child_; - }; - - - class MultiChildControl : public Control - { - protected: - MultiChildControl() = default; - public: - MultiChildControl(const MultiChildControl& other) = delete; - MultiChildControl(MultiChildControl&& other) = delete; - MultiChildControl& operator=(const MultiChildControl& other) = delete; - MultiChildControl& operator=(MultiChildControl&& other) = delete; - ~MultiChildControl() override; - - const std::vector<Control*>& GetInternalChildren() const override final - { - return children_; - } - - const std::vector<Control*>& GetChildren() const - { - return children_; - } - - //Add a child at tail. - void AddChild(Control* control); - - //Add a child before the position. - void AddChild(Control* control, int position); - - //Remove a child. - void RemoveChild(Control* child); - - //Remove a child at specified position. - void RemoveChild(int position); - - protected: - virtual void OnAddChild(Control* child); - virtual void OnRemoveChild(Control* child); - - private: - std::vector<Control*> children_; - }; - - - - //*************** region: event dispatcher helper *************** - - // Dispatch the event. - // - // This will raise routed event of the control and its parent and parent's - // parent ... (until "last_receiver" if it's not nullptr) with appropriate args. - // - // First tunnel from top to bottom possibly stopped by "handled" flag in EventArgs. - // Second bubble from bottom to top possibly stopped by "handled" flag in EventArgs. - // Last direct to each control. - // - // Args is of type "EventArgs". The first init argument is "sender", which is - // automatically bound to each receiving control. The second init argument is - // "original_sender", which is unchanged. And "args" will be perfectly forwarded - // as the rest arguments. - template<typename EventArgs, typename... Args> - void DispatchEvent(Control* const original_sender, events::RoutedEvent<EventArgs> Control::* event_ptr, Control* const last_receiver, Args&&... args) - { - std::list<Control*> receive_list; - - auto parent = original_sender; - while (parent != last_receiver) - { - receive_list.push_back(parent); - parent = parent->GetInternalParent(); - } - - auto handled = false; - - //tunnel - for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) - { - EventArgs event_args(*i, original_sender, std::forward<Args>(args)...); - (*i->*event_ptr).tunnel.Raise(event_args); - if (event_args.IsHandled()) - { - handled = true; - break; - } - } - - //bubble - if (!handled) - { - for (auto i : receive_list) - { - EventArgs event_args(i, original_sender, std::forward<Args>(args)...); - (i->*event_ptr).bubble.Raise(event_args); - if (event_args.IsHandled()) - break; - } - } - - //direct - for (auto i : receive_list) - { - EventArgs event_args(i, original_sender, std::forward<Args>(args)...); - (i->*event_ptr).direct.Raise(event_args); - } + public: + Control(const Control& other) = delete; + Control(Control&& other) = delete; + Control& operator=(const Control& other) = delete; + Control& operator=(Control&& other) = delete; + ~Control() override = default; + + public: + virtual StringView GetControlType() const = 0; + + //*************** region: tree *************** + public: + // Get the window if attached, otherwise, return nullptr. + Window* GetWindow() const { return window_; } + + Control* GetParent() const { return parent_; } + + virtual const std::vector<Control*>& GetChildren() const = 0; + + // Traverse the tree rooted the control including itself. + void TraverseDescendants(const std::function<void(Control*)>& predicate); + + void _SetParent(Control* parent); + void _SetDescendantWindow(Window* window); + + private: + static void TraverseDescendantsInternal( + Control* control, const std::function<void(Control*)>& predicate); + + //*************** region: focus *************** + public: + bool RequestFocus(); + + bool HasFocus(); + + //*************** region: cursor *************** + // If cursor is set to null, then it uses parent's cursor. + // Window's cursor can't be null. + public: + Cursor::Ptr GetCursor() const { return cursor_; } + + void SetCursor(const Cursor::Ptr& cursor); + + //*************** region: events *************** + public: + // Raised when mouse enter the control. + events::RoutedEvent<events::MouseEventArgs> mouse_enter_event; + // Raised when mouse is leave the control. + events::RoutedEvent<events::MouseEventArgs> mouse_leave_event; + // Raised when mouse is move in the control. + events::RoutedEvent<events::MouseEventArgs> mouse_move_event; + // Raised when a mouse button is pressed in the control. + events::RoutedEvent<events::MouseButtonEventArgs> mouse_down_event; + // Raised when a mouse button is released in the control. + events::RoutedEvent<events::MouseButtonEventArgs> mouse_up_event; + // Raised when a mouse button is pressed in the control and released in the + // control with mouse not leaving it between two operations. + events::RoutedEvent<events::MouseButtonEventArgs> mouse_click_event; + + events::RoutedEvent<events::MouseWheelEventArgs> mouse_wheel_event; + + events::RoutedEvent<events::KeyEventArgs> key_down_event; + events::RoutedEvent<events::KeyEventArgs> key_up_event; + events::RoutedEvent<events::CharEventArgs> char_event; + + events::RoutedEvent<events::FocusChangeEventArgs> get_focus_event; + events::RoutedEvent<events::FocusChangeEventArgs> lose_focus_event; + + //*************** region: tree *************** + protected: + virtual void OnParentChanged(Control* old_parent, Control* new_parent); + virtual void OnAttachToWindow(Window* window); + virtual void OnDetachToWindow(Window* window); + + //*************** region: additional mouse event *************** + protected: + virtual void OnMouseClickBegin(MouseButton button); + virtual void OnMouseClickEnd(MouseButton button); + + private: + Window* window_ = nullptr; + Control* parent_ = nullptr; + + Cursor::Ptr cursor_{}; +}; + +class NoChildControl : public Control { + private: + static const std::vector<Control*> empty_control_vector; + + protected: + NoChildControl() = default; + + public: + NoChildControl(const NoChildControl& other) = delete; + NoChildControl(NoChildControl&& other) = delete; + NoChildControl& operator=(const NoChildControl& other) = delete; + NoChildControl& operator=(NoChildControl&& other) = delete; + ~NoChildControl() override = default; + + protected: + const std::vector<Control*>& GetChildren() const override final { + return empty_control_vector; + } +}; + +class ContentControl : public Control { + protected: + ContentControl(); + + public: + ContentControl(const ContentControl& other) = delete; + ContentControl(ContentControl&& other) = delete; + ContentControl& operator=(const ContentControl& other) = delete; + ContentControl& operator=(ContentControl&& other) = delete; + ~ContentControl() override; + + const std::vector<Control*>& GetChildren() const override final { + return child_vector_; + } + Control* GetChild() const { return child_; } + void SetChild(Control* child); + + protected: + virtual void OnChildChanged(Control* old_child, Control* new_child); + + private: + std::vector<Control*> child_vector_; + Control*& child_; +}; + +class MultiChildControl : public Control { + protected: + MultiChildControl() = default; + + public: + MultiChildControl(const MultiChildControl& other) = delete; + MultiChildControl(MultiChildControl&& other) = delete; + MultiChildControl& operator=(const MultiChildControl& other) = delete; + MultiChildControl& operator=(MultiChildControl&& other) = delete; + ~MultiChildControl() override; + + const std::vector<Control*>& GetChildren() const override final { + return children_; + } + + void AddChild(Control* control, int position); + + void RemoveChild(int position); + + protected: + virtual void OnAddChild(Control* child); + virtual void OnRemoveChild(Control* child); + + private: + std::vector<Control*> children_; +}; + +//*************** region: event dispatcher helper *************** + +// Dispatch the event. +// +// This will raise routed event of the control and its parent and parent's +// parent ... (until "last_receiver" if it's not nullptr) with appropriate args. +// +// First tunnel from top to bottom possibly stopped by "handled" flag in +// EventArgs. Second bubble from bottom to top possibly stopped by "handled" +// flag in EventArgs. Last direct to each control. +// +// Args is of type "EventArgs". The first init argument is "sender", which is +// automatically bound to each receiving control. The second init argument is +// "original_sender", which is unchanged. And "args" will be perfectly forwarded +// as the rest arguments. +template <typename EventArgs, typename... Args> +void DispatchEvent(Control* const original_sender, + events::RoutedEvent<EventArgs> Control::*event_ptr, + Control* const last_receiver, Args&&... args) { + std::list<Control*> receive_list; + + auto parent = original_sender; + while (parent != last_receiver) { + receive_list.push_back(parent); + parent = parent->GetInternalParent(); + } + + auto handled = false; + + // tunnel + for (auto i = receive_list.crbegin(); i != receive_list.crend(); ++i) { + EventArgs event_args(*i, original_sender, std::forward<Args>(args)...); + (*i->*event_ptr).tunnel.Raise(event_args); + if (event_args.IsHandled()) { + handled = true; + break; } - - - //*************** region: tree helper *************** - - // Find the lowest common ancestor. - // Return nullptr if "left" and "right" are not in the same tree. - Control* FindLowestCommonAncestor(Control* left, Control* right); - - - //*************** region: create helper *************** - - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - return control; + } + + // bubble + if (!handled) { + for (auto i : receive_list) { + EventArgs event_args(i, original_sender, std::forward<Args>(args)...); + (i->*event_ptr).bubble.Raise(event_args); + if (event_args.IsHandled()) break; } + } - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } + // direct + for (auto i : receive_list) { + EventArgs event_args(i, original_sender, std::forward<Args>(args)...); + (i->*event_ptr).direct.Raise(event_args); + } +} - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } +//*************** region: tree helper *************** - using ControlList = std::initializer_list<Control*>; -} +// Find the lowest common ancestor. +// Return nullptr if "left" and "right" are not in the same tree. +Control* FindLowestCommonAncestor(Control* left, Control* right); + +} // namespace cru::ui diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp index d3fdc9b5..c3de7ca3 100644 --- a/src/ui/controls/linear_layout.cpp +++ b/src/ui/controls/linear_layout.cpp @@ -27,7 +27,7 @@ namespace cru::ui::controls // First measure Content and Exactly and count Stretch. if (orientation_ == Orientation::Horizontal) - for(auto control: GetInternalChildren()) + for(auto control: GetChildren()) { const auto mode = control->GetLayoutParams()->width.mode; if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) @@ -42,7 +42,7 @@ namespace cru::ui::controls stretch_control_list.push_back(control); } else - for(auto control: GetInternalChildren()) + for(auto control: GetChildren()) { const auto mode = control->GetLayoutParams()->height.mode; if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) @@ -82,7 +82,7 @@ namespace cru::ui::controls if (orientation_ == Orientation::Horizontal) { - for (auto control : GetInternalChildren()) + for (auto control : GetChildren()) { if (control->GetLayoutParams()->height.mode == MeasureMode::Stretch) { @@ -93,7 +93,7 @@ namespace cru::ui::controls } else { - for (auto control : GetInternalChildren()) + for (auto control : GetChildren()) { if (control->GetLayoutParams()->width.mode == MeasureMode::Stretch) { @@ -110,7 +110,7 @@ namespace cru::ui::controls void LinearLayout::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) { float current_main_side_anchor = 0; - for(auto control: GetInternalChildren()) + for(auto control: GetChildren()) { const auto layout_params = control->GetLayoutParams(); const auto size = control->GetDesiredSize(); diff --git a/src/ui/d2d_util.hpp b/src/ui/d2d_util.hpp index 5f2e10b2..94ef6223 100644 --- a/src/ui/d2d_util.hpp +++ b/src/ui/d2d_util.hpp @@ -1,6 +1,4 @@ #pragma once - -// ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" #include "system_headers.hpp" diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp deleted file mode 100644 index 5898a623..00000000 --- a/src/ui/layout_base.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "layout_base.hpp" - -namespace cru::ui -{ - -} diff --git a/src/ui/layout_base.hpp b/src/ui/layout_base.hpp deleted file mode 100644 index 527d9f98..00000000 --- a/src/ui/layout_base.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "ui_base.hpp" - -namespace cru::ui -{ - enum class Alignment - { - Center, - Start, - End - }; - - enum class MeasureMode - { - Exactly, - Content, - Stretch - }; - - enum class RectRange - { - Content, // content excluding padding, border and margin - Padding, // only including content and padding - HalfBorder, // including content, padding and half border - FullBorder, // including content, padding and full border - Margin // including content, padding, border and margin - }; - - struct LayoutSideParams final - { - constexpr static LayoutSideParams Exactly(const float length, const Alignment alignment = Alignment::Center) - { - return LayoutSideParams(MeasureMode::Exactly, length, alignment); - } - - constexpr static LayoutSideParams Content(const Alignment alignment = Alignment::Center) - { - return LayoutSideParams(MeasureMode::Content, 0, alignment); - } - - constexpr static LayoutSideParams Stretch(const Alignment alignment = Alignment::Center) - { - return LayoutSideParams(MeasureMode::Stretch, 0, alignment); - } - - constexpr LayoutSideParams() = default; - - constexpr explicit LayoutSideParams(const MeasureMode mode, const float length, const Alignment alignment) - : length(length), mode(mode), alignment(alignment) - { - - } - - constexpr bool Validate() const - { - if (length < 0.0) - return false; - if (min.has_value() && min.value() < 0.0) - return false; - if (max.has_value() && max.value() < 0.0) - return false; - if (min.has_value() && max.has_value() && min.value() > max.value()) - return false; - return true; - } - - // only used in exactly mode, specify the exactly side length of content. - float length = 0.0; - MeasureMode mode = MeasureMode::Content; - Alignment alignment = Alignment::Center; - - // min and max specify the min/max side length of content. - // they are used as hint and respect the actual size that content needs. - // when mode is exactly, length is coerced into the min-max range. - std::optional<float> min = std::nullopt; - std::optional<float> max = std::nullopt; - }; - - struct BasicLayoutParams final - { - BasicLayoutParams() = default; - BasicLayoutParams(const BasicLayoutParams&) = default; - BasicLayoutParams(BasicLayoutParams&&) = default; - BasicLayoutParams& operator = (const BasicLayoutParams&) = default; - BasicLayoutParams& operator = (BasicLayoutParams&&) = default; - ~BasicLayoutParams() = default; - - bool Validate() const - { - return width.Validate() && height.Validate() && margin.Validate() && padding.Validate(); - } - - LayoutSideParams width; - LayoutSideParams height; - Thickness padding; - Thickness margin; - }; -} diff --git a/src/ui/render/render_object.cpp b/src/ui/render/render_object.cpp index 0035d1be..0a0e693c 100644 --- a/src/ui/render/render_object.cpp +++ b/src/ui/render/render_object.cpp @@ -3,14 +3,6 @@ #include "cru_debug.hpp" namespace cru::ui::render { -void RenderObject::SetRenderHost(IRenderHost* new_render_host) { - if (new_render_host == render_host_) return; - - const auto old = render_host_; - render_host_ = new_render_host; - OnRenderHostChanged(old, new_render_host); -} - void RenderObject::AddChild(RenderObject* render_object, const int position) { if (render_object->GetParent() != nullptr) throw std::invalid_argument("Render object already has a parent."); @@ -52,17 +44,6 @@ void RenderObject::Layout(const Rect& rect) { OnLayoutCore(Rect{Point::Zero(), rect.GetSize()}); } -void RenderObject::OnRenderHostChanged(IRenderHost* old_render_host, - IRenderHost* new_render_host) {} - -void RenderObject::InvalidateRenderHostPaint() const { - if (render_host_ != nullptr) render_host_->InvalidatePaint(); -} - -void RenderObject::InvalidateRenderHostLayout() const { - if (render_host_ != nullptr) render_host_->InvalidateLayout(); -} - void RenderObject::OnParentChanged(RenderObject* old_parent, RenderObject* new_parent) {} diff --git a/src/ui/render/render_object.hpp b/src/ui/render/render_object.hpp index aeba1457..34f5dcee 100644 --- a/src/ui/render/render_object.hpp +++ b/src/ui/render/render_object.hpp @@ -8,11 +8,11 @@ #include "base.hpp" #include "ui/ui_base.hpp" +namespace cru::ui { +class Control; +} + namespace cru::ui::render { -struct IRenderHost : Interface { - virtual void InvalidatePaint() = 0; - virtual void InvalidateLayout() = 0; -}; class RenderObject : public Object { protected: @@ -25,8 +25,8 @@ class RenderObject : public Object { RenderObject& operator=(RenderObject&& other) = delete; ~RenderObject() override = default; - IRenderHost* GetRenderHost() const { return render_host_; } - void SetRenderHost(IRenderHost* new_render_host); + Control* GetAttachedControl() const { return control_; } + void SetAttachedControl(Control* new_control) { control_ = new_control; } RenderObject* GetParent() const { return parent_; } @@ -58,12 +58,6 @@ class RenderObject : public Object { virtual RenderObject* HitTest(const Point& point) = 0; protected: - virtual void OnRenderHostChanged(IRenderHost* old_render_host, - IRenderHost* new_render_host); - - void InvalidateRenderHostPaint() const; - void InvalidateRenderHostLayout() const; - virtual void OnParentChanged(RenderObject* old_parent, RenderObject* new_parent); @@ -80,7 +74,7 @@ class RenderObject : public Object { void OnLayoutCore(const Rect& rect); private: - IRenderHost* render_host_ = nullptr; + Control* control_ = nullptr; RenderObject* parent_ = nullptr; std::vector<RenderObject*> children_{}; diff --git a/src/ui/window.hpp b/src/ui/window.hpp index d3374684..ac26de22 100644 --- a/src/ui/window.hpp +++ b/src/ui/window.hpp @@ -3,276 +3,243 @@ // ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" -#include "system_headers.hpp" #include <map> #include <memory> +#include "system_headers.hpp" #include "control.hpp" #include "events/ui_event.hpp" -namespace cru::graph -{ - class WindowRenderTarget; +namespace cru::graph { +class WindowRenderTarget; } -namespace cru::ui -{ - class WindowManager : public Object - { - public: - static WindowManager* GetInstance(); - private: - WindowManager(); - public: - WindowManager(const WindowManager& other) = delete; - WindowManager(WindowManager&& other) = delete; - WindowManager& operator=(const WindowManager& other) = delete; - WindowManager& operator=(WindowManager&& other) = delete; - ~WindowManager() override = default; +namespace cru::ui { +class WindowManager : public Object { + public: + static WindowManager* GetInstance(); + private: + WindowManager(); - //Get the general window class for creating ordinary window. - WindowClass* GetGeneralWindowClass() const - { - return general_window_class_.get(); - } + public: + WindowManager(const WindowManager& other) = delete; + WindowManager(WindowManager&& other) = delete; + WindowManager& operator=(const WindowManager& other) = delete; + WindowManager& operator=(WindowManager&& other) = delete; + ~WindowManager() override = default; - //Register a window newly created. - //This function adds the hwnd to hwnd-window map. - //It should be called immediately after a window was created. - void RegisterWindow(HWND hwnd, Window* window); + // Get the general window class for creating ordinary window. + WindowClass* GetGeneralWindowClass() const { + return general_window_class_.get(); + } - //Unregister a window that is going to be destroyed. - //This function removes the hwnd from the hwnd-window map. - //It should be called immediately before a window is going to be destroyed, - void UnregisterWindow(HWND hwnd); + // Register a window newly created. + // This function adds the hwnd to hwnd-window map. + // It should be called immediately after a window was created. + void RegisterWindow(HWND hwnd, Window* window); - //Return a pointer to the Window object related to the HWND or nullptr if the hwnd is not in the map. - Window* FromHandle(HWND hwnd); + // Unregister a window that is going to be destroyed. + // This function removes the hwnd from the hwnd-window map. + // It should be called immediately before a window is going to be destroyed, + void UnregisterWindow(HWND hwnd); - std::vector<Window*> GetAllWindows() const; + // Return a pointer to the Window object related to the HWND or nullptr if the + // hwnd is not in the map. + Window* FromHandle(HWND hwnd); - private: - std::unique_ptr<WindowClass> general_window_class_; - std::map<HWND, Window*> window_map_; - }; + std::vector<Window*> GetAllWindows() const; + private: + std::unique_ptr<WindowClass> general_window_class_; + std::map<HWND, Window*> window_map_; +}; +class Window final : public ContentControl { + friend class WindowManager; - class Window final : public ContentControl - { - friend class WindowManager; - public: - static constexpr auto control_type = L"Window"; + public: + static constexpr auto control_type = L"Window"; - public: - static Window* CreateOverlapped(); - static Window* CreatePopup(Window* parent, bool caption = false); + public: + static Window* CreateOverlapped(); + static Window* CreatePopup(Window* parent, bool caption = false); - private: - struct tag_overlapped_constructor {}; - struct tag_popup_constructor {}; + private: + struct tag_overlapped_constructor {}; + struct tag_popup_constructor {}; - explicit Window(tag_overlapped_constructor); - Window(tag_popup_constructor, Window* parent, bool caption); + explicit Window(tag_overlapped_constructor); + Window(tag_popup_constructor, Window* parent, bool caption); - void BeforeCreateHwnd(); - void AfterCreateHwnd(WindowManager* window_manager); + void BeforeCreateHwnd(); + void AfterCreateHwnd(WindowManager* window_manager); - public: - Window(const Window& other) = delete; - Window(Window&& other) = delete; - Window& operator=(const Window& other) = delete; - Window& operator=(Window&& other) = delete; - ~Window() override; + public: + Window(const Window& other) = delete; + Window(Window&& other) = delete; + Window& operator=(const Window& other) = delete; + Window& operator=(Window&& other) = delete; + ~Window() override; - public: - StringView GetControlType() const override final; + public: + StringView GetControlType() const override final; - void SetDeleteThisOnDestroy(bool value); + void SetDeleteThisOnDestroy(bool value); - //*************** region: handle *************** + //*************** region: handle *************** - //Get the handle of the window. Return null if window is invalid. - HWND GetWindowHandle() const - { - return hwnd_; - } + // Get the handle of the window. Return null if window is invalid. + HWND GetWindowHandle() const { return hwnd_; } - //Return if the window is still valid, that is, hasn't been closed or destroyed. - bool IsWindowValid() const - { - return hwnd_ != nullptr; - } + // Return if the window is still valid, that is, hasn't been closed or + // destroyed. + bool IsWindowValid() const { return hwnd_ != nullptr; } + //*************** region: window operations *************** - //*************** region: window operations *************** + Window* GetParentWindow() const { return parent_window_; } - Window* GetParentWindow() const - { - return parent_window_; - } + // Close and destroy the window if the window is valid. + void Close(); - //Close and destroy the window if the window is valid. - void Close(); + // Send a repaint message to the window's message queue which may make the + // window repaint. + void InvalidateDraw() override final; - //Send a repaint message to the window's message queue which may make the window repaint. - void InvalidateDraw() override final; + // Show the window. + void Show(); - //Show the window. - void Show(); + // Hide thw window. + void Hide(); - //Hide thw window. - void Hide(); + // Get the client size. + Size GetClientSize(); - //Get the client size. - Size GetClientSize(); + // Set the client size and repaint. + void SetClientSize(const Size& size); - //Set the client size and repaint. - void SetClientSize(const Size& size); + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + Rect GetWindowRect(); - //Get the rect of the window containing frame. - //The lefttop of the rect is relative to screen lefttop. - Rect GetWindowRect(); + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + void SetWindowRect(const Rect& rect); - //Set the rect of the window containing frame. - //The lefttop of the rect is relative to screen lefttop. - void SetWindowRect(const Rect& rect); + // Set the lefttop of the window relative to screen. + void SetWindowPosition(const Point& position); - //Set the lefttop of the window relative to screen. - void SetWindowPosition(const Point& position); + Point PointToScreen(const Point& point); - Point PointToScreen(const Point& point); + Point PointFromScreen(const Point& point); - Point PointFromScreen(const Point& point); + // Handle the raw window message. + // Return true if the message is handled and get the result through "result" + // argument. Return false if the message is not handled. + bool HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, + LRESULT& result); - //Handle the raw window message. - //Return true if the message is handled and get the result through "result" argument. - //Return false if the message is not handled. - bool HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, LPARAM l_param, LRESULT& result); + //*************** region: mouse *************** - //*************** region: mouse *************** + Point GetMousePosition(); - Point GetMousePosition(); + Control* GetMouseHoverControl() const { return mouse_hover_control_; } - Control* GetMouseHoverControl() const - { - return mouse_hover_control_; - } + //*************** region: layout *************** - //*************** region: position and size *************** + void WindowInvalidateLayout(); - //Always return (0, 0) for a window. - Point GetOffset() override final; + void Relayout(); - //Get the size of client area for a window. - Size GetSize() override final; + void SetSizeFitContent(const Size& max_size = Size(1000, 1000)); - //This method has no effect for a window. Use SetClientSize instead. - void SetRect(const Rect& size) override final; + //*************** region: focus *************** - //Override. If point is in client area, it is in window. - bool IsPointInside(const Point& point) override final; + // Request focus for specified control. + bool RequestFocusFor(Control* control); - //*************** region: layout *************** + // Get the control that has focus. + Control* GetFocusControl(); - void WindowInvalidateLayout(); + //*************** region: mouse capture *************** - void Relayout(); + Control* CaptureMouseFor(Control* control); + Control* ReleaseCurrentMouseCapture(); - void SetSizeFitContent(const Size& max_size = Size(1000, 1000)); + //*************** region: cursor *************** + void UpdateCursor(); + //*************** region: debug *************** +#ifdef CRU_DEBUG_LAYOUT + bool IsDebugLayout() const { return debug_layout_; } - //*************** region: focus *************** + void SetDebugLayout(bool value); +#endif - //Request focus for specified control. - bool RequestFocusFor(Control* control); + public: + //*************** region: events *************** + Event<events::UiEventArgs> activated_event; + Event<events::UiEventArgs> deactivated_event; - //Get the control that has focus. - Control* GetFocusControl(); + Event<events::WindowNativeMessageEventArgs> native_message_event; + private: + //*************** region: native operations *************** - //*************** region: mouse capture *************** + // Get the client rect in pixel. + RECT GetClientRectPixel(); - Control* CaptureMouseFor(Control* control); - Control* ReleaseCurrentMouseCapture(); + bool IsMessageInQueue(UINT message); - - //*************** region: cursor *************** - void UpdateCursor(); + void SetCursorInternal(HCURSOR cursor); - //*************** region: debug *************** -#ifdef CRU_DEBUG_LAYOUT - bool IsDebugLayout() const - { - return debug_layout_; - } + //*************** region: native messages *************** - void SetDebugLayout(bool value); -#endif - - public: - //*************** region: events *************** - Event<events::UiEventArgs> activated_event; - Event<events::UiEventArgs> deactivated_event; - - Event<events::WindowNativeMessageEventArgs> native_message_event; - - private: - //*************** region: native operations *************** - - //Get the client rect in pixel. - RECT GetClientRectPixel(); - - bool IsMessageInQueue(UINT message); - - void SetCursorInternal(HCURSOR cursor); - - - //*************** region: native messages *************** - - void OnDestroyInternal(); - void OnPaintInternal(); - void OnResizeInternal(int new_width, int new_height); - - void OnSetFocusInternal(); - void OnKillFocusInternal(); - - void OnMouseMoveInternal(POINT point); - void OnMouseLeaveInternal(); - void OnMouseDownInternal(MouseButton button, POINT point); - void OnMouseUpInternal(MouseButton button, POINT point); - - void OnMouseWheelInternal(short delta, POINT point); - void OnKeyDownInternal(int virtual_code); - void OnKeyUpInternal(int virtual_code); - void OnCharInternal(wchar_t c); - - void OnActivatedInternal(); - void OnDeactivatedInternal(); - - //*************** region: event dispatcher helper *************** - - void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point); - - private: - bool delete_this_on_destroy_ = true; - - HWND hwnd_ = nullptr; - Window* parent_window_ = nullptr; - std::shared_ptr<graph::WindowRenderTarget> render_target_{}; - - Control* mouse_hover_control_ = nullptr; - - bool window_focus_ = false; - Control* focus_control_ = this; // "focus_control_" can't be nullptr - - Control* mouse_capture_control_ = nullptr; - - bool is_layout_invalid_ = false; + void OnDestroyInternal(); + void OnPaintInternal(); + void OnResizeInternal(int new_width, int new_height); + + void OnSetFocusInternal(); + void OnKillFocusInternal(); + + void OnMouseMoveInternal(POINT point); + void OnMouseLeaveInternal(); + void OnMouseDownInternal(MouseButton button, POINT point); + void OnMouseUpInternal(MouseButton button, POINT point); + + void OnMouseWheelInternal(short delta, POINT point); + void OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + void OnCharInternal(wchar_t c); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + //*************** region: event dispatcher helper *************** + + void DispatchMouseHoverControlChangeEvent(Control* old_control, + Control* new_control, + const Point& point); + + private: + bool delete_this_on_destroy_ = true; + + HWND hwnd_ = nullptr; + Window* parent_window_ = nullptr; + std::shared_ptr<graph::WindowRenderTarget> render_target_{}; + + Control* mouse_hover_control_ = nullptr; + + bool window_focus_ = false; + Control* focus_control_ = this; // "focus_control_" can't be nullptr + + Control* mouse_capture_control_ = nullptr; + + bool is_layout_invalid_ = false; #ifdef CRU_DEBUG_LAYOUT - bool debug_layout_ = false; + bool debug_layout_ = false; #endif - }; -} +}; +} // namespace cru::ui |