From efdce672123284847bd7fb6f12ac1ec96f28f3ef Mon Sep 17 00:00:00 2001 From: crupest Date: Wed, 7 Nov 2018 21:40:04 +0800 Subject: Make all header *.hpp . --- src/ui/animations/animation.cpp | 2 +- src/ui/animations/animation.h | 131 ----------- src/ui/animations/animation.hpp | 131 +++++++++++ src/ui/border_property.cpp | 4 +- src/ui/border_property.h | 83 ------- src/ui/border_property.hpp | 83 +++++++ src/ui/control.cpp | 10 +- src/ui/control.h | 445 -------------------------------------- src/ui/control.hpp | 445 ++++++++++++++++++++++++++++++++++++++ src/ui/controls/button.cpp | 4 +- src/ui/controls/button.h | 42 ---- src/ui/controls/button.hpp | 42 ++++ src/ui/controls/linear_layout.cpp | 2 +- src/ui/controls/linear_layout.h | 47 ---- src/ui/controls/linear_layout.hpp | 47 ++++ src/ui/controls/text_block.cpp | 4 +- src/ui/controls/text_block.h | 38 ---- src/ui/controls/text_block.hpp | 38 ++++ src/ui/controls/text_box.cpp | 6 +- src/ui/controls/text_box.h | 57 ----- src/ui/controls/text_box.hpp | 57 +++++ src/ui/controls/text_control.cpp | 8 +- src/ui/controls/text_control.h | 101 --------- src/ui/controls/text_control.hpp | 101 +++++++++ src/ui/controls/toggle_button.cpp | 6 +- src/ui/controls/toggle_button.h | 65 ------ src/ui/controls/toggle_button.hpp | 65 ++++++ src/ui/cursor.cpp | 4 +- src/ui/cursor.h | 38 ---- src/ui/cursor.hpp | 38 ++++ src/ui/events/ui_event.cpp | 4 +- src/ui/events/ui_event.h | 315 --------------------------- src/ui/events/ui_event.hpp | 315 +++++++++++++++++++++++++++ src/ui/layout_base.cpp | 8 +- src/ui/layout_base.h | 188 ---------------- src/ui/layout_base.hpp | 188 ++++++++++++++++ src/ui/ui_base.cpp | 4 +- src/ui/ui_base.h | 157 -------------- src/ui/ui_base.hpp | 157 ++++++++++++++ src/ui/window.cpp | 10 +- src/ui/window.h | 302 -------------------------- src/ui/window.hpp | 302 ++++++++++++++++++++++++++ 42 files changed, 2047 insertions(+), 2047 deletions(-) delete mode 100644 src/ui/animations/animation.h create mode 100644 src/ui/animations/animation.hpp delete mode 100644 src/ui/border_property.h create mode 100644 src/ui/border_property.hpp delete mode 100644 src/ui/control.h create mode 100644 src/ui/control.hpp delete mode 100644 src/ui/controls/button.h create mode 100644 src/ui/controls/button.hpp delete mode 100644 src/ui/controls/linear_layout.h create mode 100644 src/ui/controls/linear_layout.hpp delete mode 100644 src/ui/controls/text_block.h create mode 100644 src/ui/controls/text_block.hpp delete mode 100644 src/ui/controls/text_box.h create mode 100644 src/ui/controls/text_box.hpp delete mode 100644 src/ui/controls/text_control.h create mode 100644 src/ui/controls/text_control.hpp delete mode 100644 src/ui/controls/toggle_button.h create mode 100644 src/ui/controls/toggle_button.hpp delete mode 100644 src/ui/cursor.h create mode 100644 src/ui/cursor.hpp delete mode 100644 src/ui/events/ui_event.h create mode 100644 src/ui/events/ui_event.hpp delete mode 100644 src/ui/layout_base.h create mode 100644 src/ui/layout_base.hpp delete mode 100644 src/ui/ui_base.h create mode 100644 src/ui/ui_base.hpp delete mode 100644 src/ui/window.h create mode 100644 src/ui/window.hpp (limited to 'src/ui') diff --git a/src/ui/animations/animation.cpp b/src/ui/animations/animation.cpp index ca0fe8bc..33c743cf 100644 --- a/src/ui/animations/animation.cpp +++ b/src/ui/animations/animation.cpp @@ -1,4 +1,4 @@ -#include "animation.h" +#include "animation.hpp" #include diff --git a/src/ui/animations/animation.h b/src/ui/animations/animation.h deleted file mode 100644 index 91a666c9..00000000 --- a/src/ui/animations/animation.h +++ /dev/null @@ -1,131 +0,0 @@ -#pragma once - -#include - -#include "base.h" -#include "application.h" -#include "timer.h" - -namespace cru::ui::animations -{ - using AnimationTimeUnit = FloatSecond; - - struct IAnimationDelegate : virtual Interface - { - virtual void Cancel() = 0; - }; - - using AnimationDelegatePtr = std::shared_ptr; - - using AnimationStepHandler = std::function; - using AnimationStartHandler = std::function; - using AnimationFinishHandler = std::function; - using AnimationCancelHandler = std::function; - - namespace details - { - class Animation; - using AnimationPtr = std::unique_ptr; - - class AnimationInfo - { - public: - AnimationInfo(String tag, const AnimationTimeUnit duration) - : tag(std::move(tag)), - duration(duration) - { - - } - AnimationInfo(const AnimationInfo& other) = default; - AnimationInfo(AnimationInfo&& other) = default; - AnimationInfo& operator=(const AnimationInfo& other) = default; - AnimationInfo& operator=(AnimationInfo&& other) = default; - ~AnimationInfo() = default; - - String tag; - AnimationTimeUnit duration; - std::vector step_handlers{}; - std::vector start_handlers{}; - std::vector finish_handlers{}; - std::vector cancel_handlers{}; - }; - - class AnimationManager : public Object - { - public: - static AnimationManager* GetInstance() - { - return Application::GetInstance()->GetAnimationManager(); - } - - public: - AnimationManager(); - AnimationManager(const AnimationManager& other) = delete; - AnimationManager(AnimationManager&& other) = delete; - AnimationManager& operator=(const AnimationManager& other) = delete; - AnimationManager& operator=(AnimationManager&& other) = delete; - ~AnimationManager() override; - - AnimationDelegatePtr CreateAnimation(AnimationInfo info); - void RemoveAnimation(const String& tag); - - private: - void SetTimer(); - void KillTimer(); - - private: - std::unordered_map animations_; - std::optional timer_; - }; - } - - class AnimationBuilder : public Object - { - public: - AnimationBuilder(String tag, const AnimationTimeUnit duration) - : info_(std::move(tag), duration) - { - - } - - AnimationBuilder& AddStepHandler(const AnimationStepHandler& handler) - { - CheckValid(); - info_.step_handlers.push_back(handler); - return *this; - } - - AnimationBuilder& AddStartHandler(const AnimationStartHandler& handler) - { - CheckValid(); - info_.start_handlers.push_back(handler); - return *this; - } - - AnimationBuilder& AddFinishHandler(const AnimationFinishHandler& handler) - { - CheckValid(); - info_.finish_handlers.push_back(handler); - return *this; - } - - AnimationBuilder& AddCancelHandler(const AnimationCancelHandler& handler) - { - CheckValid(); - info_.cancel_handlers.push_back(handler); - return *this; - } - - AnimationDelegatePtr Start(); - - private: - void CheckValid() const - { - if (!valid_) - throw std::runtime_error("The animation builder is invalid."); - } - - bool valid_ = true; - details::AnimationInfo info_; - }; -} diff --git a/src/ui/animations/animation.hpp b/src/ui/animations/animation.hpp new file mode 100644 index 00000000..99389f33 --- /dev/null +++ b/src/ui/animations/animation.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include + +#include "base.hpp" +#include "application.hpp" +#include "timer.hpp" + +namespace cru::ui::animations +{ + using AnimationTimeUnit = FloatSecond; + + struct IAnimationDelegate : virtual Interface + { + virtual void Cancel() = 0; + }; + + using AnimationDelegatePtr = std::shared_ptr; + + using AnimationStepHandler = std::function; + using AnimationStartHandler = std::function; + using AnimationFinishHandler = std::function; + using AnimationCancelHandler = std::function; + + namespace details + { + class Animation; + using AnimationPtr = std::unique_ptr; + + class AnimationInfo + { + public: + AnimationInfo(String tag, const AnimationTimeUnit duration) + : tag(std::move(tag)), + duration(duration) + { + + } + AnimationInfo(const AnimationInfo& other) = default; + AnimationInfo(AnimationInfo&& other) = default; + AnimationInfo& operator=(const AnimationInfo& other) = default; + AnimationInfo& operator=(AnimationInfo&& other) = default; + ~AnimationInfo() = default; + + String tag; + AnimationTimeUnit duration; + std::vector step_handlers{}; + std::vector start_handlers{}; + std::vector finish_handlers{}; + std::vector cancel_handlers{}; + }; + + class AnimationManager : public Object + { + public: + static AnimationManager* GetInstance() + { + return Application::GetInstance()->GetAnimationManager(); + } + + public: + AnimationManager(); + AnimationManager(const AnimationManager& other) = delete; + AnimationManager(AnimationManager&& other) = delete; + AnimationManager& operator=(const AnimationManager& other) = delete; + AnimationManager& operator=(AnimationManager&& other) = delete; + ~AnimationManager() override; + + AnimationDelegatePtr CreateAnimation(AnimationInfo info); + void RemoveAnimation(const String& tag); + + private: + void SetTimer(); + void KillTimer(); + + private: + std::unordered_map animations_; + std::optional timer_; + }; + } + + class AnimationBuilder : public Object + { + public: + AnimationBuilder(String tag, const AnimationTimeUnit duration) + : info_(std::move(tag), duration) + { + + } + + AnimationBuilder& AddStepHandler(const AnimationStepHandler& handler) + { + CheckValid(); + info_.step_handlers.push_back(handler); + return *this; + } + + AnimationBuilder& AddStartHandler(const AnimationStartHandler& handler) + { + CheckValid(); + info_.start_handlers.push_back(handler); + return *this; + } + + AnimationBuilder& AddFinishHandler(const AnimationFinishHandler& handler) + { + CheckValid(); + info_.finish_handlers.push_back(handler); + return *this; + } + + AnimationBuilder& AddCancelHandler(const AnimationCancelHandler& handler) + { + CheckValid(); + info_.cancel_handlers.push_back(handler); + return *this; + } + + AnimationDelegatePtr Start(); + + private: + void CheckValid() const + { + if (!valid_) + throw std::runtime_error("The animation builder is invalid."); + } + + bool valid_ = true; + details::AnimationInfo info_; + }; +} diff --git a/src/ui/border_property.cpp b/src/ui/border_property.cpp index f716a8be..7f61c1b7 100644 --- a/src/ui/border_property.cpp +++ b/src/ui/border_property.cpp @@ -1,6 +1,6 @@ -#include "border_property.h" +#include "border_property.hpp" -#include "graph/graph.h" +#include "graph/graph.hpp" namespace cru::ui { diff --git a/src/ui/border_property.h b/src/ui/border_property.h deleted file mode 100644 index ce16dea7..00000000 --- a/src/ui/border_property.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -#include "system_headers.h" - -#include "base.h" - - -namespace cru::ui -{ - class BorderProperty final - { - public: - BorderProperty(); - explicit BorderProperty(Microsoft::WRL::ComPtr brush); - 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 GetBrush() const - { - return brush_; - } - - float GetStrokeWidth() const - { - return stroke_width_; - } - - Microsoft::WRL::ComPtr GetStrokeStyle() const - { - return stroke_style_; - } - - float GetRadiusX() const - { - return radius_x_; - } - - float GetRadiusY() const - { - return radius_y_; - } - - void SetBrush(Microsoft::WRL::ComPtr 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 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 brush_; - float stroke_width_ = 1.0f; - Microsoft::WRL::ComPtr stroke_style_ = nullptr; - float radius_x_ = 0.0f; - float radius_y_ = 0.0f; - }; -} diff --git a/src/ui/border_property.hpp b/src/ui/border_property.hpp new file mode 100644 index 00000000..a280fe44 --- /dev/null +++ b/src/ui/border_property.hpp @@ -0,0 +1,83 @@ +#pragma once + +#include "system_headers.hpp" + +#include "base.hpp" + + +namespace cru::ui +{ + class BorderProperty final + { + public: + BorderProperty(); + explicit BorderProperty(Microsoft::WRL::ComPtr brush); + 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 GetBrush() const + { + return brush_; + } + + float GetStrokeWidth() const + { + return stroke_width_; + } + + Microsoft::WRL::ComPtr GetStrokeStyle() const + { + return stroke_style_; + } + + float GetRadiusX() const + { + return radius_x_; + } + + float GetRadiusY() const + { + return radius_y_; + } + + void SetBrush(Microsoft::WRL::ComPtr 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 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 brush_; + float stroke_width_ = 1.0f; + Microsoft::WRL::ComPtr stroke_style_ = nullptr; + float radius_x_ = 0.0f; + float radius_y_ = 0.0f; + }; +} diff --git a/src/ui/control.cpp b/src/ui/control.cpp index ec8420c1..bb3e35f8 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -1,11 +1,11 @@ -#include "control.h" +#include "control.hpp" #include -#include "window.h" -#include "graph/graph.h" -#include "exception.h" -#include "cru_debug.h" +#include "window.hpp" +#include "graph/graph.hpp" +#include "exception.hpp" +#include "cru_debug.hpp" namespace cru::ui { diff --git a/src/ui/control.h b/src/ui/control.h deleted file mode 100644 index 020f959e..00000000 --- a/src/ui/control.h +++ /dev/null @@ -1,445 +0,0 @@ -#pragma once - -#include "system_headers.h" -#include -#include -#include -#include - -#include "base.h" -#include "format.h" -#include "ui_base.h" -#include "layout_base.h" -#include "events/ui_event.h" -#include "border_property.h" -#include "cursor.h" - -namespace cru::ui -{ - class Control; - class Window; - - - //the position cache - struct ControlPositionCache - { - //The lefttop relative to the ancestor. - Point lefttop_position_absolute; - }; - - class Control : public Object - { - friend class Window; - friend class LayoutManager; - - protected: - struct WindowConstructorTag {}; //Used for constructor for class Window. - - explicit Control(bool container = false); - - // Used only for creating Window. It will set window_ as window. - Control(WindowConstructorTag, Window* window); - - public: - Control(const Control& other) = delete; - Control(Control&& other) = delete; - Control& operator=(const Control& other) = delete; - Control& operator=(Control&& other) = delete; - ~Control() override; - - public: - - //*************** region: tree *************** - virtual StringView GetControlType() const = 0; - - bool IsContainer() const - { - return is_container_; - } - - //Get parent of control, return nullptr if it has no parent. - Control* GetParent() const - { - return parent_; - } - - //Return a immutable vector of all children. - const std::vector& GetChildren() const; - - //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); - - //Get the ancestor of the control. - Control* GetAncestor(); - - //Get the window if attached, otherwise, return nullptr. - Window* GetWindow() const - { - return window_; - } - - //Traverse the tree rooted the control including itself. - void TraverseDescendants(const std::function& predicate); - - //*************** region: position and size *************** - // Position and size part must be isolated from layout part. - // All the operations in this part must be done independently. - // And layout part must use api of this part. - - //Get the lefttop relative to its parent. - virtual Point GetPositionRelative(); - - //Set the lefttop relative to its parent. - virtual void SetPositionRelative(const Point& position); - - //Get the actual size. - virtual Size GetSize(); - - //Set the actual size directly without re-layout. - virtual void SetSize(const Size& size); - - //Get lefttop relative to ancestor. This is only valid when - //attached to window. Notice that the value is cached. - //You can invalidate and recalculate it by calling "InvalidatePositionCache". - Point GetPositionAbsolute() const; - - //Local point to absolute point. - Point ControlToWindow(const Point& point) const; - - //Absolute point to local point. - Point WindowToControl(const Point& point) const; - - virtual bool IsPointInside(const Point& point); - - - //*************** region: graphic *************** - - //Draw this control and its child controls. - void Draw(ID2D1DeviceContext* device_context); - - virtual void Repaint(); - - //*************** region: focus *************** - - bool RequestFocus(); - - bool HasFocus(); - - bool IsFocusOnPressed() const - { - return is_focus_on_pressed_; - } - - void SetFocusOnPressed(const bool value) - { - is_focus_on_pressed_ = value; - } - - //*************** region: layout *************** - - void InvalidateLayout(); - - void Measure(const Size& available_size); - - void Layout(const Rect& rect); - - Size GetDesiredSize() const; - - void SetDesiredSize(const Size& desired_size); - - BasicLayoutParams* GetLayoutParams() - { - return &layout_params_; - } - - Rect GetRect(RectRange range); - - Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content); - - //*************** region: border *************** - - BorderProperty& GetBorderProperty() - { - return border_property_; - } - - void InvalidateBorder(); - - bool IsBordered() const - { - return is_bordered_; - } - - void SetBordered(bool bordered); - - - //*************** region: additional properties *************** - template - std::optional GetAdditionalProperty(const String& key) - { - try - { - const auto find_result = additional_properties_.find(key); - if (find_result != additional_properties_.cend()) - return std::any_cast(find_result->second); - else - return std::nullopt; - } - catch (const std::bad_any_cast&) - { - throw std::runtime_error(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name())); - } - } - - template - void SetAdditionalProperty(const String& key, const T& value) - { - additional_properties_[key] = std::make_any(value); - } - - template - void SetAdditionalProperty(const String& key, T&& value) - { - additional_properties_[key] = std::make_any(std::move(value)); - } - - - //*************** region: cursor *************** - // If cursor is set to null, then it uses parent's cursor. - // Window's cursor can't be null. - - Cursor::Ptr GetCursor() const - { - return cursor_; - } - - void SetCursor(const Cursor::Ptr& cursor); - - - //*************** region: events *************** - //Raised when mouse enter the control. - events::MouseEvent mouse_enter_event; - //Raised when mouse is leave the control. - events::MouseEvent mouse_leave_event; - //Raised when mouse is move in the control. - events::MouseEvent mouse_move_event; - //Raised when a mouse button is pressed in the control. - events::MouseButtonEvent mouse_down_event; - //Raised when a mouse button is released in the control. - events::MouseButtonEvent 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::MouseButtonEvent mouse_click_event; - - events::KeyEvent key_down_event; - events::KeyEvent key_up_event; - events::CharEvent char_event; - - events::FocusChangeEvent get_focus_event; - events::FocusChangeEvent lose_focus_event; - - events::DrawEvent draw_event; - - events::PositionChangedEvent position_changed_event; - events::SizeChangedEvent size_changed_event; - - protected: - //Invoked when a child is added. Overrides should invoke base. - virtual void OnAddChild(Control* child); - //Invoked when a child is removed. Overrides should invoke base. - virtual void OnRemoveChild(Control* child); - - //Invoked when the control is attached to a window. Overrides should invoke base. - virtual void OnAttachToWindow(Window* window); - //Invoked when the control is detached to a window. Overrides should invoke base. - virtual void OnDetachToWindow(Window* window); - - private: - void OnDraw(ID2D1DeviceContext* device_context); - - protected: - virtual void OnDrawContent(ID2D1DeviceContext* device_context); - - // For a event, the window event system will first dispatch event to core functions. - // Therefore for particular controls, you should do essential actions in core functions, - // and override version should invoke base version. The base core function - // in "Control" class will call corresponding non-core function and call "Raise" on - // event objects. So user custom actions should be done by overriding non-core function - // and calling the base version is optional. - - //*************** region: position and size event *************** - virtual void OnPositionChanged(events::PositionChangedEventArgs& args); - virtual void OnSizeChanged(events::SizeChangedEventArgs& args); - - virtual void OnPositionChangedCore(events::PositionChangedEventArgs& args); - virtual void OnSizeChangedCore(events::SizeChangedEventArgs& args); - - void RaisePositionChangedEvent(events::PositionChangedEventArgs& args); - void RaiseSizeChangedEvent(events::SizeChangedEventArgs& args); - - //*************** region: mouse event *************** - virtual void OnMouseEnter(events::MouseEventArgs& args); - virtual void OnMouseLeave(events::MouseEventArgs& args); - virtual void OnMouseMove(events::MouseEventArgs& args); - virtual void OnMouseDown(events::MouseButtonEventArgs& args); - virtual void OnMouseUp(events::MouseButtonEventArgs& args); - virtual void OnMouseClick(events::MouseButtonEventArgs& args); - - virtual void OnMouseEnterCore(events::MouseEventArgs& args); - virtual void OnMouseLeaveCore(events::MouseEventArgs& args); - virtual void OnMouseMoveCore(events::MouseEventArgs& args); - virtual void OnMouseDownCore(events::MouseButtonEventArgs& args); - virtual void OnMouseUpCore(events::MouseButtonEventArgs& args); - virtual void OnMouseClickCore(events::MouseButtonEventArgs& args); - - void RaiseMouseEnterEvent(events::MouseEventArgs& args); - void RaiseMouseLeaveEvent(events::MouseEventArgs& args); - void RaiseMouseMoveEvent(events::MouseEventArgs& args); - void RaiseMouseDownEvent(events::MouseButtonEventArgs& args); - void RaiseMouseUpEvent(events::MouseButtonEventArgs& args); - void RaiseMouseClickEvent(events::MouseButtonEventArgs& args); - - virtual void OnMouseClickBegin(MouseButton button); - virtual void OnMouseClickEnd(MouseButton button); - - //*************** region: keyboard event *************** - virtual void OnKeyDown(events::KeyEventArgs& args); - virtual void OnKeyUp(events::KeyEventArgs& args); - virtual void OnChar(events::CharEventArgs& args); - - virtual void OnKeyDownCore(events::KeyEventArgs& args); - virtual void OnKeyUpCore(events::KeyEventArgs& args); - virtual void OnCharCore(events::CharEventArgs& args); - - void RaiseKeyDownEvent(events::KeyEventArgs& args); - void RaiseKeyUpEvent(events::KeyEventArgs& args); - void RaiseCharEvent(events::CharEventArgs& args); - - //*************** region: focus event *************** - virtual void OnGetFocus(events::FocusChangeEventArgs& args); - virtual void OnLoseFocus(events::FocusChangeEventArgs& args); - - virtual void OnGetFocusCore(events::FocusChangeEventArgs& args); - virtual void OnLoseFocusCore(events::FocusChangeEventArgs& args); - - void RaiseGetFocusEvent(events::FocusChangeEventArgs& args); - void RaiseLoseFocusEvent(events::FocusChangeEventArgs& args); - - //*************** region: layout *************** - Size OnMeasureCore(const Size& available_size); - void OnLayoutCore(const Rect& rect); - - virtual Size OnMeasureContent(const Size& available_size); - virtual void OnLayoutContent(const Rect& rect); - - private: - // Only for layout manager to use. - // Check if the old position is updated to current position. - // If not, then a notify of position change and update will - // be done. - void CheckAndNotifyPositionChanged(); - - void ThrowIfNotContainer() const - { - if (!is_container_) - throw std::runtime_error("You can't perform such operation on a non-container control."); - } - - private: - bool is_container_; - - protected: - Window * window_ = nullptr; // protected for Window class to write it as itself in constructor. - - private: - Control * parent_ = nullptr; - std::vector children_{}; - - // When position is changed and notification hasn't been - // sent, it will be the old position. When position is changed - // more than once, it will be the oldest position since last - // notification. If notification has been sent, it will be updated - // to position_. - Point old_position_ = Point::Zero(); - Point position_ = Point::Zero(); - Size size_ = Size::Zero(); - - ControlPositionCache position_cache_{}; - - bool is_mouse_inside_ = false; - - std::unordered_map is_mouse_click_valid_map_ - { - { MouseButton::Left, true }, - { MouseButton::Middle, true }, - { MouseButton::Right, true } - }; // used for clicking determination - - BasicLayoutParams layout_params_{}; - Size desired_size_ = Size::Zero(); - - bool is_bordered_ = false; - BorderProperty border_property_; - - std::unordered_map additional_properties_{}; - - bool is_focus_on_pressed_ = true; - -#ifdef CRU_DEBUG_LAYOUT - Microsoft::WRL::ComPtr margin_geometry_; - Microsoft::WRL::ComPtr padding_geometry_; -#endif - - Cursor::Ptr cursor_{}; - }; - - // Find the lowest common ancestor. - // Return nullptr if "left" and "right" are not in the same tree. - Control* FindLowestCommonAncestor(Control* left, Control* right); - - // Return the ancestor if one control is the ancestor of the other one, otherwise nullptr. - Control* IsAncestorOrDescendant(Control* left, Control* right); - - template - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args) - { - static_assert(std::is_base_of_v, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - return control; - } - - - template - TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward(args)...); - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } - - template - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } - - using ControlList = std::initializer_list; -} diff --git a/src/ui/control.hpp b/src/ui/control.hpp new file mode 100644 index 00000000..26be653a --- /dev/null +++ b/src/ui/control.hpp @@ -0,0 +1,445 @@ +#pragma once + +#include "system_headers.hpp" +#include +#include +#include +#include + +#include "base.hpp" +#include "format.hpp" +#include "ui_base.hpp" +#include "layout_base.hpp" +#include "events/ui_event.hpp" +#include "border_property.hpp" +#include "cursor.hpp" + +namespace cru::ui +{ + class Control; + class Window; + + + //the position cache + struct ControlPositionCache + { + //The lefttop relative to the ancestor. + Point lefttop_position_absolute; + }; + + class Control : public Object + { + friend class Window; + friend class LayoutManager; + + protected: + struct WindowConstructorTag {}; //Used for constructor for class Window. + + explicit Control(bool container = false); + + // Used only for creating Window. It will set window_ as window. + Control(WindowConstructorTag, Window* window); + + public: + Control(const Control& other) = delete; + Control(Control&& other) = delete; + Control& operator=(const Control& other) = delete; + Control& operator=(Control&& other) = delete; + ~Control() override; + + public: + + //*************** region: tree *************** + virtual StringView GetControlType() const = 0; + + bool IsContainer() const + { + return is_container_; + } + + //Get parent of control, return nullptr if it has no parent. + Control* GetParent() const + { + return parent_; + } + + //Return a immutable vector of all children. + const std::vector& GetChildren() const; + + //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); + + //Get the ancestor of the control. + Control* GetAncestor(); + + //Get the window if attached, otherwise, return nullptr. + Window* GetWindow() const + { + return window_; + } + + //Traverse the tree rooted the control including itself. + void TraverseDescendants(const std::function& predicate); + + //*************** region: position and size *************** + // Position and size part must be isolated from layout part. + // All the operations in this part must be done independently. + // And layout part must use api of this part. + + //Get the lefttop relative to its parent. + virtual Point GetPositionRelative(); + + //Set the lefttop relative to its parent. + virtual void SetPositionRelative(const Point& position); + + //Get the actual size. + virtual Size GetSize(); + + //Set the actual size directly without re-layout. + virtual void SetSize(const Size& size); + + //Get lefttop relative to ancestor. This is only valid when + //attached to window. Notice that the value is cached. + //You can invalidate and recalculate it by calling "InvalidatePositionCache". + Point GetPositionAbsolute() const; + + //Local point to absolute point. + Point ControlToWindow(const Point& point) const; + + //Absolute point to local point. + Point WindowToControl(const Point& point) const; + + virtual bool IsPointInside(const Point& point); + + + //*************** region: graphic *************** + + //Draw this control and its child controls. + void Draw(ID2D1DeviceContext* device_context); + + virtual void Repaint(); + + //*************** region: focus *************** + + bool RequestFocus(); + + bool HasFocus(); + + bool IsFocusOnPressed() const + { + return is_focus_on_pressed_; + } + + void SetFocusOnPressed(const bool value) + { + is_focus_on_pressed_ = value; + } + + //*************** region: layout *************** + + void InvalidateLayout(); + + void Measure(const Size& available_size); + + void Layout(const Rect& rect); + + Size GetDesiredSize() const; + + void SetDesiredSize(const Size& desired_size); + + BasicLayoutParams* GetLayoutParams() + { + return &layout_params_; + } + + Rect GetRect(RectRange range); + + Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content); + + //*************** region: border *************** + + BorderProperty& GetBorderProperty() + { + return border_property_; + } + + void InvalidateBorder(); + + bool IsBordered() const + { + return is_bordered_; + } + + void SetBordered(bool bordered); + + + //*************** region: additional properties *************** + template + std::optional GetAdditionalProperty(const String& key) + { + try + { + const auto find_result = additional_properties_.find(key); + if (find_result != additional_properties_.cend()) + return std::any_cast(find_result->second); + else + return std::nullopt; + } + catch (const std::bad_any_cast&) + { + throw std::runtime_error(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name())); + } + } + + template + void SetAdditionalProperty(const String& key, const T& value) + { + additional_properties_[key] = std::make_any(value); + } + + template + void SetAdditionalProperty(const String& key, T&& value) + { + additional_properties_[key] = std::make_any(std::move(value)); + } + + + //*************** region: cursor *************** + // If cursor is set to null, then it uses parent's cursor. + // Window's cursor can't be null. + + Cursor::Ptr GetCursor() const + { + return cursor_; + } + + void SetCursor(const Cursor::Ptr& cursor); + + + //*************** region: events *************** + //Raised when mouse enter the control. + events::MouseEvent mouse_enter_event; + //Raised when mouse is leave the control. + events::MouseEvent mouse_leave_event; + //Raised when mouse is move in the control. + events::MouseEvent mouse_move_event; + //Raised when a mouse button is pressed in the control. + events::MouseButtonEvent mouse_down_event; + //Raised when a mouse button is released in the control. + events::MouseButtonEvent 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::MouseButtonEvent mouse_click_event; + + events::KeyEvent key_down_event; + events::KeyEvent key_up_event; + events::CharEvent char_event; + + events::FocusChangeEvent get_focus_event; + events::FocusChangeEvent lose_focus_event; + + events::DrawEvent draw_event; + + events::PositionChangedEvent position_changed_event; + events::SizeChangedEvent size_changed_event; + + protected: + //Invoked when a child is added. Overrides should invoke base. + virtual void OnAddChild(Control* child); + //Invoked when a child is removed. Overrides should invoke base. + virtual void OnRemoveChild(Control* child); + + //Invoked when the control is attached to a window. Overrides should invoke base. + virtual void OnAttachToWindow(Window* window); + //Invoked when the control is detached to a window. Overrides should invoke base. + virtual void OnDetachToWindow(Window* window); + + private: + void OnDraw(ID2D1DeviceContext* device_context); + + protected: + virtual void OnDrawContent(ID2D1DeviceContext* device_context); + + // For a event, the window event system will first dispatch event to core functions. + // Therefore for particular controls, you should do essential actions in core functions, + // and override version should invoke base version. The base core function + // in "Control" class will call corresponding non-core function and call "Raise" on + // event objects. So user custom actions should be done by overriding non-core function + // and calling the base version is optional. + + //*************** region: position and size event *************** + virtual void OnPositionChanged(events::PositionChangedEventArgs& args); + virtual void OnSizeChanged(events::SizeChangedEventArgs& args); + + virtual void OnPositionChangedCore(events::PositionChangedEventArgs& args); + virtual void OnSizeChangedCore(events::SizeChangedEventArgs& args); + + void RaisePositionChangedEvent(events::PositionChangedEventArgs& args); + void RaiseSizeChangedEvent(events::SizeChangedEventArgs& args); + + //*************** region: mouse event *************** + virtual void OnMouseEnter(events::MouseEventArgs& args); + virtual void OnMouseLeave(events::MouseEventArgs& args); + virtual void OnMouseMove(events::MouseEventArgs& args); + virtual void OnMouseDown(events::MouseButtonEventArgs& args); + virtual void OnMouseUp(events::MouseButtonEventArgs& args); + virtual void OnMouseClick(events::MouseButtonEventArgs& args); + + virtual void OnMouseEnterCore(events::MouseEventArgs& args); + virtual void OnMouseLeaveCore(events::MouseEventArgs& args); + virtual void OnMouseMoveCore(events::MouseEventArgs& args); + virtual void OnMouseDownCore(events::MouseButtonEventArgs& args); + virtual void OnMouseUpCore(events::MouseButtonEventArgs& args); + virtual void OnMouseClickCore(events::MouseButtonEventArgs& args); + + void RaiseMouseEnterEvent(events::MouseEventArgs& args); + void RaiseMouseLeaveEvent(events::MouseEventArgs& args); + void RaiseMouseMoveEvent(events::MouseEventArgs& args); + void RaiseMouseDownEvent(events::MouseButtonEventArgs& args); + void RaiseMouseUpEvent(events::MouseButtonEventArgs& args); + void RaiseMouseClickEvent(events::MouseButtonEventArgs& args); + + virtual void OnMouseClickBegin(MouseButton button); + virtual void OnMouseClickEnd(MouseButton button); + + //*************** region: keyboard event *************** + virtual void OnKeyDown(events::KeyEventArgs& args); + virtual void OnKeyUp(events::KeyEventArgs& args); + virtual void OnChar(events::CharEventArgs& args); + + virtual void OnKeyDownCore(events::KeyEventArgs& args); + virtual void OnKeyUpCore(events::KeyEventArgs& args); + virtual void OnCharCore(events::CharEventArgs& args); + + void RaiseKeyDownEvent(events::KeyEventArgs& args); + void RaiseKeyUpEvent(events::KeyEventArgs& args); + void RaiseCharEvent(events::CharEventArgs& args); + + //*************** region: focus event *************** + virtual void OnGetFocus(events::FocusChangeEventArgs& args); + virtual void OnLoseFocus(events::FocusChangeEventArgs& args); + + virtual void OnGetFocusCore(events::FocusChangeEventArgs& args); + virtual void OnLoseFocusCore(events::FocusChangeEventArgs& args); + + void RaiseGetFocusEvent(events::FocusChangeEventArgs& args); + void RaiseLoseFocusEvent(events::FocusChangeEventArgs& args); + + //*************** region: layout *************** + Size OnMeasureCore(const Size& available_size); + void OnLayoutCore(const Rect& rect); + + virtual Size OnMeasureContent(const Size& available_size); + virtual void OnLayoutContent(const Rect& rect); + + private: + // Only for layout manager to use. + // Check if the old position is updated to current position. + // If not, then a notify of position change and update will + // be done. + void CheckAndNotifyPositionChanged(); + + void ThrowIfNotContainer() const + { + if (!is_container_) + throw std::runtime_error("You can't perform such operation on a non-container control."); + } + + private: + bool is_container_; + + protected: + Window * window_ = nullptr; // protected for Window class to write it as itself in constructor. + + private: + Control * parent_ = nullptr; + std::vector children_{}; + + // When position is changed and notification hasn't been + // sent, it will be the old position. When position is changed + // more than once, it will be the oldest position since last + // notification. If notification has been sent, it will be updated + // to position_. + Point old_position_ = Point::Zero(); + Point position_ = Point::Zero(); + Size size_ = Size::Zero(); + + ControlPositionCache position_cache_{}; + + bool is_mouse_inside_ = false; + + std::unordered_map is_mouse_click_valid_map_ + { + { MouseButton::Left, true }, + { MouseButton::Middle, true }, + { MouseButton::Right, true } + }; // used for clicking determination + + BasicLayoutParams layout_params_{}; + Size desired_size_ = Size::Zero(); + + bool is_bordered_ = false; + BorderProperty border_property_; + + std::unordered_map additional_properties_{}; + + bool is_focus_on_pressed_ = true; + +#ifdef CRU_DEBUG_LAYOUT + Microsoft::WRL::ComPtr margin_geometry_; + Microsoft::WRL::ComPtr padding_geometry_; +#endif + + Cursor::Ptr cursor_{}; + }; + + // Find the lowest common ancestor. + // Return nullptr if "left" and "right" are not in the same tree. + Control* FindLowestCommonAncestor(Control* left, Control* right); + + // Return the ancestor if one control is the ancestor of the other one, otherwise nullptr. + Control* IsAncestorOrDescendant(Control* left, Control* right); + + template + TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args) + { + static_assert(std::is_base_of_v, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward(args)...); + control->GetLayoutParams()->width = width; + control->GetLayoutParams()->height = height; + return control; + } + + + template + TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, Args&&... args) + { + static_assert(std::is_base_of_v, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward(args)...); + control->GetLayoutParams()->padding = padding; + control->GetLayoutParams()->margin = margin; + return control; + } + + template + TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, Args&&... args) + { + static_assert(std::is_base_of_v, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward(args)...); + control->GetLayoutParams()->width = width; + control->GetLayoutParams()->height = height; + control->GetLayoutParams()->padding = padding; + control->GetLayoutParams()->margin = margin; + return control; + } + + using ControlList = std::initializer_list; +} diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp index 11f8e31b..0422506b 100644 --- a/src/ui/controls/button.cpp +++ b/src/ui/controls/button.cpp @@ -1,6 +1,6 @@ -#include "button.h" +#include "button.hpp" -#include "graph/graph.h" +#include "graph/graph.hpp" namespace cru::ui::controls { diff --git a/src/ui/controls/button.h b/src/ui/controls/button.h deleted file mode 100644 index f50a6cbd..00000000 --- a/src/ui/controls/button.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -#include - -#include "ui/control.h" - -namespace cru::ui::controls -{ - class Button : public Control - { - public: - static constexpr auto control_type = L"Button"; - - static Button* Create(const std::initializer_list& children = std::initializer_list()) - { - const auto button = new Button(); - for (const auto control : children) - button->AddChild(control); - return button; - } - - protected: - Button(); - - public: - Button(const Button& other) = delete; - Button(Button&& other) = delete; - Button& operator=(const Button& other) = delete; - Button& operator=(Button&& other) = delete; - ~Button() override = default; - - StringView GetControlType() const override final; - - protected: - void OnMouseClickBegin(MouseButton button) override final; - void OnMouseClickEnd(MouseButton button) override final; - - private: - BorderProperty normal_border_; - BorderProperty pressed_border_; - }; -} diff --git a/src/ui/controls/button.hpp b/src/ui/controls/button.hpp new file mode 100644 index 00000000..50640b11 --- /dev/null +++ b/src/ui/controls/button.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "ui/control.hpp" + +namespace cru::ui::controls +{ + class Button : public Control + { + public: + static constexpr auto control_type = L"Button"; + + static Button* Create(const std::initializer_list& children = std::initializer_list()) + { + const auto button = new Button(); + for (const auto control : children) + button->AddChild(control); + return button; + } + + protected: + Button(); + + public: + Button(const Button& other) = delete; + Button(Button&& other) = delete; + Button& operator=(const Button& other) = delete; + Button& operator=(Button&& other) = delete; + ~Button() override = default; + + StringView GetControlType() const override final; + + protected: + void OnMouseClickBegin(MouseButton button) override final; + void OnMouseClickEnd(MouseButton button) override final; + + private: + BorderProperty normal_border_; + BorderProperty pressed_border_; + }; +} diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp index ed445f4c..f21a9933 100644 --- a/src/ui/controls/linear_layout.cpp +++ b/src/ui/controls/linear_layout.cpp @@ -1,4 +1,4 @@ -#include "linear_layout.h" +#include "linear_layout.hpp" #include diff --git a/src/ui/controls/linear_layout.h b/src/ui/controls/linear_layout.h deleted file mode 100644 index 021f4b7d..00000000 --- a/src/ui/controls/linear_layout.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "ui/control.h" - -namespace cru::ui::controls -{ - // Min length of main side in layout params is of no meaning. - // All children will layout from start and redundant length is blank. - class LinearLayout : public Control - { - public: - static constexpr auto control_type = L"LinearLayout"; - - enum class Orientation - { - Horizontal, - Vertical - }; - - static LinearLayout* Create(const Orientation orientation = Orientation::Vertical, const std::initializer_list& children = std::initializer_list()) - { - const auto linear_layout = new LinearLayout(orientation); - for (const auto control : children) - linear_layout->AddChild(control); - return linear_layout; - } - - protected: - explicit LinearLayout(Orientation orientation = Orientation::Vertical); - - public: - LinearLayout(const LinearLayout& other) = delete; - LinearLayout(LinearLayout&& other) = delete; - LinearLayout& operator=(const LinearLayout& other) = delete; - LinearLayout& operator=(LinearLayout&& other) = delete; - ~LinearLayout() override = default; - - StringView GetControlType() const override final; - - protected: - Size OnMeasureContent(const Size& available_size) override; - void OnLayoutContent(const Rect& rect) override; - - private: - Orientation orientation_; - }; -} diff --git a/src/ui/controls/linear_layout.hpp b/src/ui/controls/linear_layout.hpp new file mode 100644 index 00000000..b7ca42ec --- /dev/null +++ b/src/ui/controls/linear_layout.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "ui/control.hpp" + +namespace cru::ui::controls +{ + // Min length of main side in layout params is of no meaning. + // All children will layout from start and redundant length is blank. + class LinearLayout : public Control + { + public: + static constexpr auto control_type = L"LinearLayout"; + + enum class Orientation + { + Horizontal, + Vertical + }; + + static LinearLayout* Create(const Orientation orientation = Orientation::Vertical, const std::initializer_list& children = std::initializer_list()) + { + const auto linear_layout = new LinearLayout(orientation); + for (const auto control : children) + linear_layout->AddChild(control); + return linear_layout; + } + + protected: + explicit LinearLayout(Orientation orientation = Orientation::Vertical); + + public: + LinearLayout(const LinearLayout& other) = delete; + LinearLayout(LinearLayout&& other) = delete; + LinearLayout& operator=(const LinearLayout& other) = delete; + LinearLayout& operator=(LinearLayout&& other) = delete; + ~LinearLayout() override = default; + + StringView GetControlType() const override final; + + protected: + Size OnMeasureContent(const Size& available_size) override; + void OnLayoutContent(const Rect& rect) override; + + private: + Orientation orientation_; + }; +} diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp index e6c7fd7e..b8a7e8a6 100644 --- a/src/ui/controls/text_block.cpp +++ b/src/ui/controls/text_block.cpp @@ -1,6 +1,6 @@ -#include "text_block.h" +#include "text_block.hpp" -#include "ui/window.h" +#include "ui/window.hpp" namespace cru::ui::controls { diff --git a/src/ui/controls/text_block.h b/src/ui/controls/text_block.h deleted file mode 100644 index 681dc47b..00000000 --- a/src/ui/controls/text_block.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "text_control.h" - -namespace cru::ui::controls -{ - class TextBlock : public TextControl - { - public: - static constexpr auto control_type = L"TextBlock"; - - static TextBlock* Create( - const String& text = L"", - const Microsoft::WRL::ComPtr& init_text_format = nullptr, - const Microsoft::WRL::ComPtr& init_brush = nullptr) - { - const auto text_block = new TextBlock(init_text_format, init_brush); - text_block->SetText(text); - return text_block; - } - - using TextControl::SetSelectable; // Make this public. - - protected: - TextBlock( - const Microsoft::WRL::ComPtr& init_text_format, - const Microsoft::WRL::ComPtr& init_brush - ); - public: - TextBlock(const TextBlock& other) = delete; - TextBlock(TextBlock&& other) = delete; - TextBlock& operator=(const TextBlock& other) = delete; - TextBlock& operator=(TextBlock&& other) = delete; - ~TextBlock() override = default; - - StringView GetControlType() const override final; - }; -} diff --git a/src/ui/controls/text_block.hpp b/src/ui/controls/text_block.hpp new file mode 100644 index 00000000..b2b4aaf9 --- /dev/null +++ b/src/ui/controls/text_block.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "text_control.hpp" + +namespace cru::ui::controls +{ + class TextBlock : public TextControl + { + public: + static constexpr auto control_type = L"TextBlock"; + + static TextBlock* Create( + const String& text = L"", + const Microsoft::WRL::ComPtr& init_text_format = nullptr, + const Microsoft::WRL::ComPtr& init_brush = nullptr) + { + const auto text_block = new TextBlock(init_text_format, init_brush); + text_block->SetText(text); + return text_block; + } + + using TextControl::SetSelectable; // Make this public. + + protected: + TextBlock( + const Microsoft::WRL::ComPtr& init_text_format, + const Microsoft::WRL::ComPtr& init_brush + ); + public: + TextBlock(const TextBlock& other) = delete; + TextBlock(TextBlock&& other) = delete; + TextBlock& operator=(const TextBlock& other) = delete; + TextBlock& operator=(TextBlock&& other) = delete; + ~TextBlock() override = default; + + StringView GetControlType() const override final; + }; +} diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp index a132ba67..605e1a24 100644 --- a/src/ui/controls/text_box.cpp +++ b/src/ui/controls/text_box.cpp @@ -1,10 +1,10 @@ -#include "text_box.h" +#include "text_box.hpp" #include #include -#include "graph/graph.h" -#include "exception.h" +#include "graph/graph.hpp" +#include "exception.hpp" namespace cru::ui::controls { diff --git a/src/ui/controls/text_box.h b/src/ui/controls/text_box.h deleted file mode 100644 index 85a5942d..00000000 --- a/src/ui/controls/text_box.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "text_control.h" -#include "timer.h" - -namespace cru::ui::controls -{ - class TextBox : public TextControl - { - public: - static constexpr auto control_type = L"TextBox"; - - static TextBox* Create( - const Microsoft::WRL::ComPtr& init_text_format = nullptr, - const Microsoft::WRL::ComPtr& init_brush = nullptr) - { - return new TextBox(init_text_format, init_brush); - } - - protected: - explicit TextBox( - const Microsoft::WRL::ComPtr& init_text_format, - const Microsoft::WRL::ComPtr& init_brush - ); - public: - TextBox(const TextBox& other) = delete; - TextBox(TextBox&& other) = delete; - TextBox& operator=(const TextBox& other) = delete; - TextBox& operator=(TextBox&& other) = delete; - ~TextBox() override; - - StringView GetControlType() const override final; - - protected: - void OnDrawContent(ID2D1DeviceContext* device_context) override; - - void OnGetFocusCore(events::FocusChangeEventArgs& args) override final; - void OnLoseFocusCore(events::FocusChangeEventArgs& args) override final; - - void OnKeyDownCore(events::KeyEventArgs& args) override final; - void OnCharCore(events::CharEventArgs& args) override final; - - void RequestChangeCaretPosition(unsigned position) override final; - - private: - // return true if left - bool GetCaretSelectionSide() const; - void ShiftLeftSelectionRange(int count); - void ShiftRightSelectionRange(int count); - - private: - unsigned caret_position_ = 0; - std::optional caret_timer_{}; - Microsoft::WRL::ComPtr caret_brush_; - bool is_caret_show_ = false; - }; -} diff --git a/src/ui/controls/text_box.hpp b/src/ui/controls/text_box.hpp new file mode 100644 index 00000000..434aa232 --- /dev/null +++ b/src/ui/controls/text_box.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "text_control.hpp" +#include "timer.hpp" + +namespace cru::ui::controls +{ + class TextBox : public TextControl + { + public: + static constexpr auto control_type = L"TextBox"; + + static TextBox* Create( + const Microsoft::WRL::ComPtr& init_text_format = nullptr, + const Microsoft::WRL::ComPtr& init_brush = nullptr) + { + return new TextBox(init_text_format, init_brush); + } + + protected: + explicit TextBox( + const Microsoft::WRL::ComPtr& init_text_format, + const Microsoft::WRL::ComPtr& init_brush + ); + public: + TextBox(const TextBox& other) = delete; + TextBox(TextBox&& other) = delete; + TextBox& operator=(const TextBox& other) = delete; + TextBox& operator=(TextBox&& other) = delete; + ~TextBox() override; + + StringView GetControlType() const override final; + + protected: + void OnDrawContent(ID2D1DeviceContext* device_context) override; + + void OnGetFocusCore(events::FocusChangeEventArgs& args) override final; + void OnLoseFocusCore(events::FocusChangeEventArgs& args) override final; + + void OnKeyDownCore(events::KeyEventArgs& args) override final; + void OnCharCore(events::CharEventArgs& args) override final; + + void RequestChangeCaretPosition(unsigned position) override final; + + private: + // return true if left + bool GetCaretSelectionSide() const; + void ShiftLeftSelectionRange(int count); + void ShiftRightSelectionRange(int count); + + private: + unsigned caret_position_ = 0; + std::optional caret_timer_{}; + Microsoft::WRL::ComPtr caret_brush_; + bool is_caret_show_ = false; + }; +} diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp index 6ccb8a02..5d2c840e 100644 --- a/src/ui/controls/text_control.cpp +++ b/src/ui/controls/text_control.cpp @@ -1,8 +1,8 @@ -#include "text_control.h" +#include "text_control.hpp" -#include "ui/window.h" -#include "graph/graph.h" -#include "exception.h" +#include "ui/window.hpp" +#include "graph/graph.hpp" +#include "exception.hpp" #include namespace cru::ui::controls diff --git a/src/ui/controls/text_control.h b/src/ui/controls/text_control.h deleted file mode 100644 index bfdfe20f..00000000 --- a/src/ui/controls/text_control.h +++ /dev/null @@ -1,101 +0,0 @@ -#pragma once - -#include "ui/control.h" - -namespace cru::ui::controls -{ - class TextControl : public Control - { - protected: - TextControl( - const Microsoft::WRL::ComPtr& init_text_format, - const Microsoft::WRL::ComPtr& init_brush - ); - public: - TextControl(const TextControl& other) = delete; - TextControl(TextControl&& other) = delete; - TextControl& operator=(const TextControl& other) = delete; - TextControl& operator=(TextControl&& other) = delete; - ~TextControl() override = default; - - String GetText() const - { - return text_; - } - - void SetText(const String& text); - - Microsoft::WRL::ComPtr GetBrush() const - { - return brush_; - } - - void SetBrush(const Microsoft::WRL::ComPtr& brush); - - Microsoft::WRL::ComPtr GetTextFormat() const - { - return text_format_; - } - - void SetTextFormat(const Microsoft::WRL::ComPtr& text_format); - - bool IsSelectable() const - { - return is_selectable_; - } - - std::optional GetSelectedRange() const - { - return selected_range_; - } - - void SetSelectedRange(std::optional text_range); - - void ClearSelection() - { - SetSelectedRange(std::nullopt); - } - - protected: - void SetSelectable(bool is_selectable); - - protected: - void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final; - void OnDrawContent(ID2D1DeviceContext* device_context) override; - - void OnMouseDownCore(events::MouseButtonEventArgs& args) override final; - void OnMouseMoveCore(events::MouseEventArgs& args) override final; - void OnMouseUpCore(events::MouseButtonEventArgs& args) override final; - - void OnLoseFocusCore(events::FocusChangeEventArgs& args) override; - - Size OnMeasureContent(const Size& available_size) override; - - - virtual void RequestChangeCaretPosition(unsigned position); - - private: - void OnTextChangedCore(const String& old_text, const String& new_text); - - void RecreateTextLayout(); - - // param point is the mouse point relative to this control. - void UpdateCursor(const std::optional& point); - - private: - String text_; - - Microsoft::WRL::ComPtr brush_; - Microsoft::WRL::ComPtr selection_brush_; - Microsoft::WRL::ComPtr text_format_; - protected: - Microsoft::WRL::ComPtr text_layout_; - - private: - bool is_selectable_ = false; - - bool is_selecting_ = false; - unsigned mouse_down_position_ = 0; - std::optional selected_range_ = std::nullopt; - }; -} diff --git a/src/ui/controls/text_control.hpp b/src/ui/controls/text_control.hpp new file mode 100644 index 00000000..93120a44 --- /dev/null +++ b/src/ui/controls/text_control.hpp @@ -0,0 +1,101 @@ +#pragma once + +#include "ui/control.hpp" + +namespace cru::ui::controls +{ + class TextControl : public Control + { + protected: + TextControl( + const Microsoft::WRL::ComPtr& init_text_format, + const Microsoft::WRL::ComPtr& init_brush + ); + public: + TextControl(const TextControl& other) = delete; + TextControl(TextControl&& other) = delete; + TextControl& operator=(const TextControl& other) = delete; + TextControl& operator=(TextControl&& other) = delete; + ~TextControl() override = default; + + String GetText() const + { + return text_; + } + + void SetText(const String& text); + + Microsoft::WRL::ComPtr GetBrush() const + { + return brush_; + } + + void SetBrush(const Microsoft::WRL::ComPtr& brush); + + Microsoft::WRL::ComPtr GetTextFormat() const + { + return text_format_; + } + + void SetTextFormat(const Microsoft::WRL::ComPtr& text_format); + + bool IsSelectable() const + { + return is_selectable_; + } + + std::optional GetSelectedRange() const + { + return selected_range_; + } + + void SetSelectedRange(std::optional text_range); + + void ClearSelection() + { + SetSelectedRange(std::nullopt); + } + + protected: + void SetSelectable(bool is_selectable); + + protected: + void OnSizeChangedCore(events::SizeChangedEventArgs& args) override final; + void OnDrawContent(ID2D1DeviceContext* device_context) override; + + void OnMouseDownCore(events::MouseButtonEventArgs& args) override final; + void OnMouseMoveCore(events::MouseEventArgs& args) override final; + void OnMouseUpCore(events::MouseButtonEventArgs& args) override final; + + void OnLoseFocusCore(events::FocusChangeEventArgs& args) override; + + Size OnMeasureContent(const Size& available_size) override; + + + virtual void RequestChangeCaretPosition(unsigned position); + + private: + void OnTextChangedCore(const String& old_text, const String& new_text); + + void RecreateTextLayout(); + + // param point is the mouse point relative to this control. + void UpdateCursor(const std::optional& point); + + private: + String text_; + + Microsoft::WRL::ComPtr brush_; + Microsoft::WRL::ComPtr selection_brush_; + Microsoft::WRL::ComPtr text_format_; + protected: + Microsoft::WRL::ComPtr text_layout_; + + private: + bool is_selectable_ = false; + + bool is_selecting_ = false; + unsigned mouse_down_position_ = 0; + std::optional selected_range_ = std::nullopt; + }; +} diff --git a/src/ui/controls/toggle_button.cpp b/src/ui/controls/toggle_button.cpp index 9bcd7a26..f35b8bfe 100644 --- a/src/ui/controls/toggle_button.cpp +++ b/src/ui/controls/toggle_button.cpp @@ -1,7 +1,7 @@ -#include "toggle_button.h" +#include "toggle_button.hpp" -#include "graph/graph.h" -#include "ui/animations/animation.h" +#include "graph/graph.hpp" +#include "ui/animations/animation.hpp" namespace cru::ui::controls { diff --git a/src/ui/controls/toggle_button.h b/src/ui/controls/toggle_button.h deleted file mode 100644 index 6f3683de..00000000 --- a/src/ui/controls/toggle_button.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -#include "ui/control.h" - -namespace cru::ui::controls -{ - class ToggleButton : public Control - { - public: - static constexpr auto control_type = L"ToggleButton"; - - static ToggleButton* Create() - { - return new ToggleButton(); - } - - protected: - ToggleButton(); - - public: - ToggleButton(const ToggleButton& other) = delete; - ToggleButton(ToggleButton&& other) = delete; - ToggleButton& operator=(const ToggleButton& other) = delete; - ToggleButton& operator=(ToggleButton&& other) = delete; - ~ToggleButton() override = default; - - StringView GetControlType() const override final; - - bool IsPointInside(const Point& point) override; - - bool GetState() const - { - return state_; - } - - void SetState(bool state); - - void Toggle(); - - public: - events::ToggleEvent toggle_event; - - protected: - virtual void OnToggle(events::ToggleEventArgs& args); - - protected: - void OnDrawContent(ID2D1DeviceContext* device_context) override; - - void OnMouseClickCore(events::MouseButtonEventArgs& args) override; - - Size OnMeasureContent(const Size& available_size) override; - - private: - void RaiseToggleEvent(bool new_state); - - private: - bool state_ = false; - - float current_circle_position_; - - Microsoft::WRL::ComPtr frame_path_; - Microsoft::WRL::ComPtr on_brush_; - Microsoft::WRL::ComPtr off_brush_; - }; -} diff --git a/src/ui/controls/toggle_button.hpp b/src/ui/controls/toggle_button.hpp new file mode 100644 index 00000000..5de40ca5 --- /dev/null +++ b/src/ui/controls/toggle_button.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "ui/control.hpp" + +namespace cru::ui::controls +{ + class ToggleButton : public Control + { + public: + static constexpr auto control_type = L"ToggleButton"; + + static ToggleButton* Create() + { + return new ToggleButton(); + } + + protected: + ToggleButton(); + + public: + ToggleButton(const ToggleButton& other) = delete; + ToggleButton(ToggleButton&& other) = delete; + ToggleButton& operator=(const ToggleButton& other) = delete; + ToggleButton& operator=(ToggleButton&& other) = delete; + ~ToggleButton() override = default; + + StringView GetControlType() const override final; + + bool IsPointInside(const Point& point) override; + + bool GetState() const + { + return state_; + } + + void SetState(bool state); + + void Toggle(); + + public: + events::ToggleEvent toggle_event; + + protected: + virtual void OnToggle(events::ToggleEventArgs& args); + + protected: + void OnDrawContent(ID2D1DeviceContext* device_context) override; + + void OnMouseClickCore(events::MouseButtonEventArgs& args) override; + + Size OnMeasureContent(const Size& available_size) override; + + private: + void RaiseToggleEvent(bool new_state); + + private: + bool state_ = false; + + float current_circle_position_; + + Microsoft::WRL::ComPtr frame_path_; + Microsoft::WRL::ComPtr on_brush_; + Microsoft::WRL::ComPtr off_brush_; + }; +} diff --git a/src/ui/cursor.cpp b/src/ui/cursor.cpp index e1f0e5ef..cf88cd25 100644 --- a/src/ui/cursor.cpp +++ b/src/ui/cursor.cpp @@ -1,6 +1,6 @@ -#include "cursor.h" +#include "cursor.hpp" -#include "exception.h" +#include "exception.hpp" namespace cru::ui { diff --git a/src/ui/cursor.h b/src/ui/cursor.h deleted file mode 100644 index ccb21d32..00000000 --- a/src/ui/cursor.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "system_headers.h" -#include - -#include "base.h" - -namespace cru::ui -{ - class Cursor : public Object - { - public: - using Ptr = std::shared_ptr; - - Cursor(HCURSOR handle, bool auto_release); - Cursor(const Cursor& other) = delete; - Cursor(Cursor&& other) = delete; - Cursor& operator=(const Cursor& other) = delete; - Cursor& operator=(Cursor&& other) = delete; - ~Cursor() override; - - HCURSOR GetHandle() const - { - return handle_; - } - - private: - HCURSOR handle_; - bool auto_release_; - }; - - namespace cursors - { - extern Cursor::Ptr arrow; - extern Cursor::Ptr hand; - extern Cursor::Ptr i_beam; - } -} diff --git a/src/ui/cursor.hpp b/src/ui/cursor.hpp new file mode 100644 index 00000000..e3657171 --- /dev/null +++ b/src/ui/cursor.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "system_headers.hpp" +#include + +#include "base.hpp" + +namespace cru::ui +{ + class Cursor : public Object + { + public: + using Ptr = std::shared_ptr; + + Cursor(HCURSOR handle, bool auto_release); + Cursor(const Cursor& other) = delete; + Cursor(Cursor&& other) = delete; + Cursor& operator=(const Cursor& other) = delete; + Cursor& operator=(Cursor&& other) = delete; + ~Cursor() override; + + HCURSOR GetHandle() const + { + return handle_; + } + + private: + HCURSOR handle_; + bool auto_release_; + }; + + namespace cursors + { + extern Cursor::Ptr arrow; + extern Cursor::Ptr hand; + extern Cursor::Ptr i_beam; + } +} diff --git a/src/ui/events/ui_event.cpp b/src/ui/events/ui_event.cpp index 9f5185ce..a1fc3d82 100644 --- a/src/ui/events/ui_event.cpp +++ b/src/ui/events/ui_event.cpp @@ -1,6 +1,6 @@ -#include "ui_event.h" +#include "ui_event.hpp" -#include "ui/control.h" +#include "ui/control.hpp" namespace cru::ui::events { diff --git a/src/ui/events/ui_event.h b/src/ui/events/ui_event.h deleted file mode 100644 index 24429f04..00000000 --- a/src/ui/events/ui_event.h +++ /dev/null @@ -1,315 +0,0 @@ -#pragma once - -#include "system_headers.h" -#include - -#include "base.h" -#include "cru_event.h" -#include "ui/ui_base.h" -#include "ui/layout_base.h" - -namespace cru::ui -{ - class Control; -} - -namespace cru::ui::events -{ - class UiEventArgs : public BasicEventArgs - { - public: - UiEventArgs(Object* sender, Object* original_sender) - : BasicEventArgs(sender), original_sender_(original_sender) - { - - } - - UiEventArgs(const UiEventArgs& other) = default; - UiEventArgs(UiEventArgs&& other) = default; - UiEventArgs& operator=(const UiEventArgs& other) = default; - UiEventArgs& operator=(UiEventArgs&& other) = default; - ~UiEventArgs() override = default; - - Object* GetOriginalSender() const - { - return original_sender_; - } - - private: - Object* original_sender_; - }; - - - class MouseEventArgs : public UiEventArgs - { - public: - MouseEventArgs(Object* sender, Object* original_sender, const std::optional& point = std::nullopt) - : UiEventArgs(sender, original_sender), point_(point) - { - - } - MouseEventArgs(const MouseEventArgs& other) = default; - MouseEventArgs(MouseEventArgs&& other) = default; - MouseEventArgs& operator=(const MouseEventArgs& other) = default; - MouseEventArgs& operator=(MouseEventArgs&& other) = default; - ~MouseEventArgs() override = default; - - Point GetPoint(Control* control, RectRange range = RectRange::Content) const; - - private: - std::optional point_; - }; - - - class MouseButtonEventArgs : public MouseEventArgs - { - public: - MouseButtonEventArgs(Object* sender, Object* original_sender, const Point& point, const MouseButton button) - : MouseEventArgs(sender, original_sender, point), button_(button) - { - - } - MouseButtonEventArgs(const MouseButtonEventArgs& other) = default; - MouseButtonEventArgs(MouseButtonEventArgs&& other) = default; - MouseButtonEventArgs& operator=(const MouseButtonEventArgs& other) = default; - MouseButtonEventArgs& operator=(MouseButtonEventArgs&& other) = default; - ~MouseButtonEventArgs() override = default; - - MouseButton GetMouseButton() const - { - return button_; - } - - private: - MouseButton button_; - }; - - - class DrawEventArgs : public UiEventArgs - { - public: - DrawEventArgs(Object* sender, Object* original_sender, ID2D1DeviceContext* device_context) - : UiEventArgs(sender, original_sender), device_context_(device_context) - { - - } - DrawEventArgs(const DrawEventArgs& other) = default; - DrawEventArgs(DrawEventArgs&& other) = default; - DrawEventArgs& operator=(const DrawEventArgs& other) = default; - DrawEventArgs& operator=(DrawEventArgs&& other) = default; - ~DrawEventArgs() = default; - - ID2D1DeviceContext* GetDeviceContext() const - { - return device_context_; - } - - private: - ID2D1DeviceContext * device_context_; - }; - - - class PositionChangedEventArgs : public UiEventArgs - { - public: - PositionChangedEventArgs(Object* sender, Object* original_sender, const Point& old_position, const Point& new_position) - : UiEventArgs(sender, original_sender), old_position_(old_position), new_position_(new_position) - { - - } - PositionChangedEventArgs(const PositionChangedEventArgs& other) = default; - PositionChangedEventArgs(PositionChangedEventArgs&& other) = default; - PositionChangedEventArgs& operator=(const PositionChangedEventArgs& other) = default; - PositionChangedEventArgs& operator=(PositionChangedEventArgs&& other) = default; - ~PositionChangedEventArgs() override = default; - - Point GetOldPosition() const - { - return old_position_; - } - - Point GetNewPosition() const - { - return new_position_; - } - - private: - Point old_position_; - Point new_position_; - }; - - - class SizeChangedEventArgs : public UiEventArgs - { - public: - SizeChangedEventArgs(Object* sender, Object* original_sender, const Size& old_size, const Size& new_size) - : UiEventArgs(sender, original_sender), old_size_(old_size), new_size_(new_size) - { - - } - SizeChangedEventArgs(const SizeChangedEventArgs& other) = default; - SizeChangedEventArgs(SizeChangedEventArgs&& other) = default; - SizeChangedEventArgs& operator=(const SizeChangedEventArgs& other) = default; - SizeChangedEventArgs& operator=(SizeChangedEventArgs&& other) = default; - ~SizeChangedEventArgs() override = default; - - Size GetOldSize() const - { - return old_size_; - } - - Size GetNewSize() const - { - return new_size_; - } - - private: - Size old_size_; - Size new_size_; - }; - - class FocusChangeEventArgs : public UiEventArgs - { - public: - FocusChangeEventArgs(Object* sender, Object* original_sender, const bool is_window = false) - : UiEventArgs(sender, original_sender), is_window_(is_window) - { - - } - FocusChangeEventArgs(const FocusChangeEventArgs& other) = default; - FocusChangeEventArgs(FocusChangeEventArgs&& other) = default; - FocusChangeEventArgs& operator=(const FocusChangeEventArgs& other) = default; - FocusChangeEventArgs& operator=(FocusChangeEventArgs&& other) = default; - ~FocusChangeEventArgs() override = default; - - // Return whether the focus change is caused by the window-wide focus change. - bool IsWindow() const - { - return is_window_; - } - - private: - bool is_window_; - }; - - class ToggleEventArgs : public UiEventArgs - { - public: - ToggleEventArgs(Object* sender, Object* original_sender, bool new_state) - : UiEventArgs(sender, original_sender), new_state_(new_state) - { - - } - ToggleEventArgs(const ToggleEventArgs& other) = default; - ToggleEventArgs(ToggleEventArgs&& other) = default; - ToggleEventArgs& operator=(const ToggleEventArgs& other) = default; - ToggleEventArgs& operator=(ToggleEventArgs&& other) = default; - ~ToggleEventArgs() override = default; - - bool GetNewState() const - { - return new_state_; - } - - private: - bool new_state_; - }; - - struct WindowNativeMessage - { - HWND hwnd; - int msg; - WPARAM w_param; - LPARAM l_param; - }; - - class WindowNativeMessageEventArgs : public UiEventArgs - { - public: - WindowNativeMessageEventArgs(Object* sender, Object* original_sender, const WindowNativeMessage& message) - : UiEventArgs(sender, original_sender), message_(message), result_(std::nullopt) - { - - } - WindowNativeMessageEventArgs(const WindowNativeMessageEventArgs& other) = default; - WindowNativeMessageEventArgs(WindowNativeMessageEventArgs&& other) = default; - WindowNativeMessageEventArgs& operator=(const WindowNativeMessageEventArgs& other) = default; - WindowNativeMessageEventArgs& operator=(WindowNativeMessageEventArgs&& other) = default; - ~WindowNativeMessageEventArgs() override = default; - - WindowNativeMessage GetWindowMessage() const - { - return message_; - } - - std::optional GetResult() const - { - return result_; - } - - void SetResult(const std::optional result) - { - result_ = result; - } - - private: - WindowNativeMessage message_; - std::optional result_; - }; - - class KeyEventArgs : public UiEventArgs - { - public: - KeyEventArgs(Object* sender, Object* original_sender, int virtual_code) - : UiEventArgs(sender, original_sender), virtual_code_(virtual_code) - { - } - KeyEventArgs(const KeyEventArgs& other) = default; - KeyEventArgs(KeyEventArgs&& other) = default; - KeyEventArgs& operator=(const KeyEventArgs& other) = default; - KeyEventArgs& operator=(KeyEventArgs&& other) = default; - ~KeyEventArgs() override = default; - - int GetVirtualCode() const - { - return virtual_code_; - } - - private: - int virtual_code_; - }; - - class CharEventArgs : public UiEventArgs - { - public: - CharEventArgs(Object* sender, Object* original_sender, wchar_t c) - : UiEventArgs(sender, original_sender), c_(c) - { - } - CharEventArgs(const CharEventArgs& other) = default; - CharEventArgs(CharEventArgs&& other) = default; - CharEventArgs& operator=(const CharEventArgs& other) = default; - CharEventArgs& operator=(CharEventArgs&& other) = default; - ~CharEventArgs() override = default; - - wchar_t GetChar() const - { - return c_; - } - - private: - wchar_t c_; - }; - - using UiEvent = Event; - using MouseEvent = Event; - using MouseButtonEvent = Event; - using DrawEvent = Event; - using PositionChangedEvent = Event; - using SizeChangedEvent = Event; - using FocusChangeEvent = Event; - using ToggleEvent = Event; - using WindowNativeMessageEvent = Event; - using KeyEvent = Event; - using CharEvent = Event; -} diff --git a/src/ui/events/ui_event.hpp b/src/ui/events/ui_event.hpp new file mode 100644 index 00000000..c0585506 --- /dev/null +++ b/src/ui/events/ui_event.hpp @@ -0,0 +1,315 @@ +#pragma once + +#include "system_headers.hpp" +#include + +#include "base.hpp" +#include "cru_event.hpp" +#include "ui/ui_base.hpp" +#include "ui/layout_base.hpp" + +namespace cru::ui +{ + class Control; +} + +namespace cru::ui::events +{ + class UiEventArgs : public BasicEventArgs + { + public: + UiEventArgs(Object* sender, Object* original_sender) + : BasicEventArgs(sender), original_sender_(original_sender) + { + + } + + UiEventArgs(const UiEventArgs& other) = default; + UiEventArgs(UiEventArgs&& other) = default; + UiEventArgs& operator=(const UiEventArgs& other) = default; + UiEventArgs& operator=(UiEventArgs&& other) = default; + ~UiEventArgs() override = default; + + Object* GetOriginalSender() const + { + return original_sender_; + } + + private: + Object* original_sender_; + }; + + + class MouseEventArgs : public UiEventArgs + { + public: + MouseEventArgs(Object* sender, Object* original_sender, const std::optional& point = std::nullopt) + : UiEventArgs(sender, original_sender), point_(point) + { + + } + MouseEventArgs(const MouseEventArgs& other) = default; + MouseEventArgs(MouseEventArgs&& other) = default; + MouseEventArgs& operator=(const MouseEventArgs& other) = default; + MouseEventArgs& operator=(MouseEventArgs&& other) = default; + ~MouseEventArgs() override = default; + + Point GetPoint(Control* control, RectRange range = RectRange::Content) const; + + private: + std::optional point_; + }; + + + class MouseButtonEventArgs : public MouseEventArgs + { + public: + MouseButtonEventArgs(Object* sender, Object* original_sender, const Point& point, const MouseButton button) + : MouseEventArgs(sender, original_sender, point), button_(button) + { + + } + MouseButtonEventArgs(const MouseButtonEventArgs& other) = default; + MouseButtonEventArgs(MouseButtonEventArgs&& other) = default; + MouseButtonEventArgs& operator=(const MouseButtonEventArgs& other) = default; + MouseButtonEventArgs& operator=(MouseButtonEventArgs&& other) = default; + ~MouseButtonEventArgs() override = default; + + MouseButton GetMouseButton() const + { + return button_; + } + + private: + MouseButton button_; + }; + + + class DrawEventArgs : public UiEventArgs + { + public: + DrawEventArgs(Object* sender, Object* original_sender, ID2D1DeviceContext* device_context) + : UiEventArgs(sender, original_sender), device_context_(device_context) + { + + } + DrawEventArgs(const DrawEventArgs& other) = default; + DrawEventArgs(DrawEventArgs&& other) = default; + DrawEventArgs& operator=(const DrawEventArgs& other) = default; + DrawEventArgs& operator=(DrawEventArgs&& other) = default; + ~DrawEventArgs() = default; + + ID2D1DeviceContext* GetDeviceContext() const + { + return device_context_; + } + + private: + ID2D1DeviceContext * device_context_; + }; + + + class PositionChangedEventArgs : public UiEventArgs + { + public: + PositionChangedEventArgs(Object* sender, Object* original_sender, const Point& old_position, const Point& new_position) + : UiEventArgs(sender, original_sender), old_position_(old_position), new_position_(new_position) + { + + } + PositionChangedEventArgs(const PositionChangedEventArgs& other) = default; + PositionChangedEventArgs(PositionChangedEventArgs&& other) = default; + PositionChangedEventArgs& operator=(const PositionChangedEventArgs& other) = default; + PositionChangedEventArgs& operator=(PositionChangedEventArgs&& other) = default; + ~PositionChangedEventArgs() override = default; + + Point GetOldPosition() const + { + return old_position_; + } + + Point GetNewPosition() const + { + return new_position_; + } + + private: + Point old_position_; + Point new_position_; + }; + + + class SizeChangedEventArgs : public UiEventArgs + { + public: + SizeChangedEventArgs(Object* sender, Object* original_sender, const Size& old_size, const Size& new_size) + : UiEventArgs(sender, original_sender), old_size_(old_size), new_size_(new_size) + { + + } + SizeChangedEventArgs(const SizeChangedEventArgs& other) = default; + SizeChangedEventArgs(SizeChangedEventArgs&& other) = default; + SizeChangedEventArgs& operator=(const SizeChangedEventArgs& other) = default; + SizeChangedEventArgs& operator=(SizeChangedEventArgs&& other) = default; + ~SizeChangedEventArgs() override = default; + + Size GetOldSize() const + { + return old_size_; + } + + Size GetNewSize() const + { + return new_size_; + } + + private: + Size old_size_; + Size new_size_; + }; + + class FocusChangeEventArgs : public UiEventArgs + { + public: + FocusChangeEventArgs(Object* sender, Object* original_sender, const bool is_window = false) + : UiEventArgs(sender, original_sender), is_window_(is_window) + { + + } + FocusChangeEventArgs(const FocusChangeEventArgs& other) = default; + FocusChangeEventArgs(FocusChangeEventArgs&& other) = default; + FocusChangeEventArgs& operator=(const FocusChangeEventArgs& other) = default; + FocusChangeEventArgs& operator=(FocusChangeEventArgs&& other) = default; + ~FocusChangeEventArgs() override = default; + + // Return whether the focus change is caused by the window-wide focus change. + bool IsWindow() const + { + return is_window_; + } + + private: + bool is_window_; + }; + + class ToggleEventArgs : public UiEventArgs + { + public: + ToggleEventArgs(Object* sender, Object* original_sender, bool new_state) + : UiEventArgs(sender, original_sender), new_state_(new_state) + { + + } + ToggleEventArgs(const ToggleEventArgs& other) = default; + ToggleEventArgs(ToggleEventArgs&& other) = default; + ToggleEventArgs& operator=(const ToggleEventArgs& other) = default; + ToggleEventArgs& operator=(ToggleEventArgs&& other) = default; + ~ToggleEventArgs() override = default; + + bool GetNewState() const + { + return new_state_; + } + + private: + bool new_state_; + }; + + struct WindowNativeMessage + { + HWND hwnd; + int msg; + WPARAM w_param; + LPARAM l_param; + }; + + class WindowNativeMessageEventArgs : public UiEventArgs + { + public: + WindowNativeMessageEventArgs(Object* sender, Object* original_sender, const WindowNativeMessage& message) + : UiEventArgs(sender, original_sender), message_(message), result_(std::nullopt) + { + + } + WindowNativeMessageEventArgs(const WindowNativeMessageEventArgs& other) = default; + WindowNativeMessageEventArgs(WindowNativeMessageEventArgs&& other) = default; + WindowNativeMessageEventArgs& operator=(const WindowNativeMessageEventArgs& other) = default; + WindowNativeMessageEventArgs& operator=(WindowNativeMessageEventArgs&& other) = default; + ~WindowNativeMessageEventArgs() override = default; + + WindowNativeMessage GetWindowMessage() const + { + return message_; + } + + std::optional GetResult() const + { + return result_; + } + + void SetResult(const std::optional result) + { + result_ = result; + } + + private: + WindowNativeMessage message_; + std::optional result_; + }; + + class KeyEventArgs : public UiEventArgs + { + public: + KeyEventArgs(Object* sender, Object* original_sender, int virtual_code) + : UiEventArgs(sender, original_sender), virtual_code_(virtual_code) + { + } + KeyEventArgs(const KeyEventArgs& other) = default; + KeyEventArgs(KeyEventArgs&& other) = default; + KeyEventArgs& operator=(const KeyEventArgs& other) = default; + KeyEventArgs& operator=(KeyEventArgs&& other) = default; + ~KeyEventArgs() override = default; + + int GetVirtualCode() const + { + return virtual_code_; + } + + private: + int virtual_code_; + }; + + class CharEventArgs : public UiEventArgs + { + public: + CharEventArgs(Object* sender, Object* original_sender, wchar_t c) + : UiEventArgs(sender, original_sender), c_(c) + { + } + CharEventArgs(const CharEventArgs& other) = default; + CharEventArgs(CharEventArgs&& other) = default; + CharEventArgs& operator=(const CharEventArgs& other) = default; + CharEventArgs& operator=(CharEventArgs&& other) = default; + ~CharEventArgs() override = default; + + wchar_t GetChar() const + { + return c_; + } + + private: + wchar_t c_; + }; + + using UiEvent = Event; + using MouseEvent = Event; + using MouseButtonEvent = Event; + using DrawEvent = Event; + using PositionChangedEvent = Event; + using SizeChangedEvent = Event; + using FocusChangeEvent = Event; + using ToggleEvent = Event; + using WindowNativeMessageEvent = Event; + using KeyEvent = Event; + using CharEvent = Event; +} diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp index 0ffe3870..a384500a 100644 --- a/src/ui/layout_base.cpp +++ b/src/ui/layout_base.cpp @@ -1,8 +1,8 @@ -#include "layout_base.h" +#include "layout_base.hpp" -#include "application.h" -#include "control.h" -#include "window.h" +#include "application.hpp" +#include "control.hpp" +#include "window.hpp" namespace cru::ui { diff --git a/src/ui/layout_base.h b/src/ui/layout_base.h deleted file mode 100644 index b3001268..00000000 --- a/src/ui/layout_base.h +++ /dev/null @@ -1,188 +0,0 @@ -#pragma once - -#include - -#include "base.h" -#include "ui_base.h" - -namespace cru::ui -{ - class Control; - class Window; - - 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 Thickness - { - constexpr static Thickness Zero() - { - return Thickness(0); - } - - constexpr Thickness() : Thickness(0) { } - - constexpr explicit Thickness(const float width) - : left(width), top(width), right(width), bottom(width) { } - - constexpr explicit Thickness(const float horizontal, const float vertical) - : left(horizontal), top(vertical), right(horizontal), bottom(vertical) { } - - constexpr Thickness(const float left, const float top, const float right, const float bottom) - : left(left), top(top), right(right), bottom(bottom) { } - - float GetHorizontalTotal() const - { - return left + right; - } - - float GetVerticalTotal() const - { - return top + bottom; - } - - float Validate() const - { - return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0; - } - - float left; - float top; - float right; - float bottom; - }; - - 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 min = std::nullopt; - std::optional 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; - }; - - - class LayoutManager : public Object - { - public: - static LayoutManager* GetInstance(); - - public: - LayoutManager() = default; - LayoutManager(const LayoutManager& other) = delete; - LayoutManager(LayoutManager&& other) = delete; - LayoutManager& operator=(const LayoutManager& other) = delete; - LayoutManager& operator=(LayoutManager&& other) = delete; - ~LayoutManager() override = default; - - - //*************** region: position cache *************** - - //Mark position cache of the control and its descendants invalid, - //(which is saved as an auto-managed list internal) - //and send a message to refresh them. - void InvalidateControlPositionCache(Control* control); - - //Refresh position cache of the control and its descendants whose cache - //has been marked as invalid. - void RefreshInvalidControlPositionCache(); - - //Refresh position cache of the control and its descendants immediately. - static void RefreshControlPositionCache(Control* control); - - - //*************** region: layout *************** - - void InvalidateWindowLayout(Window* window); - - void RefreshInvalidWindowLayout(); - - private: - static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); - - private: - std::unordered_set cache_invalid_controls_; - std::unordered_set layout_invalid_windows_; - }; -} diff --git a/src/ui/layout_base.hpp b/src/ui/layout_base.hpp new file mode 100644 index 00000000..1c35f0b7 --- /dev/null +++ b/src/ui/layout_base.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include + +#include "base.hpp" +#include "ui_base.hpp" + +namespace cru::ui +{ + class Control; + class Window; + + 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 Thickness + { + constexpr static Thickness Zero() + { + return Thickness(0); + } + + constexpr Thickness() : Thickness(0) { } + + constexpr explicit Thickness(const float width) + : left(width), top(width), right(width), bottom(width) { } + + constexpr explicit Thickness(const float horizontal, const float vertical) + : left(horizontal), top(vertical), right(horizontal), bottom(vertical) { } + + constexpr Thickness(const float left, const float top, const float right, const float bottom) + : left(left), top(top), right(right), bottom(bottom) { } + + float GetHorizontalTotal() const + { + return left + right; + } + + float GetVerticalTotal() const + { + return top + bottom; + } + + float Validate() const + { + return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0; + } + + float left; + float top; + float right; + float bottom; + }; + + 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 min = std::nullopt; + std::optional 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; + }; + + + class LayoutManager : public Object + { + public: + static LayoutManager* GetInstance(); + + public: + LayoutManager() = default; + LayoutManager(const LayoutManager& other) = delete; + LayoutManager(LayoutManager&& other) = delete; + LayoutManager& operator=(const LayoutManager& other) = delete; + LayoutManager& operator=(LayoutManager&& other) = delete; + ~LayoutManager() override = default; + + + //*************** region: position cache *************** + + //Mark position cache of the control and its descendants invalid, + //(which is saved as an auto-managed list internal) + //and send a message to refresh them. + void InvalidateControlPositionCache(Control* control); + + //Refresh position cache of the control and its descendants whose cache + //has been marked as invalid. + void RefreshInvalidControlPositionCache(); + + //Refresh position cache of the control and its descendants immediately. + static void RefreshControlPositionCache(Control* control); + + + //*************** region: layout *************** + + void InvalidateWindowLayout(Window* window); + + void RefreshInvalidWindowLayout(); + + private: + static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); + + private: + std::unordered_set cache_invalid_controls_; + std::unordered_set layout_invalid_windows_; + }; +} diff --git a/src/ui/ui_base.cpp b/src/ui/ui_base.cpp index 0195c588..b52694e7 100644 --- a/src/ui/ui_base.cpp +++ b/src/ui/ui_base.cpp @@ -1,6 +1,6 @@ -#include "ui_base.h" +#include "ui_base.hpp" -#include "system_headers.h" +#include "system_headers.hpp" namespace cru::ui { diff --git a/src/ui/ui_base.h b/src/ui/ui_base.h deleted file mode 100644 index 8daa43d7..00000000 --- a/src/ui/ui_base.h +++ /dev/null @@ -1,157 +0,0 @@ -#pragma once - -#include - - -namespace cru::ui -{ - struct Point - { - constexpr static Point Zero() - { - return Point(0, 0); - } - - constexpr Point() = default; - constexpr Point(const float x, const float y) : x(x), y(y) { } - - float x = 0; - float y = 0; - }; - - constexpr bool operator==(const Point& left, const Point& right) - { - return left.x == right.x && left.y == right.y; - } - - constexpr bool operator!=(const Point& left, const Point& right) - { - return !(left == right); - } - - struct Size - { - constexpr static Size Zero() - { - return Size(0, 0); - } - - constexpr Size() = default; - constexpr Size(const float width, const float height) : width(width), height(height) { } - - float width = 0; - float height = 0; - }; - - constexpr Size operator + (const Size& left, const Size& right) - { - return Size(left.width + right.width, left.height + right.height); - } - - constexpr Size operator - (const Size& left, const Size& right) - { - return Size(left.width - right.width, left.height - right.height); - } - - constexpr bool operator==(const Size& left, const Size& right) - { - return left.width == right.width && left.height == right.height; - } - - constexpr bool operator!=(const Size& left, const Size& right) - { - return !(left == right); - } - - struct Rect - { - constexpr Rect() = default; - constexpr Rect(const float left, const float top, const float width, const float height) - : left(left), top(top), width(width), height(height) { } - constexpr Rect(const Point& lefttop, const Size& size) - : left(lefttop.x), top(lefttop.y), width(size.width), height(size.height) { } - - constexpr static Rect FromVertices(const float left, const float top, const float right, const float bottom) - { - return Rect(left, top, right - left, bottom - top); - } - - constexpr float GetRight() const - { - return left + width; - } - - constexpr float GetBottom() const - { - return top + height; - } - - constexpr Point GetLeftTop() const - { - return Point(left, top); - } - - constexpr Point GetRightBottom() const - { - return Point(left + width, top + height); - } - - constexpr Size GetSize() const - { - return Size(width, height); - } - - constexpr bool IsPointInside(const Point& point) const - { - return - point.x >= left && - point.x < GetRight() && - point.y >= top && - point.y < GetBottom(); - } - - float left = 0.0f; - float top = 0.0f; - float width = 0.0f; - float height = 0.0f; - }; - - enum class MouseButton - { - Left, - Right, - Middle - }; - - struct TextRange - { - constexpr static std::optional FromTwoSides(unsigned first, unsigned second) - { - if (first > second) - return std::make_optional(second, first - second); - if (first < second) - return std::make_optional(first, second - first); - return std::nullopt; - } - - constexpr static std::pair ToTwoSides(std::optional text_range, unsigned default_position = 0) - { - if (text_range.has_value()) - return std::make_pair(text_range.value().position, text_range.value().position + text_range.value().count); - return std::make_pair(default_position, default_position); - } - - constexpr TextRange() = default; - constexpr TextRange(const unsigned position, const unsigned count) - : position(position), count(count) - { - - } - - unsigned position = 0; - unsigned count = 0; - }; - - bool IsKeyDown(int virtual_code); - bool IsKeyToggled(int virtual_code); -} diff --git a/src/ui/ui_base.hpp b/src/ui/ui_base.hpp new file mode 100644 index 00000000..8daa43d7 --- /dev/null +++ b/src/ui/ui_base.hpp @@ -0,0 +1,157 @@ +#pragma once + +#include + + +namespace cru::ui +{ + struct Point + { + constexpr static Point Zero() + { + return Point(0, 0); + } + + constexpr Point() = default; + constexpr Point(const float x, const float y) : x(x), y(y) { } + + float x = 0; + float y = 0; + }; + + constexpr bool operator==(const Point& left, const Point& right) + { + return left.x == right.x && left.y == right.y; + } + + constexpr bool operator!=(const Point& left, const Point& right) + { + return !(left == right); + } + + struct Size + { + constexpr static Size Zero() + { + return Size(0, 0); + } + + constexpr Size() = default; + constexpr Size(const float width, const float height) : width(width), height(height) { } + + float width = 0; + float height = 0; + }; + + constexpr Size operator + (const Size& left, const Size& right) + { + return Size(left.width + right.width, left.height + right.height); + } + + constexpr Size operator - (const Size& left, const Size& right) + { + return Size(left.width - right.width, left.height - right.height); + } + + constexpr bool operator==(const Size& left, const Size& right) + { + return left.width == right.width && left.height == right.height; + } + + constexpr bool operator!=(const Size& left, const Size& right) + { + return !(left == right); + } + + struct Rect + { + constexpr Rect() = default; + constexpr Rect(const float left, const float top, const float width, const float height) + : left(left), top(top), width(width), height(height) { } + constexpr Rect(const Point& lefttop, const Size& size) + : left(lefttop.x), top(lefttop.y), width(size.width), height(size.height) { } + + constexpr static Rect FromVertices(const float left, const float top, const float right, const float bottom) + { + return Rect(left, top, right - left, bottom - top); + } + + constexpr float GetRight() const + { + return left + width; + } + + constexpr float GetBottom() const + { + return top + height; + } + + constexpr Point GetLeftTop() const + { + return Point(left, top); + } + + constexpr Point GetRightBottom() const + { + return Point(left + width, top + height); + } + + constexpr Size GetSize() const + { + return Size(width, height); + } + + constexpr bool IsPointInside(const Point& point) const + { + return + point.x >= left && + point.x < GetRight() && + point.y >= top && + point.y < GetBottom(); + } + + float left = 0.0f; + float top = 0.0f; + float width = 0.0f; + float height = 0.0f; + }; + + enum class MouseButton + { + Left, + Right, + Middle + }; + + struct TextRange + { + constexpr static std::optional FromTwoSides(unsigned first, unsigned second) + { + if (first > second) + return std::make_optional(second, first - second); + if (first < second) + return std::make_optional(first, second - first); + return std::nullopt; + } + + constexpr static std::pair ToTwoSides(std::optional text_range, unsigned default_position = 0) + { + if (text_range.has_value()) + return std::make_pair(text_range.value().position, text_range.value().position + text_range.value().count); + return std::make_pair(default_position, default_position); + } + + constexpr TextRange() = default; + constexpr TextRange(const unsigned position, const unsigned count) + : position(position), count(count) + { + + } + + unsigned position = 0; + unsigned count = 0; + }; + + bool IsKeyDown(int virtual_code); + bool IsKeyToggled(int virtual_code); +} diff --git a/src/ui/window.cpp b/src/ui/window.cpp index cc08810b..e426bc78 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -1,9 +1,9 @@ -#include "window.h" +#include "window.hpp" -#include "application.h" -#include "graph/graph.h" -#include "exception.h" -#include "cursor.h" +#include "application.hpp" +#include "graph/graph.hpp" +#include "exception.hpp" +#include "cursor.hpp" namespace cru::ui { diff --git a/src/ui/window.h b/src/ui/window.h deleted file mode 100644 index 822bf32d..00000000 --- a/src/ui/window.h +++ /dev/null @@ -1,302 +0,0 @@ -#pragma once - -#include "system_headers.h" -#include -#include -#include - -#include "control.h" -#include "events/ui_event.h" - -namespace cru::graph -{ - class WindowRenderTarget; -} - -namespace cru::ui -{ - class WindowClass : public Object - { - public: - WindowClass(const String& name, WNDPROC window_proc, HINSTANCE h_instance); - WindowClass(const WindowClass& other) = delete; - WindowClass(WindowClass&& other) = delete; - WindowClass& operator=(const WindowClass& other) = delete; - WindowClass& operator=(WindowClass&& other) = delete; - ~WindowClass() override = default; - - - const wchar_t* GetName() const - { - return name_.c_str(); - } - - ATOM GetAtom() const - { - return atom_; - } - - private: - String name_; - ATOM atom_; - }; - - class WindowManager : public Object - { - public: - WindowManager(); - WindowManager(const WindowManager& other) = delete; - WindowManager(WindowManager&& other) = delete; - WindowManager& operator=(const WindowManager& other) = delete; - WindowManager& operator=(WindowManager&& other) = delete; - ~WindowManager() override = default; - - - //Get the general window class for creating ordinary window. - WindowClass* GetGeneralWindowClass() const - { - return general_window_class_.get(); - } - - //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); - - //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); - - //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); - - std::vector GetAllWindows() const; - - private: - std::unique_ptr general_window_class_; - std::map window_map_; - }; - - - - class Window : public Control - { - friend class WindowManager; - public: - static constexpr auto control_type = L"Window"; - - Window(); - 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; - - //*************** region: handle *************** - - //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; - } - - - //*************** region: window operations *************** - - //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 Repaint() override; - - //Show the window. - void Show(); - - //Hide thw window. - void Hide(); - - //Get the client size. - Size GetClientSize(); - - //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(); - - //Set the rect of the window containing frame. - //The lefttop of the rect is relative to screen lefttop. - void SetWindowRect(const Rect& rect); - - //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 *************** - - Point GetMousePosition(); - - Control* GetMouseHoverControl() const - { - return mouse_hover_control_; - } - - //*************** region: position and size *************** - - //Always return (0, 0) for a window. - Point GetPositionRelative() override final; - - //This method has no effect for a window. - void SetPositionRelative(const Point& position) override final; - - //Get the size of client area for a window. - Size GetSize() override final; - - //This method has no effect for a window. Use SetClientSize instead. - void SetSize(const Size& size) override final; - - //*************** region: layout *************** - - void Relayout(); - - //*************** 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 *************** - - //Request focus for specified control. - bool RequestFocusFor(Control* control); - - //Get the control that has focus. - Control* GetFocusControl(); - - - //*************** region: mouse capture *************** - - Control* CaptureMouseFor(Control* control); - Control* ReleaseCurrentMouseCapture(); - - - //*************** region: cursor *************** - void UpdateCursor(); - - //*************** region: debug *************** -#ifdef CRU_DEBUG_LAYOUT - bool IsDebugLayout() const - { - return debug_layout_; - } - - void SetDebugLayout(bool value); -#endif - - public: - //*************** region: events *************** - events::UiEvent activated_event; - events::UiEvent deactivated_event; - - events::WindowNativeMessageEvent native_message_event; - - private: - //*************** region: native operations *************** - - //Get the client rect in pixel. - RECT GetClientRectPixel(); - - bool IsMessageInQueue(UINT message); - - void SetCursorInternal(HCURSOR cursor); - - - //*************** region: layout *************** - - Size OnMeasureContent(const Size& available_size) override; - - - //*************** 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 OnKeyDownInternal(int virtual_code); - void OnKeyUpInternal(int virtual_code); - void OnCharInternal(wchar_t c); - - void OnActivatedInternal(); - void OnDeactivatedInternal(); - - //*************** region: event dispatcher helper *************** - - template - using EventMethod = void (Control::*)(EventArgs&); - - // Dispatch the event. - // - // This will invoke the "event_method" of the control and its parent and parent's - // parent ... (until "last_receiver" if it's not nullptr) with appropriate args. - // - // 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 - void DispatchEvent(Control* original_sender, EventMethod event_method, Control* last_receiver, Args&&... args) - { - auto control = original_sender; - while (control != nullptr && control != last_receiver) - { - EventArgs event_args(control, original_sender, std::forward(args)...); - (control->*event_method)(event_args); - control = control->GetParent(); - } - } - - void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point); - - private: - HWND hwnd_ = nullptr; - std::shared_ptr render_target_{}; - - std::list control_list_{}; - - Control* mouse_hover_control_ = nullptr; - - bool window_focus_ = false; - Control* focus_control_ = this; // "focus_control_" can't be nullptr - - Control* mouse_capture_control_ = nullptr; - -#ifdef CRU_DEBUG_LAYOUT - bool debug_layout_ = false; -#endif - }; -} - diff --git a/src/ui/window.hpp b/src/ui/window.hpp new file mode 100644 index 00000000..9f773f55 --- /dev/null +++ b/src/ui/window.hpp @@ -0,0 +1,302 @@ +#pragma once + +#include "system_headers.hpp" +#include +#include +#include + +#include "control.hpp" +#include "events/ui_event.hpp" + +namespace cru::graph +{ + class WindowRenderTarget; +} + +namespace cru::ui +{ + class WindowClass : public Object + { + public: + WindowClass(const String& name, WNDPROC window_proc, HINSTANCE h_instance); + WindowClass(const WindowClass& other) = delete; + WindowClass(WindowClass&& other) = delete; + WindowClass& operator=(const WindowClass& other) = delete; + WindowClass& operator=(WindowClass&& other) = delete; + ~WindowClass() override = default; + + + const wchar_t* GetName() const + { + return name_.c_str(); + } + + ATOM GetAtom() const + { + return atom_; + } + + private: + String name_; + ATOM atom_; + }; + + class WindowManager : public Object + { + public: + WindowManager(); + WindowManager(const WindowManager& other) = delete; + WindowManager(WindowManager&& other) = delete; + WindowManager& operator=(const WindowManager& other) = delete; + WindowManager& operator=(WindowManager&& other) = delete; + ~WindowManager() override = default; + + + //Get the general window class for creating ordinary window. + WindowClass* GetGeneralWindowClass() const + { + return general_window_class_.get(); + } + + //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); + + //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); + + //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); + + std::vector GetAllWindows() const; + + private: + std::unique_ptr general_window_class_; + std::map window_map_; + }; + + + + class Window : public Control + { + friend class WindowManager; + public: + static constexpr auto control_type = L"Window"; + + Window(); + 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; + + //*************** region: handle *************** + + //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; + } + + + //*************** region: window operations *************** + + //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 Repaint() override; + + //Show the window. + void Show(); + + //Hide thw window. + void Hide(); + + //Get the client size. + Size GetClientSize(); + + //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(); + + //Set the rect of the window containing frame. + //The lefttop of the rect is relative to screen lefttop. + void SetWindowRect(const Rect& rect); + + //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 *************** + + Point GetMousePosition(); + + Control* GetMouseHoverControl() const + { + return mouse_hover_control_; + } + + //*************** region: position and size *************** + + //Always return (0, 0) for a window. + Point GetPositionRelative() override final; + + //This method has no effect for a window. + void SetPositionRelative(const Point& position) override final; + + //Get the size of client area for a window. + Size GetSize() override final; + + //This method has no effect for a window. Use SetClientSize instead. + void SetSize(const Size& size) override final; + + //*************** region: layout *************** + + void Relayout(); + + //*************** 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 *************** + + //Request focus for specified control. + bool RequestFocusFor(Control* control); + + //Get the control that has focus. + Control* GetFocusControl(); + + + //*************** region: mouse capture *************** + + Control* CaptureMouseFor(Control* control); + Control* ReleaseCurrentMouseCapture(); + + + //*************** region: cursor *************** + void UpdateCursor(); + + //*************** region: debug *************** +#ifdef CRU_DEBUG_LAYOUT + bool IsDebugLayout() const + { + return debug_layout_; + } + + void SetDebugLayout(bool value); +#endif + + public: + //*************** region: events *************** + events::UiEvent activated_event; + events::UiEvent deactivated_event; + + events::WindowNativeMessageEvent native_message_event; + + private: + //*************** region: native operations *************** + + //Get the client rect in pixel. + RECT GetClientRectPixel(); + + bool IsMessageInQueue(UINT message); + + void SetCursorInternal(HCURSOR cursor); + + + //*************** region: layout *************** + + Size OnMeasureContent(const Size& available_size) override; + + + //*************** 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 OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + void OnCharInternal(wchar_t c); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + //*************** region: event dispatcher helper *************** + + template + using EventMethod = void (Control::*)(EventArgs&); + + // Dispatch the event. + // + // This will invoke the "event_method" of the control and its parent and parent's + // parent ... (until "last_receiver" if it's not nullptr) with appropriate args. + // + // 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 + void DispatchEvent(Control* original_sender, EventMethod event_method, Control* last_receiver, Args&&... args) + { + auto control = original_sender; + while (control != nullptr && control != last_receiver) + { + EventArgs event_args(control, original_sender, std::forward(args)...); + (control->*event_method)(event_args); + control = control->GetParent(); + } + } + + void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point); + + private: + HWND hwnd_ = nullptr; + std::shared_ptr render_target_{}; + + std::list control_list_{}; + + Control* mouse_hover_control_ = nullptr; + + bool window_focus_ = false; + Control* focus_control_ = this; // "focus_control_" can't be nullptr + + Control* mouse_capture_control_ = nullptr; + +#ifdef CRU_DEBUG_LAYOUT + bool debug_layout_ = false; +#endif + }; +} + -- cgit v1.2.3