diff options
author | crupest <crupest@outlook.com> | 2019-04-04 17:12:25 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-04-04 17:12:25 +0800 |
commit | a410e2048db6f5ef6fb50e401a59b4b98b979050 (patch) | |
tree | 500680c63b074e8c3eefd756fd6a1d0f41840c1a /include/cru | |
parent | fcaf471275a67d718887430ee63a53890915c4c7 (diff) | |
download | cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.gz cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.bz2 cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.zip |
...
Diffstat (limited to 'include/cru')
-rw-r--r-- | include/cru/common/ui_base.hpp | 16 | ||||
-rw-r--r-- | include/cru/platform/painter.hpp | 5 | ||||
-rw-r--r-- | include/cru/platform/text_layout.hpp | 10 | ||||
-rw-r--r-- | include/cru/platform/win/win_painter.hpp | 5 | ||||
-rw-r--r-- | include/cru/platform/win/win_pre_config.hpp | 1 | ||||
-rw-r--r-- | include/cru/platform/win/win_text_layout.hpp | 2 | ||||
-rw-r--r-- | include/cru/ui/content_control.hpp | 29 | ||||
-rw-r--r-- | include/cru/ui/control.hpp | 137 | ||||
-rw-r--r-- | include/cru/ui/layout_control.hpp | 31 | ||||
-rw-r--r-- | include/cru/ui/no_child_control.hpp | 24 | ||||
-rw-r--r-- | include/cru/ui/render/text_render_object.hpp | 60 | ||||
-rw-r--r-- | include/cru/ui/ui_manager.hpp | 51 | ||||
-rw-r--r-- | include/cru/ui/window.hpp | 97 |
13 files changed, 436 insertions, 32 deletions
diff --git a/include/cru/common/ui_base.hpp b/include/cru/common/ui_base.hpp index 0da18f22..017e3bd1 100644 --- a/include/cru/common/ui_base.hpp +++ b/include/cru/common/ui_base.hpp @@ -233,9 +233,25 @@ struct TextRange final { }; struct Color { + constexpr Color() : Color(0, 0, 0, 255) {} + constexpr Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, + std::uint8_t alpha = 255) + : red(red), green(green), blue(blue), alpha(alpha) {} + + constexpr static Color FromHex(std::uint32_t hex) { + return Color(hex & (0b11111111 << 16), hex & (0b11111111 << 8), + hex & (0b11111111), hex & (0b11111111 << 24)); + } + std::uint8_t red; std::uint8_t green; std::uint8_t blue; std::uint8_t alpha; }; + +namespace colors { +constexpr Color black{0, 0, 0}; +constexpr Color white{255, 255, 255}; +constexpr Color skyblue = Color::FromHex(0x87ceeb); +} // namespace colors } // namespace cru::ui diff --git a/include/cru/platform/painter.hpp b/include/cru/platform/painter.hpp index 2e979184..7310bc5c 100644 --- a/include/cru/platform/painter.hpp +++ b/include/cru/platform/painter.hpp @@ -7,13 +7,18 @@ namespace cru::platform { struct Brush; struct Geometry; +struct TextLayout; struct Painter : virtual Interface { virtual Matrix GetTransform() = 0; virtual void SetTransform(const Matrix& matrix) = 0; + virtual void StrokeRectangle(const ui::Rect& rectangle, Brush* brush, + float width) = 0; + virtual void FillRectangle(const ui::Rect& rectangle, Brush* brush) = 0; virtual void StrokeGeometry(Geometry* geometry, Brush* brush, float width) = 0; virtual void FillGeometry(Geometry* geometry, Brush* brush) = 0; + virtual void DrawText(const ui::Point& offset, TextLayout* text_layout, Brush* brush); virtual void EndDraw() = 0; virtual bool IsDisposed() = 0; }; diff --git a/include/cru/platform/text_layout.hpp b/include/cru/platform/text_layout.hpp index 7bcf01fe..e43adfde 100644 --- a/include/cru/platform/text_layout.hpp +++ b/include/cru/platform/text_layout.hpp @@ -3,16 +3,22 @@ #include "cru/common/ui_base.hpp" -#include <vector> +#include <memory> #include <string> +#include <vector> namespace cru::platform { +struct FontDescriptor; + struct TextLayout : virtual Interface { virtual std::wstring GetText() = 0; virtual void SetText(std::wstring new_text) = 0; + virtual std::shared_ptr<FontDescriptor> GetFont() = 0; + virtual void SetFont(std::shared_ptr<FontDescriptor> font) = 0; virtual void SetMaxWidth(float max_width) = 0; virtual void SetMaxHeight(float max_height) = 0; virtual ui::Rect GetTextBounds() = 0; - virtual std::vector<ui::Rect> TextRangeRect(const ui::TextRange& text_range) = 0; + virtual std::vector<ui::Rect> TextRangeRect( + const ui::TextRange& text_range) = 0; }; } // namespace cru::platform diff --git a/include/cru/platform/win/win_painter.hpp b/include/cru/platform/win/win_painter.hpp index 1e449d85..dfb981d5 100644 --- a/include/cru/platform/win/win_painter.hpp +++ b/include/cru/platform/win/win_painter.hpp @@ -17,8 +17,13 @@ class WinPainter : public Object, public virtual Painter { Matrix GetTransform() override; void SetTransform(const Matrix& matrix) override; + void StrokeRectangle(const ui::Rect& rectangle, Brush* brush, + float width) override; + void FillRectangle(const ui::Rect& rectangle, Brush* brush) override; void StrokeGeometry(Geometry* geometry, Brush* brush, float width) override; void FillGeometry(Geometry* geometry, Brush* brush) override; + void DrawText(const ui::Point& offset, TextLayout* text_layout, + Brush* brush) override; void EndDraw() override; bool IsDisposed() override { return is_disposed; } diff --git a/include/cru/platform/win/win_pre_config.hpp b/include/cru/platform/win/win_pre_config.hpp index d6ba4ec7..6962eb7b 100644 --- a/include/cru/platform/win/win_pre_config.hpp +++ b/include/cru/platform/win/win_pre_config.hpp @@ -4,6 +4,7 @@ #define WIN32_LEAN_AND_MEAN #include <Windows.h> #undef CreateWindow +#undef DrawText #include <d2d1_2.h> #include <d3d11.h> diff --git a/include/cru/platform/win/win_text_layout.hpp b/include/cru/platform/win/win_text_layout.hpp index 277bbcae..9c93aa8c 100644 --- a/include/cru/platform/win/win_text_layout.hpp +++ b/include/cru/platform/win/win_text_layout.hpp @@ -21,6 +21,8 @@ class WinTextLayout : public Object, public virtual TextLayout { std::wstring GetText() override; void SetText(std::wstring new_text) override; + std::shared_ptr<FontDescriptor> GetFont(); + void SetFont(std::shared_ptr<FontDescriptor> font); void SetMaxWidth(float max_width) override; void SetMaxHeight(float max_height) override; ui::Rect GetTextBounds() override; diff --git a/include/cru/ui/content_control.hpp b/include/cru/ui/content_control.hpp new file mode 100644 index 00000000..f88ec157 --- /dev/null +++ b/include/cru/ui/content_control.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "control.hpp" + +namespace cru::ui { +class ContentControl : public Control { + protected: + ContentControl(); + + public: + ContentControl(const ContentControl& other) = delete; + ContentControl(ContentControl&& other) = delete; + ContentControl& operator=(const ContentControl& other) = delete; + ContentControl& operator=(ContentControl&& other) = delete; + ~ContentControl() override; + + const std::vector<Control*>& GetChildren() const override final { + return child_vector_; + } + Control* GetChild() const { return child_; } + void SetChild(Control* child); + + protected: + virtual void OnChildChanged(Control* old_child, Control* new_child); + + private: + std::vector<Control*> child_vector_; + Control*& child_; +}; +} // namespace cru::ui diff --git a/include/cru/ui/control.hpp b/include/cru/ui/control.hpp new file mode 100644 index 00000000..684af2f0 --- /dev/null +++ b/include/cru/ui/control.hpp @@ -0,0 +1,137 @@ +#pragma once +#include "cru/common/base.hpp" + +#include "cru/platform/basic_types.hpp" +#include "event/ui_event.hpp" + +#include <string_view> +#include <vector> + +namespace cru::ui { +class Window; +namespace render { +class RenderObject; +} // namespace render + +class Control : public Object { + friend class Window; + + protected: + Control() = default; + + public: + Control(const Control& other) = delete; + Control(Control&& other) = delete; + Control& operator=(const Control& other) = delete; + Control& operator=(Control&& other) = delete; + ~Control() override = default; + + public: + virtual std::wstring_view GetControlType() const = 0; + + //*************** region: tree *************** + public: + // Get the window if attached, otherwise, return nullptr. + Window* GetWindow() const { return window_; } + + Control* GetParent() const { return parent_; } + + virtual const std::vector<Control*>& GetChildren() const = 0; + + // Traverse the tree rooted the control including itself. + void TraverseDescendants(const std::function<void(Control*)>& predicate); + + void _SetParent(Control* parent); + void _SetDescendantWindow(Window* window); + + private: + static void _TraverseDescendants( + Control* control, const std::function<void(Control*)>& predicate); + + public: + virtual render::RenderObject* GetRenderObject() const = 0; + + //*************** region: focus *************** + public: + bool RequestFocus(); + + bool HasFocus(); + + //*************** region: events *************** + public: + // Raised when mouse enter the control. + event::RoutedEvent<event::MouseEventArgs>* MouseEnterEvent() { + return &mouse_enter_event_; + } + // Raised when mouse is leave the control. + event::RoutedEvent<event::MouseEventArgs>* MouseLeaveEvent() { + return &mouse_leave_event_; + } + // Raised when mouse is move in the control. + event::RoutedEvent<event::MouseEventArgs>* MouseMoveEvent() { + return &mouse_move_event_; + } + // Raised when a mouse button is pressed in the control. + event::RoutedEvent<event::MouseButtonEventArgs>* MouseDownEvent() { + return &mouse_down_event_; + } + // Raised when a mouse button is released in the control. + event::RoutedEvent<event::MouseButtonEventArgs>* MouseUpEvent() { + return &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. + event::RoutedEvent<event::MouseButtonEventArgs>* MouseClickEvent() { + return &mouse_click_event_; + } + event::RoutedEvent<event::MouseWheelEventArgs>* MouseWheelEvent() { + return &mouse_wheel_event_; + } + event::RoutedEvent<event::KeyEventArgs>* KeyDownEvent() { + return &key_down_event_; + } + event::RoutedEvent<event::KeyEventArgs>* KeyUpEvent() { + return &key_up_event_; + } + // event::RoutedEvent<event::CharEventArgs>* CharEvent() { + // return &char_event_; + // } + event::RoutedEvent<event::FocusChangeEventArgs>* GainFocusEvent() { + return &gain_focus_event_; + } + event::RoutedEvent<event::FocusChangeEventArgs>* LoseFocusEvent() { + return &lose_focus_event_; + } + + private: + event::RoutedEvent<event::MouseEventArgs> mouse_enter_event_; + event::RoutedEvent<event::MouseEventArgs> mouse_leave_event_; + event::RoutedEvent<event::MouseEventArgs> mouse_move_event_; + event::RoutedEvent<event::MouseButtonEventArgs> mouse_down_event_; + event::RoutedEvent<event::MouseButtonEventArgs> mouse_up_event_; + event::RoutedEvent<event::MouseButtonEventArgs> mouse_click_event_; + event::RoutedEvent<event::MouseWheelEventArgs> mouse_wheel_event_; + + event::RoutedEvent<event::KeyEventArgs> key_down_event_; + event::RoutedEvent<event::KeyEventArgs> key_up_event_; + // event::RoutedEvent<event::CharEventArgs> char_event_; + + event::RoutedEvent<event::FocusChangeEventArgs> gain_focus_event_; + event::RoutedEvent<event::FocusChangeEventArgs> lose_focus_event_; + + //*************** region: tree *************** + protected: + virtual void OnParentChanged(Control* old_parent, Control* new_parent); + virtual void OnAttachToWindow(Window* window); + virtual void OnDetachToWindow(Window* window); + + //*************** region: additional mouse event *************** + protected: + virtual void OnMouseClickBegin(platform::MouseButton button); + virtual void OnMouseClickEnd(platform::MouseButton button); + + private: + Window* window_ = nullptr; + Control* parent_ = nullptr; +}; +} // namespace cru::ui diff --git a/include/cru/ui/layout_control.hpp b/include/cru/ui/layout_control.hpp new file mode 100644 index 00000000..187f0e0d --- /dev/null +++ b/include/cru/ui/layout_control.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "control.hpp" + +namespace cru::ui { +class LayoutControl : public Control { + protected: + LayoutControl() = default; + + public: + LayoutControl(const LayoutControl& other) = delete; + LayoutControl(LayoutControl&& other) = delete; + LayoutControl& operator=(const LayoutControl& other) = delete; + LayoutControl& operator=(LayoutControl&& other) = delete; + ~LayoutControl() override; + + const std::vector<Control*>& GetChildren() const override final { + return children_; + } + + void AddChild(Control* control, int position); + + void RemoveChild(int position); + + protected: + virtual void OnAddChild(Control* child, int position); + virtual void OnRemoveChild(Control* child, int position); + + private: + std::vector<Control*> children_; +}; +} // namespace cru::ui diff --git a/include/cru/ui/no_child_control.hpp b/include/cru/ui/no_child_control.hpp new file mode 100644 index 00000000..62a9fa8d --- /dev/null +++ b/include/cru/ui/no_child_control.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "control.hpp" + +namespace cru::ui { +class NoChildControl : public Control { + private: + static const std::vector<Control*> empty_control_vector; + + protected: + NoChildControl() = default; + + public: + NoChildControl(const NoChildControl& other) = delete; + NoChildControl(NoChildControl&& other) = delete; + NoChildControl& operator=(const NoChildControl& other) = delete; + NoChildControl& operator=(NoChildControl&& other) = delete; + ~NoChildControl() override = default; + + protected: + const std::vector<Control*>& GetChildren() const override final { + return empty_control_vector; + } +}; +} // namespace cru::ui diff --git a/include/cru/ui/render/text_render_object.hpp b/include/cru/ui/render/text_render_object.hpp index 7827f994..329af18a 100644 --- a/include/cru/ui/render/text_render_object.hpp +++ b/include/cru/ui/render/text_render_object.hpp @@ -1,35 +1,38 @@ #pragma once -#include "pre.hpp" - #include "render_object.hpp" +#include <memory> +#include <string> + // forward declarations -struct ID2D1Brush; -struct IDWriteTextFormat; -struct IDWriteTextLayout; +namespace cru::platform { +struct Brush; +struct FontDescriptor; +struct TextLayout; +} // namespace cru::platform namespace cru::ui::render { class TextRenderObject : public RenderObject { public: - TextRenderObject(ID2D1Brush* brush, IDWriteTextFormat* format, - ID2D1Brush* selection_brush); + TextRenderObject(std::shared_ptr<platform::Brush> brush, + std::shared_ptr<platform::FontDescriptor> font, + std::shared_ptr<platform::Brush> 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(); - } + std::wstring GetText() const; + void SetText(std::wstring new_text); - ID2D1Brush* GetBrush() const { return brush_; } - void SetBrush(ID2D1Brush* new_brush); + std::shared_ptr<platform::Brush> GetBrush() const { return brush_; } + void SetBrush(std::shared_ptr<platform::Brush> new_brush) { + new_brush.swap(brush_); + } - IDWriteTextFormat* GetTextFormat() const { return text_format_; } - void SetTextFormat(IDWriteTextFormat* new_text_format); + std::shared_ptr<platform::FontDescriptor> GetFont() const; + void SetFont(std::shared_ptr<platform::FontDescriptor> font); std::optional<TextRange> GetSelectionRange() const { return selection_range_; @@ -38,12 +41,14 @@ class TextRenderObject : public RenderObject { selection_range_ = std::move(new_range); } - ID2D1Brush* GetSelectionBrush() const { return selection_brush_; } - void SetSelectionBrush(ID2D1Brush* new_brush); - - void Refresh() { RecreateTextLayout(); } + std::shared_ptr<platform::Brush> GetSelectionBrush() const { + return selection_brush_; + } + void SetSelectionBrush(std::shared_ptr<platform::Brush> new_brush) { + new_brush.swap(selection_brush_); + } - void Draw(ID2D1RenderTarget* render_target) override; + void Draw(platform::Painter* painter) override; RenderObject* HitTest(const Point& point) override; @@ -54,16 +59,11 @@ class TextRenderObject : public RenderObject { 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::shared_ptr<platform::Brush> brush_; + std::shared_ptr<platform::FontDescriptor> font_; + std::shared_ptr<platform::TextLayout> text_layout_; std::optional<TextRange> selection_range_ = std::nullopt; - ID2D1Brush* selection_brush_ = nullptr; + std::shared_ptr<platform::Brush> selection_brush_; }; } // namespace cru::ui::render diff --git a/include/cru/ui/ui_manager.hpp b/include/cru/ui/ui_manager.hpp new file mode 100644 index 00000000..6f4a3bc0 --- /dev/null +++ b/include/cru/ui/ui_manager.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "cru/common/base.hpp" + +#include <memory> + +namespace cru::platform { +struct Brush; +struct FontDescriptor; +} // namespace cru::platform + +namespace cru::ui { +class PredefineResources : public Object { + public: + PredefineResources(); + PredefineResources(const PredefineResources& other) = delete; + PredefineResources(PredefineResources&& other) = delete; + PredefineResources& operator=(const PredefineResources& other) = delete; + PredefineResources& operator=(PredefineResources&& other) = delete; + ~PredefineResources() override = default; + + // region Button + std::shared_ptr<platform::Brush> button_normal_border_brush; + + // region TextBlock + std::shared_ptr<platform::Brush> text_block_selection_brush; + std::shared_ptr<platform::Brush> text_block_text_brush; + std::shared_ptr<platform::FontDescriptor> text_block_font; +}; + +class UiManager : public Object { + public: + static UiManager* GetInstance(); + + private: + UiManager(); + + public: + UiManager(const UiManager& other) = delete; + UiManager(UiManager&& other) = delete; + UiManager& operator=(const UiManager& other) = delete; + UiManager& operator=(UiManager&& other) = delete; + ~UiManager() override = default; + + const PredefineResources* GetPredefineResources() const { + return predefine_resources_.get(); + } + + private: + std::unique_ptr<PredefineResources> predefine_resources_; +}; +} // namespace cru::ui diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp new file mode 100644 index 00000000..043aae35 --- /dev/null +++ b/include/cru/ui/window.hpp @@ -0,0 +1,97 @@ +#pragma once +#include "content_control.hpp" + +#include "event/ui_event.hpp" + +#include <memory> + +namespace cru::platform { +struct NativeWindow; +} + +namespace cru::ui { +namespace render { +class WindowRenderObject; +} + +class Window final : public ContentControl { + public: + static constexpr auto control_type = L"Window"; + + public: + static Window* CreateOverlapped(); + + private: + struct tag_overlapped_constructor {}; + + explicit Window(tag_overlapped_constructor); + + public: + Window(const Window& other) = delete; + Window(Window&& other) = delete; + Window& operator=(const Window& other) = delete; + Window& operator=(Window&& other) = delete; + ~Window() override; + + public: + std::wstring_view GetControlType() const override final; + + render::RenderObject* GetRenderObject() const override; + + platform::NativeWindow* GetNativeWindow() const; + + Control* GetMouseHoverControl() const { return mouse_hover_control_; } + + //*************** region: focus *************** + + // Request focus for specified control. + bool RequestFocusFor(Control* control); + + // Get the control that has focus. + Control* GetFocusControl(); + + protected: + void OnChildChanged(Control* old_child, Control* new_child) override; + + private: + Control* HitTest(const Point& point); + + //*************** region: native messages *************** + + void OnNativeDestroy(); + void OnNativePaint(); + void OnNativeResize(float new_width, float new_height); + + void OnSetFocusInternal(); + void OnKillFocusInternal(); + + void OnMouseMoveInternal(POINT point); + void OnMouseLeaveInternal(); + void OnMouseDownInternal(MouseButton button, POINT point); + void OnMouseUpInternal(MouseButton button, POINT point); + + void OnMouseWheelInternal(short delta, POINT point); + void OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + void OnCharInternal(wchar_t c); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + //*************** region: event dispatcher helper *************** + + void DispatchMouseHoverControlChangeEvent(Control* old_control, + Control* new_control, + const Point& point); + + private: + platform::NativeWindow* native_window_; + std::vector<EventHandlerToken> revoke_tokens_; + + std::shared_ptr<render::WindowRenderObject> render_object_; + + Control* mouse_hover_control_ = nullptr; + + Control* focus_control_ = this; // "focus_control_" can't be nullptr +}; +} // namespace cru::ui |