aboutsummaryrefslogtreecommitdiff
path: root/include/cru/ui
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2019-04-04 17:12:25 +0800
committercrupest <crupest@outlook.com>2019-04-04 17:12:25 +0800
commita410e2048db6f5ef6fb50e401a59b4b98b979050 (patch)
tree500680c63b074e8c3eefd756fd6a1d0f41840c1a /include/cru/ui
parentfcaf471275a67d718887430ee63a53890915c4c7 (diff)
downloadcru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.gz
cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.bz2
cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.zip
...
Diffstat (limited to 'include/cru/ui')
-rw-r--r--include/cru/ui/content_control.hpp29
-rw-r--r--include/cru/ui/control.hpp137
-rw-r--r--include/cru/ui/layout_control.hpp31
-rw-r--r--include/cru/ui/no_child_control.hpp24
-rw-r--r--include/cru/ui/render/text_render_object.hpp60
-rw-r--r--include/cru/ui/ui_manager.hpp51
-rw-r--r--include/cru/ui/window.hpp97
7 files changed, 399 insertions, 30 deletions
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