diff options
author | crupest <crupest@outlook.com> | 2019-04-01 18:08:58 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-04-01 18:08:58 +0800 |
commit | de00126c6aeba189a50296df455dd516e21e4176 (patch) | |
tree | 3d89a8a36a3603096d4371230c2d071f91e9e986 /include/cru/ui | |
parent | 055a3cde0cd19c896f3e498b774078654555c065 (diff) | |
download | cru-de00126c6aeba189a50296df455dd516e21e4176.tar.gz cru-de00126c6aeba189a50296df455dd516e21e4176.tar.bz2 cru-de00126c6aeba189a50296df455dd516e21e4176.zip |
...
Diffstat (limited to 'include/cru/ui')
-rw-r--r-- | include/cru/ui/event/ui_event.hpp | 200 | ||||
-rw-r--r-- | include/cru/ui/render/border_render_object.hpp | 88 | ||||
-rw-r--r-- | include/cru/ui/render/flex_layout_render_object.hpp | 57 | ||||
-rw-r--r-- | include/cru/ui/render/render_object.hpp | 98 | ||||
-rw-r--r-- | include/cru/ui/render/text_render_object.hpp | 69 | ||||
-rw-r--r-- | include/cru/ui/render/window_render_object.hpp | 40 |
6 files changed, 552 insertions, 0 deletions
diff --git a/include/cru/ui/event/ui_event.hpp b/include/cru/ui/event/ui_event.hpp new file mode 100644 index 00000000..ba8940cb --- /dev/null +++ b/include/cru/ui/event/ui_event.hpp @@ -0,0 +1,200 @@ +#pragma once +#include "cru/common/base.hpp" + +#include "cru/common/event.hpp" +#include "cru/common/ui_base.hpp" +#include "cru/platform/basic_types.hpp" + +#include <optional> + +namespace cru::platform { +struct Painter; +} + +namespace cru::ui { +class Control; +} + +namespace cru::ui::event { +class UiEventArgs : public Object { + public: + UiEventArgs(Object* sender, Object* original_sender) + : sender_(sender), + original_sender_(original_sender), + handled_(false) {} + + 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_; } + + bool IsHandled() const { return handled_; } + void SetHandled(const bool handled = true) { handled_ = handled; } + + private: + Object* sender_; + Object* original_sender_; + bool handled_; +}; + +template <typename TEventArgs> +class RoutedEvent { + public: + static_assert(std::is_base_of_v<UiEventArgs, TEventArgs>, + "TEventArgs must be subclass of UiEventArgs."); + + using EventArgs = TEventArgs; + + RoutedEvent() = default; + RoutedEvent(const RoutedEvent& other) = delete; + RoutedEvent(RoutedEvent&& other) = delete; + RoutedEvent& operator=(const RoutedEvent& other) = delete; + RoutedEvent& operator=(RoutedEvent&& other) = delete; + ~RoutedEvent() = default; + + Event<TEventArgs> direct; + Event<TEventArgs> bubble; + Event<TEventArgs> tunnel; +}; + +class MouseEventArgs : public UiEventArgs { + public: + MouseEventArgs(Object* sender, Object* original_sender, + const std::optional<Point>& 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() const { return point_.value_or(Point{}); } + + private: + std::optional<Point> point_; +}; + +class MouseButtonEventArgs : public MouseEventArgs { + public: + MouseButtonEventArgs(Object* sender, Object* original_sender, + const Point& point, const platform::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; + + platform::MouseButton GetMouseButton() const { return button_; } + + private: + platform::MouseButton button_; +}; + +class MouseWheelEventArgs : public MouseEventArgs { + public: + MouseWheelEventArgs(Object* sender, Object* original_sender, + const Point& point, const float delta) + : MouseEventArgs(sender, original_sender, point), delta_(delta) {} + MouseWheelEventArgs(const MouseWheelEventArgs& other) = default; + MouseWheelEventArgs(MouseWheelEventArgs&& other) = default; + MouseWheelEventArgs& operator=(const MouseWheelEventArgs& other) = default; + MouseWheelEventArgs& operator=(MouseWheelEventArgs&& other) = default; + ~MouseWheelEventArgs() override = default; + + float GetDelta() const { return delta_; } + + private: + float delta_; +}; + +class PaintEventArgs : public UiEventArgs { + public: + PaintEventArgs(Object* sender, Object* original_sender, + platform::Painter* painter) + : UiEventArgs(sender, original_sender), painter_(painter) {} + PaintEventArgs(const PaintEventArgs& other) = default; + PaintEventArgs(PaintEventArgs&& other) = default; + PaintEventArgs& operator=(const PaintEventArgs& other) = default; + PaintEventArgs& operator=(PaintEventArgs&& other) = default; + ~PaintEventArgs() = default; + + platform::Painter* GetPainter() const { return painter_; } + + private: + platform::Painter* painter_; +}; + +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_; +}; +*/ + +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_; +}; +*/ +} // namespace cru::ui::events diff --git a/include/cru/ui/render/border_render_object.hpp b/include/cru/ui/render/border_render_object.hpp new file mode 100644 index 00000000..a96ccf99 --- /dev/null +++ b/include/cru/ui/render/border_render_object.hpp @@ -0,0 +1,88 @@ +#pragma once +#include "render_object.hpp" + +namespace cru::platform { +struct Brush; +} + +namespace cru::ui::render { +struct CornerRadius { + constexpr CornerRadius() + : left_top(), right_top(), left_bottom(), right_bottom() {} + constexpr CornerRadius(const Point& value) + : left_top(value), + right_top(value), + left_bottom(value), + right_bottom(value) {} + constexpr CornerRadius(Point left_top, Point right_top, Point left_bottom, + Point right_bottom) + : left_top(left_top), + right_top(right_top), + left_bottom(left_bottom), + right_bottom(right_bottom) {} + + Point left_top; + Point right_top; + Point left_bottom; + Point right_bottom; +}; + +class BorderRenderObject : public RenderObject { + public: + explicit BorderRenderObject(platform::Brush* brush); + BorderRenderObject(const BorderRenderObject& other) = delete; + BorderRenderObject(BorderRenderObject&& other) = delete; + BorderRenderObject& operator=(const BorderRenderObject& other) = delete; + BorderRenderObject& operator=(BorderRenderObject&& other) = delete; + ~BorderRenderObject() override; + + bool IsEnabled() const { return is_enabled_; } + void SetEnabled(bool enabled) { is_enabled_ = enabled; } + + ID2D1Brush* GetBrush() const { return border_brush_; } + void SetBrush(ID2D1Brush* new_brush); + + Thickness GetBorderWidth() const { return border_thickness_; } + void SetBorderWidth(const Thickness& thickness) { + border_thickness_ = thickness; + } + + CornerRadius GetCornerRadius() const { return corner_radius_; } + void SetCornerRadius(const CornerRadius& new_corner_radius) { + corner_radius_ = new_corner_radius; + } + + void Refresh() { RecreateGeometry(); } + + void Draw(ID2D1RenderTarget* render_target) override; + + RenderObject* HitTest(const Point& point) override; + + protected: + void OnAddChild(RenderObject* new_child, int position) override; + + void OnSizeChanged(const Size& old_size, const Size& new_size) override; + + void OnMeasureCore(const Size& available_size) override; + void OnLayoutCore(const Rect& rect) override; + Size OnMeasureContent(const Size& available_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + private: + RenderObject* GetChild() const { + return GetChildren().empty() ? nullptr : GetChildren()[0]; + } + + void RecreateGeometry(); + + private: + bool is_enabled_ = false; + + ID2D1Brush* border_brush_ = nullptr; + Thickness border_thickness_ = Thickness::Zero(); + CornerRadius corner_radius_{}; + + ID2D1Geometry* geometry_ = nullptr; + ID2D1Geometry* border_outer_geometry_ = nullptr; +}; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/flex_layout_render_object.hpp b/include/cru/ui/render/flex_layout_render_object.hpp new file mode 100644 index 00000000..278bf8c2 --- /dev/null +++ b/include/cru/ui/render/flex_layout_render_object.hpp @@ -0,0 +1,57 @@ +#pragma once +#include "render_object.hpp" + +#include <optional> + +namespace cru::ui::render { +enum class FlexDirection { + Horizontal, + HorizontalReverse, + Vertical, + VertivalReverse +}; + +enum class Alignment { Start, End, Center }; + +struct FlexChildLayoutData { + std::optional<float> flex_basis; // nullopt stands for content + float flex_grow = 0; + float flex_shrink = 0; + Alignment alignment = Alignment::Center; +}; + +class FlexLayoutRenderObject : public RenderObject { + public: + FlexLayoutRenderObject() = default; + FlexLayoutRenderObject(const FlexLayoutRenderObject& other) = delete; + FlexLayoutRenderObject& operator=(const FlexLayoutRenderObject& other) = + delete; + FlexLayoutRenderObject(FlexLayoutRenderObject&& other) = delete; + FlexLayoutRenderObject& operator=(FlexLayoutRenderObject&& other) = delete; + ~FlexLayoutRenderObject() override = default; + + FlexDirection GetFlexDirection() const { return direction_; } + void SetFlexDirection(FlexDirection direction) { direction_ = direction; } + + Alignment GetContentMainAlign() const { return content_main_align_; } + void SetContentMainAlign(Alignment align) { content_main_align_ = align; } + + FlexChildLayoutData* GetChildLayoutData(int position); + + void Draw(platform::Painter* painter) override; + + RenderObject* HitTest(const Point& point) override; + + protected: + void OnAddChild(RenderObject* new_child, int position) override; + void OnRemoveChild(RenderObject* removed_child, int position) override; + + Size OnMeasureContent(const Size& available_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + private: + FlexDirection direction_ = FlexDirection::Horizontal; + Alignment content_main_align_ = Alignment::Start; + std::vector<FlexChildLayoutData> child_layout_data_{}; +}; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/render_object.hpp b/include/cru/ui/render/render_object.hpp new file mode 100644 index 00000000..3cd14a6a --- /dev/null +++ b/include/cru/ui/render/render_object.hpp @@ -0,0 +1,98 @@ +#pragma once +#include "cru/common/base.hpp" + +#include "cru/common/ui_base.hpp" + +#include <vector> + +// forward declarations +namespace cru::ui { +class Control; +} + +namespace cru::platform { +struct Painter; +} + +namespace cru::ui::render { +class RenderObject : public Object { + protected: + RenderObject() = default; + + public: + RenderObject(const RenderObject& other) = delete; + RenderObject(RenderObject&& other) = delete; + RenderObject& operator=(const RenderObject& other) = delete; + RenderObject& operator=(RenderObject&& other) = delete; + ~RenderObject() override = default; + + Control* GetAttachedControl() const { return control_; } + void SetAttachedControl(Control* new_control) { control_ = new_control; } + + RenderObject* GetParent() const { return parent_; } + + const std::vector<RenderObject*>& GetChildren() const { return children_; } + void AddChild(RenderObject* render_object, int position); + void RemoveChild(int position); + + Point GetOffset() const { return offset_; } + void SetOffset(const Point& offset) { offset_ = offset; } + Size GetSize() const { return size_; } + void SetSize(const Size& size) { + const auto old_size = size_; + size_ = size; + OnSizeChanged(old_size, size); + } + + Thickness GetMargin() const { return margin_; } + void SetMargin(const Thickness& margin) { margin_ = margin; } + + Thickness GetPadding() const { return padding_; } + void SetPadding(const Thickness& padding) { padding_ = padding; } + + Size GetPreferredSize() const { return preferred_size_; } + void SetPreferredSize(const Size& preferred_size) { + preferred_size_ = preferred_size; + } + + void Measure(const Size& available_size); + void Layout(const Rect& rect); + + virtual void Draw(platform::Painter* render_target) = 0; + + virtual RenderObject* HitTest(const Point& point) = 0; + + protected: + virtual void OnParentChanged(RenderObject* old_parent, + RenderObject* new_parent); + + virtual void OnAddChild(RenderObject* new_child, int position); + virtual void OnRemoveChild(RenderObject* removed_child, int position); + + virtual void OnSizeChanged(const Size& old_size, const Size& new_size); + + virtual void OnMeasureCore(const Size& available_size); + virtual void OnLayoutCore(const Rect& rect); + virtual Size OnMeasureContent(const Size& available_size) = 0; + virtual void OnLayoutContent(const Rect& content_rect) = 0; + + Rect GetContentRect() const; + + private: + void SetParent(RenderObject* new_parent); + + private: + Control* control_ = nullptr; + + RenderObject* parent_ = nullptr; + std::vector<RenderObject*> children_{}; + + Point offset_{}; + Size size_{}; + + Thickness margin_{}; + Thickness padding_{}; + + Size preferred_size_{}; +}; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/text_render_object.hpp b/include/cru/ui/render/text_render_object.hpp new file mode 100644 index 00000000..7827f994 --- /dev/null +++ b/include/cru/ui/render/text_render_object.hpp @@ -0,0 +1,69 @@ +#pragma once +#include "pre.hpp" + +#include "render_object.hpp" + +// forward declarations +struct ID2D1Brush; +struct IDWriteTextFormat; +struct IDWriteTextLayout; + +namespace cru::ui::render { +class TextRenderObject : public RenderObject { + public: + TextRenderObject(ID2D1Brush* brush, IDWriteTextFormat* format, + ID2D1Brush* selection_brush); + TextRenderObject(const TextRenderObject& other) = delete; + TextRenderObject(TextRenderObject&& other) = delete; + TextRenderObject& operator=(const TextRenderObject& other) = delete; + TextRenderObject& operator=(TextRenderObject&& other) = delete; + ~TextRenderObject() override; + + String GetText() const { return text_; } + void SetText(String new_text) { + text_ = std::move(new_text); + RecreateTextLayout(); + } + + ID2D1Brush* GetBrush() const { return brush_; } + void SetBrush(ID2D1Brush* new_brush); + + IDWriteTextFormat* GetTextFormat() const { return text_format_; } + void SetTextFormat(IDWriteTextFormat* new_text_format); + + std::optional<TextRange> GetSelectionRange() const { + return selection_range_; + } + void SetSelectionRange(std::optional<TextRange> new_range) { + selection_range_ = std::move(new_range); + } + + ID2D1Brush* GetSelectionBrush() const { return selection_brush_; } + void SetSelectionBrush(ID2D1Brush* new_brush); + + void Refresh() { RecreateTextLayout(); } + + void Draw(ID2D1RenderTarget* render_target) override; + + RenderObject* HitTest(const Point& point) override; + + protected: + void OnSizeChanged(const Size& old_size, const Size& new_size) override; + + Size OnMeasureContent(const Size& available_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + private: + void RecreateTextLayout(); + + private: + String text_; + + ID2D1Brush* brush_ = nullptr; + IDWriteTextFormat* text_format_ = nullptr; + IDWriteTextLayout* text_layout_ = nullptr; + + std::optional<TextRange> selection_range_ = std::nullopt; + ID2D1Brush* selection_brush_ = nullptr; +}; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/window_render_object.hpp b/include/cru/ui/render/window_render_object.hpp new file mode 100644 index 00000000..63eb8588 --- /dev/null +++ b/include/cru/ui/render/window_render_object.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "pre.hpp" + +#include "render_object.hpp" + +namespace cru::ui { +class Window; +} + +namespace cru::ui::render { +class WindowRenderObject : public RenderObject { + public: + WindowRenderObject(Window* window) : window_(window) {} + WindowRenderObject(const WindowRenderObject& other) = delete; + WindowRenderObject(WindowRenderObject&& other) = delete; + WindowRenderObject& operator=(const WindowRenderObject& other) = delete; + WindowRenderObject& operator=(WindowRenderObject&& other) = delete; + ~WindowRenderObject() override = default; + + void MeasureAndLayout(); + + void Draw(ID2D1RenderTarget* render_target) override; + + RenderObject* HitTest(const Point& point) override; + + protected: + void OnAddChild(RenderObject* new_child, int position) override; + + Size OnMeasureContent(const Size& available_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + private: + RenderObject* GetChild() const { + return GetChildren().empty() ? nullptr : GetChildren()[0]; + } + + private: + Window* window_; +}; +} // namespace cru::ui::render |