diff options
Diffstat (limited to 'src/ui/control.h')
-rw-r--r-- | src/ui/control.h | 691 |
1 files changed, 344 insertions, 347 deletions
diff --git a/src/ui/control.h b/src/ui/control.h index 9ee657f7..020f959e 100644 --- a/src/ui/control.h +++ b/src/ui/control.h @@ -14,435 +14,432 @@ #include "border_property.h" #include "cursor.h" -namespace cru +namespace cru::ui { - namespace ui - { - class Control; - class Window; + class Control; + class Window; - //the position cache - struct ControlPositionCache - { - //The lefttop relative to the ancestor. - Point lefttop_position_absolute; - }; + //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; + class Control : public Object + { + friend class Window; + friend class LayoutManager; - protected: - struct WindowConstructorTag {}; //Used for constructor for class Window. + protected: + struct WindowConstructorTag {}; //Used for constructor for class Window. - explicit Control(bool container = false); + explicit Control(bool container = false); - // Used only for creating Window. It will set window_ as window. - Control(WindowConstructorTag, Window* window); + // 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: + Control(const Control& other) = delete; + Control(Control&& other) = delete; + Control& operator=(const Control& other) = delete; + Control& operator=(Control&& other) = delete; + ~Control() override; - public: + public: - //*************** region: tree *************** - virtual StringView GetControlType() const = 0; + //*************** region: tree *************** + virtual StringView GetControlType() const = 0; - bool IsContainer() const - { - return is_container_; - } + bool IsContainer() const + { + return is_container_; + } - //Get parent of control, return nullptr if it has no parent. - Control* GetParent() const - { - return parent_; - } + //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<Control*>& GetChildren() const; + //Return a immutable vector of all children. + const std::vector<Control*>& GetChildren() const; - //Add a child at tail. - void AddChild(Control* control); + //Add a child at tail. + void AddChild(Control* control); - //Add a child before the position. - void AddChild(Control* control, int position); + //Add a child before the position. + void AddChild(Control* control, int position); - //Remove a child. - void RemoveChild(Control* child); + //Remove a child. + void RemoveChild(Control* child); - //Remove a child at specified position. - void RemoveChild(int position); + //Remove a child at specified position. + void RemoveChild(int position); - //Get the ancestor of the control. - Control* GetAncestor(); + //Get the ancestor of the control. + Control* GetAncestor(); - //Get the window if attached, otherwise, return nullptr. - Window* GetWindow() const - { - return window_; - } + //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<void(Control*)>& predicate); + //Traverse the tree rooted the control including itself. + void TraverseDescendants(const std::function<void(Control*)>& 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. + //*************** 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(); + //Get the lefttop relative to its parent. + virtual Point GetPositionRelative(); - //Set the lefttop relative to its parent. - virtual void SetPositionRelative(const Point& position); + //Set the lefttop relative to its parent. + virtual void SetPositionRelative(const Point& position); - //Get the actual size. - virtual Size GetSize(); + //Get the actual size. + virtual Size GetSize(); - //Set the actual size directly without re-layout. - virtual void SetSize(const Size& size); + //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; + //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; + //Local point to absolute point. + Point ControlToWindow(const Point& point) const; - //Absolute point to local point. - Point WindowToControl(const Point& point) const; + //Absolute point to local point. + Point WindowToControl(const Point& point) const; - virtual bool IsPointInside(const Point& point); + virtual bool IsPointInside(const Point& point); - //*************** region: graphic *************** + //*************** region: graphic *************** - //Draw this control and its child controls. - void Draw(ID2D1DeviceContext* device_context); + //Draw this control and its child controls. + void Draw(ID2D1DeviceContext* device_context); - virtual void Repaint(); + virtual void Repaint(); - //*************** region: focus *************** + //*************** region: focus *************** - bool RequestFocus(); + bool RequestFocus(); - bool HasFocus(); + bool HasFocus(); - bool IsFocusOnPressed() const - { - return is_focus_on_pressed_; - } + bool IsFocusOnPressed() const + { + return is_focus_on_pressed_; + } - void SetFocusOnPressed(const bool value) - { - is_focus_on_pressed_ = value; - } + void SetFocusOnPressed(const bool value) + { + is_focus_on_pressed_ = value; + } - //*************** region: layout *************** + //*************** region: layout *************** - void InvalidateLayout(); + void InvalidateLayout(); - void Measure(const Size& available_size); + void Measure(const Size& available_size); - void Layout(const Rect& rect); + void Layout(const Rect& rect); - Size GetDesiredSize() const; + Size GetDesiredSize() const; - void SetDesiredSize(const Size& desired_size); + void SetDesiredSize(const Size& desired_size); - BasicLayoutParams* GetLayoutParams() - { - return &layout_params_; - } + BasicLayoutParams* GetLayoutParams() + { + return &layout_params_; + } - Rect GetRect(RectRange range); + Rect GetRect(RectRange range); - Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content); + Point TransformPoint(const Point& point, RectRange from = RectRange::Margin, RectRange to = RectRange::Content); - //*************** region: border *************** + //*************** region: border *************** - BorderProperty& GetBorderProperty() - { - return border_property_; - } + BorderProperty& GetBorderProperty() + { + return border_property_; + } - void InvalidateBorder(); + void InvalidateBorder(); - bool IsBordered() const - { - return is_bordered_; - } + bool IsBordered() const + { + return is_bordered_; + } - void SetBordered(bool bordered); + void SetBordered(bool bordered); - //*************** region: additional properties *************** - template <typename T> - std::optional<T> GetAdditionalProperty(const String& key) + //*************** region: additional properties *************** + template <typename T> + std::optional<T> GetAdditionalProperty(const String& key) + { + try { - try - { - const auto find_result = additional_properties_.find(key); - if (find_result != additional_properties_.cend()) - return std::any_cast<T>(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())); - } + const auto find_result = additional_properties_.find(key); + if (find_result != additional_properties_.cend()) + return std::any_cast<T>(find_result->second); + else + return std::nullopt; } - - template <typename T> - void SetAdditionalProperty(const String& key, const T& value) + catch (const std::bad_any_cast&) { - additional_properties_[key] = std::make_any<T>(value); + throw std::runtime_error(Format("Key \"{}\" is not of the type {}.", ToUtf8String(key), typeid(T).name())); } + } - template <typename T> - void SetAdditionalProperty(const String& key, T&& value) - { - additional_properties_[key] = std::make_any<T>(std::move(value)); - } + template <typename T> + void SetAdditionalProperty(const String& key, const T& value) + { + additional_properties_[key] = std::make_any<T>(value); + } - - //*************** region: cursor *************** - // If cursor is set to null, then it uses parent's cursor. - // Window's cursor can't be null. + template <typename T> + void SetAdditionalProperty(const String& key, T&& value) + { + additional_properties_[key] = std::make_any<T>(std::move(value)); + } - Cursor::Ptr GetCursor() const - { - return cursor_; - } + + //*************** region: cursor *************** + // If cursor is set to null, then it uses parent's cursor. + // Window's cursor can't be null. - 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."); - } + Cursor::Ptr GetCursor() const + { + return cursor_; + } - private: - bool is_container_; + 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."); + } - protected: - Window * window_ = nullptr; // protected for Window class to write it as itself in constructor. + private: + bool is_container_; - private: - Control * parent_ = nullptr; - std::vector<Control*> children_{}; + protected: + Window * window_ = nullptr; // protected for Window class to write it as itself in constructor. - // 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(); + private: + Control * parent_ = nullptr; + std::vector<Control*> children_{}; - ControlPositionCache position_cache_{}; + // 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(); - bool is_mouse_inside_ = false; + ControlPositionCache position_cache_{}; - std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_ - { - { MouseButton::Left, true }, - { MouseButton::Middle, true }, - { MouseButton::Right, true } - }; // used for clicking determination + bool is_mouse_inside_ = false; - BasicLayoutParams layout_params_{}; - Size desired_size_ = Size::Zero(); + std::unordered_map<MouseButton, bool> is_mouse_click_valid_map_ + { + { MouseButton::Left, true }, + { MouseButton::Middle, true }, + { MouseButton::Right, true } + }; // used for clicking determination - bool is_bordered_ = false; - BorderProperty border_property_; + BasicLayoutParams layout_params_{}; + Size desired_size_ = Size::Zero(); - std::unordered_map<String, std::any> additional_properties_{}; + bool is_bordered_ = false; + BorderProperty border_property_; - bool is_focus_on_pressed_ = true; + std::unordered_map<String, std::any> additional_properties_{}; + + bool is_focus_on_pressed_ = true; #ifdef CRU_DEBUG_LAYOUT - Microsoft::WRL::ComPtr<ID2D1Geometry> margin_geometry_; - Microsoft::WRL::ComPtr<ID2D1Geometry> padding_geometry_; + Microsoft::WRL::ComPtr<ID2D1Geometry> margin_geometry_; + Microsoft::WRL::ComPtr<ID2D1Geometry> padding_geometry_; #endif - Cursor::Ptr cursor_{}; - }; + 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); + // 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); + // Return the ancestor if one control is the ancestor of the other one, otherwise nullptr. + Control* IsAncestorOrDescendant(Control* left, Control* right); - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - return control; - } + template <typename TControl, typename... Args> + TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, Args&&... args) + { + static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward<Args>(args)...); + control->GetLayoutParams()->width = width; + control->GetLayoutParams()->height = height; + return control; + } - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } - - template <typename TControl, typename... Args> - TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, Args&&... args) - { - static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); - TControl* control = TControl::Create(std::forward<Args>(args)...); - control->GetLayoutParams()->width = width; - control->GetLayoutParams()->height = height; - control->GetLayoutParams()->padding = padding; - control->GetLayoutParams()->margin = margin; - return control; - } + template <typename TControl, typename... Args> + TControl* CreateWithLayout(const Thickness& padding, const Thickness& margin, Args&&... args) + { + static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward<Args>(args)...); + control->GetLayoutParams()->padding = padding; + control->GetLayoutParams()->margin = margin; + return control; + } - using ControlList = std::initializer_list<Control*>; + template <typename TControl, typename... Args> + TControl* CreateWithLayout(const LayoutSideParams& width, const LayoutSideParams& height, const Thickness& padding, const Thickness& margin, Args&&... args) + { + static_assert(std::is_base_of_v<Control, TControl>, "TControl is not a control class."); + TControl* control = TControl::Create(std::forward<Args>(args)...); + control->GetLayoutParams()->width = width; + control->GetLayoutParams()->height = height; + control->GetLayoutParams()->padding = padding; + control->GetLayoutParams()->margin = margin; + return control; } + + using ControlList = std::initializer_list<Control*>; } |