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 /src/ui | |
parent | fcaf471275a67d718887430ee63a53890915c4c7 (diff) | |
download | cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.gz cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.tar.bz2 cru-a410e2048db6f5ef6fb50e401a59b4b98b979050.zip |
...
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/content_control.cpp | 4 | ||||
-rw-r--r-- | src/ui/content_control.hpp | 31 | ||||
-rw-r--r-- | src/ui/control.cpp | 8 | ||||
-rw-r--r-- | src/ui/control.hpp | 134 | ||||
-rw-r--r-- | src/ui/input_util.cpp | 20 | ||||
-rw-r--r-- | src/ui/input_util.hpp | 10 | ||||
-rw-r--r-- | src/ui/layout_control.cpp | 7 | ||||
-rw-r--r-- | src/ui/layout_control.hpp | 33 | ||||
-rw-r--r-- | src/ui/no_child_control.cpp | 2 | ||||
-rw-r--r-- | src/ui/no_child_control.hpp | 26 | ||||
-rw-r--r-- | src/ui/render/text_render_object.cpp | 151 | ||||
-rw-r--r-- | src/ui/ui_manager.cpp | 77 | ||||
-rw-r--r-- | src/ui/ui_manager.hpp | 61 | ||||
-rw-r--r-- | src/ui/window.cpp | 283 | ||||
-rw-r--r-- | src/ui/window.hpp | 162 |
15 files changed, 84 insertions, 925 deletions
diff --git a/src/ui/content_control.cpp b/src/ui/content_control.cpp index d5abca1c..3a23164c 100644 --- a/src/ui/content_control.cpp +++ b/src/ui/content_control.cpp @@ -1,7 +1,9 @@ -#include "content_control.hpp" +#include "cru/ui/content_control.hpp" #include "window.hpp" +#include <cassert> + namespace cru::ui { ContentControl::ContentControl() : child_vector_{nullptr}, child_(child_vector_[0]) {} diff --git a/src/ui/content_control.hpp b/src/ui/content_control.hpp deleted file mode 100644 index 88e7f60f..00000000 --- a/src/ui/content_control.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once -#include "pre.hpp" - -#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/src/ui/control.cpp b/src/ui/control.cpp index 318d591a..c5d02d40 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -1,7 +1,9 @@ -#include "control.hpp" +#include "cru/ui/control.hpp" #include "window.hpp" +#include <cassert> + namespace cru::ui { void Control::_SetParent(Control* parent) { const auto old_parent = GetParent(); @@ -61,7 +63,7 @@ void Control::OnAttachToWindow(Window* window) {} void Control::OnDetachToWindow(Window* window) {} -void Control::OnMouseClickBegin(MouseButton button) {} +void Control::OnMouseClickBegin(platform::MouseButton button) {} -void Control::OnMouseClickEnd(MouseButton button) {} +void Control::OnMouseClickEnd(platform::MouseButton button) {} } // namespace cru::ui diff --git a/src/ui/control.hpp b/src/ui/control.hpp deleted file mode 100644 index b69734d6..00000000 --- a/src/ui/control.hpp +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once -#include "cru/common/base.hpp" - -#include "cru/ui/event/ui_event.hpp" - -#include "" - -#include <string_view> - -namespace cru::ui { -class Window; - -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. - events::RoutedEvent<events::MouseEventArgs>* MouseEnterEvent() { - return &mouse_enter_event_; - } - // Raised when mouse is leave the control. - events::RoutedEvent<events::MouseEventArgs>* MouseLeaveEvent() { - return &mouse_leave_event_; - } - // Raised when mouse is move in the control. - events::RoutedEvent<events::MouseEventArgs>* MouseMoveEvent() { - return &mouse_move_event_; - } - // Raised when a mouse button is pressed in the control. - events::RoutedEvent<events::MouseButtonEventArgs>* MouseDownEvent() { - return &mouse_down_event_; - } - // Raised when a mouse button is released in the control. - events::RoutedEvent<events::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. - events::RoutedEvent<events::MouseButtonEventArgs>* MouseClickEvent() { - return &mouse_click_event_; - } - events::RoutedEvent<events::MouseWheelEventArgs>* MouseWheelEvent() { - return &mouse_wheel_event_; - } - events::RoutedEvent<events::KeyEventArgs>* KeyDownEvent() { - return &key_down_event_; - } - events::RoutedEvent<events::KeyEventArgs>* KeyUpEvent() { - return &key_up_event_; - } - events::RoutedEvent<events::CharEventArgs>* CharEvent() { - return &char_event_; - } - events::RoutedEvent<events::FocusChangeEventArgs>* GainFocusEvent() { - return &gain_focus_event_; - } - events::RoutedEvent<events::FocusChangeEventArgs>* LoseFocusEvent() { - return &lose_focus_event_; - } - - private: - events::RoutedEvent<events::MouseEventArgs> mouse_enter_event_; - events::RoutedEvent<events::MouseEventArgs> mouse_leave_event_; - events::RoutedEvent<events::MouseEventArgs> mouse_move_event_; - events::RoutedEvent<events::MouseButtonEventArgs> mouse_down_event_; - events::RoutedEvent<events::MouseButtonEventArgs> mouse_up_event_; - events::RoutedEvent<events::MouseButtonEventArgs> mouse_click_event_; - events::RoutedEvent<events::MouseWheelEventArgs> mouse_wheel_event_; - - events::RoutedEvent<events::KeyEventArgs> key_down_event_; - events::RoutedEvent<events::KeyEventArgs> key_up_event_; - events::RoutedEvent<events::CharEventArgs> char_event_; - - events::RoutedEvent<events::FocusChangeEventArgs> gain_focus_event_; - events::RoutedEvent<events::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(MouseButton button); - virtual void OnMouseClickEnd(MouseButton button); - - private: - Window* window_ = nullptr; - Control* parent_ = nullptr; -}; -} // namespace cru::ui diff --git a/src/ui/input_util.cpp b/src/ui/input_util.cpp deleted file mode 100644 index 193cba4a..00000000 --- a/src/ui/input_util.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "input_util.hpp" - -#include <Windows.h> - -namespace cru::ui { -bool IsKeyDown(const int virtual_code) { - const auto result = ::GetKeyState(virtual_code); - return (static_cast<unsigned short>(result) & 0x8000) != 0; -} - -bool IsKeyToggled(const int virtual_code) { - const auto result = ::GetKeyState(virtual_code); - return (static_cast<unsigned short>(result) & 1) != 0; -} - -bool IsAnyMouseButtonDown() { - return IsKeyDown(VK_LBUTTON) || IsKeyDown(VK_RBUTTON) || - IsKeyDown(VK_MBUTTON); -} -} // namespace cru::ui diff --git a/src/ui/input_util.hpp b/src/ui/input_util.hpp deleted file mode 100644 index 2d01f725..00000000 --- a/src/ui/input_util.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include "pre.hpp" - -namespace cru::ui { -enum class MouseButton { Left, Right, Middle }; - -bool IsKeyDown(int virtual_code); -bool IsKeyToggled(int virtual_code); -bool IsAnyMouseButtonDown(); -} // namespace cru::ui diff --git a/src/ui/layout_control.cpp b/src/ui/layout_control.cpp index c0c4a7fe..9d789670 100644 --- a/src/ui/layout_control.cpp +++ b/src/ui/layout_control.cpp @@ -1,7 +1,9 @@ -#include "layout_control.hpp" +#include "cru/ui/layout_control.hpp" #include "window.hpp" +#include <cassert> + namespace cru::ui { LayoutControl::~LayoutControl() { for (const auto child : children_) delete child; @@ -10,7 +12,8 @@ LayoutControl::~LayoutControl() { void LayoutControl::AddChild(Control* control, const int position) { assert(control->GetParent() == nullptr); // The control already has a parent. assert(!dynamic_cast<Window*>(control)); // Can't add a window as child. - assert(position >= 0 || position <= this->children_.size()); // The position is out of range. + assert(position >= 0 || + position <= this->children_.size()); // The position is out of range. children_.insert(this->children_.cbegin() + position, control); diff --git a/src/ui/layout_control.hpp b/src/ui/layout_control.hpp deleted file mode 100644 index 53f53186..00000000 --- a/src/ui/layout_control.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "pre.hpp" - -#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/src/ui/no_child_control.cpp b/src/ui/no_child_control.cpp index e6bbe813..81299411 100644 --- a/src/ui/no_child_control.cpp +++ b/src/ui/no_child_control.cpp @@ -1,4 +1,4 @@ -#include "no_child_control.hpp" +#include "cru/ui/no_child_control.hpp" namespace cru::ui { const std::vector<Control*> NoChildControl::empty_control_vector{}; diff --git a/src/ui/no_child_control.hpp b/src/ui/no_child_control.hpp deleted file mode 100644 index 26b5546f..00000000 --- a/src/ui/no_child_control.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "pre.hpp" - -#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/src/ui/render/text_render_object.cpp b/src/ui/render/text_render_object.cpp index 69563ad7..bdf48c9a 100644 --- a/src/ui/render/text_render_object.cpp +++ b/src/ui/render/text_render_object.cpp @@ -1,103 +1,61 @@ -#include "text_render_object.hpp" +#include "cru/ui/render/text_render_object.hpp" -#include <d2d1.h> -#include <dwrite.h> -#include <algorithm> +#include "cru/platform/graph_factory.hpp" +#include "cru/platform/painter_util.hpp" +#include "cru/platform/text_layout.hpp" +#include "cru/platform/ui_applicaition.hpp" -#include "exception.hpp" -#include "graph/graph_manager.hpp" -#include "graph/graph_util.hpp" -#include "util/com_util.hpp" +#include <algorithm> +#include <cassert> namespace cru::ui::render { -TextRenderObject::TextRenderObject(ID2D1Brush* brush, IDWriteTextFormat* format, - ID2D1Brush* selection_brush) { +TextRenderObject::TextRenderObject( + std::shared_ptr<platform::Brush> brush, + std::shared_ptr<platform::FontDescriptor> font, + std::shared_ptr<platform::Brush> selection_brush) { assert(brush); - assert(format); + assert(font); assert(selection_brush); - brush->AddRef(); - format->AddRef(); - selection_brush->AddRef(); - this->brush_ = brush; - this->text_format_ = format; - this->selection_brush_ = selection_brush; - try { - RecreateTextLayout(); - } catch (...) { - brush->Release(); - format->Release(); - selection_brush->Release(); - throw; - } -} -TextRenderObject::~TextRenderObject() { - util::SafeRelease(brush_); - util::SafeRelease(text_format_); - util::SafeRelease(text_layout_); - util::SafeRelease(selection_brush_); -} + brush.swap(brush_); + font.swap(font_); + selection_brush.swap(selection_brush_); -void TextRenderObject::SetBrush(ID2D1Brush* new_brush) { - assert(new_brush); - util::SafeRelease(brush_); - new_brush->AddRef(); - brush_ = new_brush; -} + const auto graph_factory = + platform::UiApplication::GetInstance()->GetGraphFactory(); -void TextRenderObject::SetTextFormat(IDWriteTextFormat* new_text_format) { - assert(new_text_format); - util::SafeRelease(text_format_); - new_text_format->AddRef(); - text_format_ = new_text_format; - RecreateTextLayout(); + text_layout_.reset(graph_factory->CreateTextLayout(font_, L"")); } -void TextRenderObject::SetSelectionBrush(ID2D1Brush* new_brush) { - assert(new_brush); - util::SafeRelease(selection_brush_); - new_brush->AddRef(); - selection_brush_ = new_brush; +std::wstring TextRenderObject::GetText() const { + return text_layout_->GetText(); } -namespace { -void DrawSelectionRect(ID2D1RenderTarget* render_target, - IDWriteTextLayout* layout, ID2D1Brush* brush, - const std::optional<TextRange> range) { - if (range.has_value()) { - DWRITE_TEXT_METRICS text_metrics{}; - ThrowIfFailed(layout->GetMetrics(&text_metrics)); - const auto metrics_count = - text_metrics.lineCount * text_metrics.maxBidiReorderingDepth; - - std::vector<DWRITE_HIT_TEST_METRICS> hit_test_metrics(metrics_count); - UINT32 actual_count; - layout->HitTestTextRange(range.value().position, range.value().count, 0, 0, - hit_test_metrics.data(), metrics_count, - &actual_count); +void TextRenderObject::SetText(std::wstring new_text) { + text_layout_->SetText(std::move(new_text)); +} - hit_test_metrics.erase(hit_test_metrics.cbegin() + actual_count, - hit_test_metrics.cend()); +std::shared_ptr<platform::FontDescriptor> TextRenderObject::GetFont() const { + return text_layout_->GetFont(); +} - for (const auto& metrics : hit_test_metrics) - render_target->FillRoundedRectangle( - D2D1::RoundedRect(D2D1::RectF(metrics.left, metrics.top, - metrics.left + metrics.width, - metrics.top + metrics.height), - 3, 3), - brush); - } +void TextRenderObject::SetFont(std::shared_ptr<platform::FontDescriptor> font) { + text_layout_->SetFont(std::move(font)); } -} // namespace -void TextRenderObject::Draw(ID2D1RenderTarget* render_target) { - graph::WithTransform( - render_target, - D2D1::Matrix3x2F::Translation(GetMargin().left + GetPadding().left, +void TextRenderObject::Draw(platform::Painter* painter) { + platform::util::WithTransform( + painter, + platform::Matrix::Translation(GetMargin().left + GetPadding().left, GetMargin().top + GetPadding().top), - [this](auto rt) { - DrawSelectionRect(rt, text_layout_, selection_brush_, selection_range_); - rt->DrawTextLayout(D2D1::Point2F(), text_layout_, brush_); + [this](platform::Painter* p) { + if (this->selection_range_.has_value()) { + const auto&& rects = + text_layout_->TextRangeRect(this->selection_range_.value()); + for (const auto& rect : rects) + p->FillRectangle(rect, this->GetSelectionBrush().get()); + } + p->DrawText(Point{}, text_layout_.get(), brush_.get()); }); } @@ -115,34 +73,15 @@ RenderObject* TextRenderObject::HitTest(const Point& point) { void TextRenderObject::OnSizeChanged(const Size& old_size, const Size& new_size) { const auto&& size = GetContentRect().GetSize(); - ThrowIfFailed(text_layout_->SetMaxWidth(size.width)); - ThrowIfFailed(text_layout_->SetMaxHeight(size.height)); + text_layout_->SetMaxWidth(size.width); + text_layout_->SetMaxHeight(size.height); } Size TextRenderObject::OnMeasureContent(const Size& available_size) { - ThrowIfFailed(text_layout_->SetMaxWidth(available_size.width)); - ThrowIfFailed(text_layout_->SetMaxHeight(available_size.height)); - - DWRITE_TEXT_METRICS metrics; - ThrowIfFailed(text_layout_->GetMetrics(&metrics)); - - return Size(metrics.width, metrics.height); + text_layout_->SetMaxWidth(available_size.width); + text_layout_->SetMaxHeight(available_size.height); + return text_layout_->GetTextBounds().GetSize(); } void TextRenderObject::OnLayoutContent(const Rect& content_rect) {} - -void TextRenderObject::RecreateTextLayout() { - assert(text_format_ != nullptr); - - util::SafeRelease(text_layout_); - - const auto dwrite_factory = - graph::GraphManager::GetInstance()->GetDWriteFactory(); - - const auto&& size = GetContentRect().GetSize(); - - ThrowIfFailed(dwrite_factory->CreateTextLayout( - text_.c_str(), static_cast<UINT32>(text_.size()), text_format_, - size.width, size.height, &text_layout_)); -} } // namespace cru::ui::render diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp index 4d14575b..9c3c00d2 100644 --- a/src/ui/ui_manager.cpp +++ b/src/ui/ui_manager.cpp @@ -1,74 +1,27 @@ -#include "ui_manager.hpp" +#include "cru/ui/ui_manager.hpp" -#include <Windows.h> -#include <d2d1.h> -#include <dwrite.h> - -#include "application.hpp" -#include "exception.hpp" -#include "graph/graph_manager.hpp" -#include "graph/graph_util.hpp" -#include "util/com_util.hpp" +#include "cru/platform/graph_factory.hpp" +#include "cru/platform/ui_applicaition.hpp" namespace cru::ui { -namespace { -void GetSystemCaretInfo(CaretInfo* caret_info) { - caret_info->caret_blink_duration = - std::chrono::milliseconds(::GetCaretBlinkTime()); - DWORD caret_width; - if (!::SystemParametersInfoW(SPI_GETCARETWIDTH, 0, &caret_width, 0)) - throw Win32Error(::GetLastError(), "Failed to get system caret width."); - caret_info->half_caret_width = caret_width / 2.0f; -} - -IDWriteTextFormat* CreateDefaultTextFormat() { - const auto dwrite_factory = - graph::GraphManager::GetInstance()->GetDWriteFactory(); - IDWriteTextFormat* text_format; - - ThrowIfFailed(dwrite_factory->CreateTextFormat( - L"等线", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, - DWRITE_FONT_STRETCH_NORMAL, 24.0, L"zh-cn", &text_format)); - - ThrowIfFailed(text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); - ThrowIfFailed( - text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)); - - return text_format; -} -} // namespace - PredefineResources::PredefineResources() { - try { - button_normal_border_brush = - graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black)); + const auto graph_factory = + platform::UiApplication::GetInstance()->GetGraphFactory(); - text_block_selection_brush = - graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue)); - text_block_text_brush = - graph::CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black)); - text_block_text_format = CreateDefaultTextFormat(); - } catch (...) { - util::SafeRelease(button_normal_border_brush); - util::SafeRelease(text_block_selection_brush); - util::SafeRelease(text_block_text_brush); - util::SafeRelease(text_block_text_format); - } -} + button_normal_border_brush.reset( + graph_factory->CreateSolidColorBrush(colors::black)); -PredefineResources::~PredefineResources() { - util::SafeRelease(button_normal_border_brush); - util::SafeRelease(text_block_selection_brush); - util::SafeRelease(text_block_text_brush); - util::SafeRelease(text_block_text_format); + text_block_selection_brush.reset( + graph_factory->CreateSolidColorBrush(colors::skyblue)); + text_block_text_brush.reset( + graph_factory->CreateSolidColorBrush(colors::black)); + text_block_font.reset(graph_factory->CreateFontDescriptor(L"等线", 24.0f)); } UiManager* UiManager::GetInstance() { - return Application::GetInstance()->ResolveSingleton<UiManager>( - [](auto) { return new UiManager{}; }); + static UiManager instance; + return &instance; } -UiManager::UiManager() : predefine_resources_() { - GetSystemCaretInfo(&caret_info_); -} +UiManager::UiManager() : predefine_resources_(new PredefineResources()) {} } // namespace cru::ui diff --git a/src/ui/ui_manager.hpp b/src/ui/ui_manager.hpp deleted file mode 100644 index 107b536c..00000000 --- a/src/ui/ui_manager.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once -#include "pre.hpp" - -#include "base.hpp" - -struct ID2D1Brush; -struct IDWriteTextFormat; -namespace cru::graph { -class GraphManager; -} - -namespace cru::ui { -struct CaretInfo { - std::chrono::milliseconds caret_blink_duration; - float half_caret_width; -}; - -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; - - // region Button - ID2D1Brush* button_normal_border_brush = nullptr; - - // region TextBlock - ID2D1Brush* text_block_selection_brush = nullptr; - ID2D1Brush* text_block_text_brush = nullptr; - IDWriteTextFormat* text_block_text_format = nullptr; -}; - -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; - - CaretInfo GetCaretInfo() const { return caret_info_; } - - const PredefineResources* GetPredefineResources() const { - return &predefine_resources_; - } - - private: - CaretInfo caret_info_; - - PredefineResources predefine_resources_; -}; -} // namespace cru::ui diff --git a/src/ui/window.cpp b/src/ui/window.cpp index d138424f..1065a3fb 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -1,14 +1,10 @@ -#include "window.hpp" +#include "cru/ui/window.hpp" -#include <d2d1_1.h> -#include <windowsx.h> +#include "cru/ui/render/window_render_object.hpp" +#include "cru/platform/ui_applicaition.hpp" +#include "cru/platform/native_window.hpp" -#include "application.hpp" -#include "exception.hpp" -#include "graph/graph_manager.hpp" -#include "graph/graph_util.hpp" -#include "graph/window_render_target.hpp" -#include "render/window_render_object.hpp" +#include <cassert> namespace cru::ui { namespace { @@ -27,7 +23,7 @@ namespace { // as the rest arguments. template <typename EventArgs, typename... Args> void DispatchEvent(Control* const original_sender, - events::RoutedEvent<EventArgs>* (Control::*event_ptr)(), + event::RoutedEvent<EventArgs>* (Control::*event_ptr)(), Control* const last_receiver, Args&&... args) { std::list<Control*> receive_list; @@ -97,232 +93,31 @@ Control* FindLowestCommonAncestor(Control* left, Control* right) { } } // namespace - -inline Point PiToDip(const POINT& pi_point) { - return Point(graph::PixelToDipX(pi_point.x), graph::PixelToDipY(pi_point.y)); -} - -inline POINT DipToPi(const Point& dip_point) { - POINT result; - result.x = graph::DipToPixelX(dip_point.x); - result.y = graph::DipToPixelY(dip_point.y); - return result; -} - Window* Window::CreateOverlapped() { return new Window(tag_overlapped_constructor{}); } -Window* Window::CreatePopup(Window* parent, const bool caption) { - return new Window(tag_popup_constructor{}, parent, caption); -} Window::Window(tag_overlapped_constructor) { - BeforeCreateHwnd(); - - const auto window_manager = WindowManager::GetInstance(); - - hwnd_ = - CreateWindowEx(0, window_manager->GetGeneralWindowClass()->GetName(), L"", - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, - Application::GetInstance()->GetInstanceHandle(), nullptr); - - if (hwnd_ == nullptr) - throw Win32Error(::GetLastError(), "Failed to create window."); - - AfterCreateHwnd(window_manager); -} - -Window::Window(tag_popup_constructor, Window* parent, const bool caption) { - assert(parent == nullptr || - parent->IsWindowValid()); // Parent window is not valid. - - BeforeCreateHwnd(); - - parent_window_ = parent; - - const auto window_manager = WindowManager::GetInstance(); - - hwnd_ = CreateWindowEx( - 0, window_manager->GetGeneralWindowClass()->GetName(), L"", - caption ? (WS_POPUPWINDOW | WS_CAPTION) : WS_POPUP, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - parent == nullptr ? nullptr : parent->GetWindowHandle(), nullptr, - Application::GetInstance()->GetInstanceHandle(), nullptr); - - if (hwnd_ == nullptr) - throw Win32Error(::GetLastError(), "Failed to create window."); - - AfterCreateHwnd(window_manager); -} - -void Window::BeforeCreateHwnd() { window_ = this; } - -void Window::AfterCreateHwnd(WindowManager* window_manager) { - window_manager->RegisterWindow(hwnd_, this); - - render_target_.reset( - new graph::WindowRenderTarget(graph::GraphManager::GetInstance(), hwnd_)); - + native_window_ = platform::UiApplication::GetInstance()->CreateWindow(nullptr); render_object_.reset(new render::WindowRenderObject(this)); } Window::~Window() { - TraverseDescendants( [this](Control* control) { control->OnDetachToWindow(this); }); } -StringView Window::GetControlType() const { return control_type; } +std::wstring_view Window::GetControlType() const { return control_type; } render::RenderObject* Window::GetRenderObject() const { return render_object_.get(); } -bool Window::HandleWindowMessage(HWND hwnd, int msg, WPARAM w_param, - LPARAM l_param, LRESULT& result) { - events::WindowNativeMessageEventArgs args(this, this, - {hwnd, msg, w_param, l_param}); - native_message_event_.Raise(args); - if (args.GetResult().has_value()) { - result = args.GetResult().value(); - return true; - } - - switch (msg) { - case WM_PAINT: - OnPaintInternal(); - result = 0; - return true; - case WM_ERASEBKGND: - result = 1; - return true; - case WM_SETFOCUS: - OnSetFocusInternal(); - result = 0; - return true; - case WM_KILLFOCUS: - OnKillFocusInternal(); - result = 0; - return true; - case WM_MOUSEMOVE: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseMoveInternal(point); - result = 0; - return true; - } - case WM_LBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(MouseButton::Left, point); - result = 0; - return true; - } - case WM_LBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(MouseButton::Left, point); - result = 0; - return true; - } - case WM_RBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(MouseButton::Right, point); - result = 0; - return true; - } - case WM_RBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(MouseButton::Right, point); - result = 0; - return true; - } - case WM_MBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(MouseButton::Middle, point); - result = 0; - return true; - } - case WM_MBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(MouseButton::Middle, point); - result = 0; - return true; - } - case WM_MOUSEWHEEL: - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - ScreenToClient(hwnd, &point); - OnMouseWheelInternal(GET_WHEEL_DELTA_WPARAM(w_param), point); - result = 0; - return true; - case WM_KEYDOWN: - OnKeyDownInternal(static_cast<int>(w_param)); - result = 0; - return true; - case WM_KEYUP: - OnKeyUpInternal(static_cast<int>(w_param)); - result = 0; - return true; - case WM_CHAR: - OnCharInternal(static_cast<wchar_t>(w_param)); - result = 0; - return true; - case WM_SIZE: - OnResizeInternal(LOWORD(l_param), HIWORD(l_param)); - result = 0; - return true; - case WM_ACTIVATE: - if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE) - OnActivatedInternal(); - else if (w_param == WA_INACTIVE) - OnDeactivatedInternal(); - result = 0; - return true; - case WM_DESTROY: - OnDestroyInternal(); - result = 0; - return true; - default: - return false; - } -} - -Point Window::GetMousePosition() { - if (!IsWindowValid()) return Point::Zero(); - POINT point; - ::GetCursorPos(&point); - ::ScreenToClient(hwnd_, &point); - return PiToDip(point); -} - bool Window::RequestFocusFor(Control* control) { assert(control != nullptr); // The control to request focus can't be null. // You can set it as the window. - if (!IsWindowValid()) return false; - - if (!window_focus_) { - focus_control_ = control; - ::SetFocus(hwnd_); - return true; // event dispatch will be done in window message handling - // function "OnSetFocusInternal". - } - if (focus_control_ == control) return true; DispatchEvent(focus_control_, &Control::LoseFocusEvent, nullptr, false); @@ -336,41 +131,6 @@ bool Window::RequestFocusFor(Control* control) { Control* Window::GetFocusControl() { return focus_control_; } -Control* Window::CaptureMouseFor(Control* control) { - if (control != nullptr) { - ::SetCapture(hwnd_); - std::swap(mouse_capture_control_, control); - DispatchMouseHoverControlChangeEvent( - control ? control : mouse_hover_control_, mouse_capture_control_, - GetMousePosition()); - return control; - } else { - return ReleaseCurrentMouseCapture(); - } -} - -Control* Window::ReleaseCurrentMouseCapture() { - if (mouse_capture_control_) { - const auto previous = mouse_capture_control_; - mouse_capture_control_ = nullptr; - ::ReleaseCapture(); - DispatchMouseHoverControlChangeEvent(previous, mouse_hover_control_, - GetMousePosition()); - return previous; - } else { - return nullptr; - } -} - -#ifdef CRU_DEBUG_LAYOUT -void Window::SetDebugLayout(const bool value) { - if (debug_layout_ != value) { - debug_layout_ = value; - InvalidateDraw(); - } -} -#endif - void Window::OnChildChanged(Control* old_child, Control* new_child) { if (old_child) render_object_->RemoveChild(0); if (new_child) render_object_->AddChild(new_child->GetRenderObject(), 0); @@ -380,32 +140,9 @@ Control* Window::HitTest(const Point& point) { return render_object_->HitTest(point)->GetAttachedControl(); } -RECT Window::GetClientRectPixel() { - RECT rect{}; - GetClientRect(hwnd_, &rect); - return rect; -} - -bool Window::IsMessageInQueue(UINT message) { - MSG msg; - return ::PeekMessageW(&msg, hwnd_, message, message, PM_NOREMOVE) != 0; -} - -void Window::SetCursorInternal(HCURSOR cursor) { - if (IsWindowValid()) { - ::SetClassLongPtrW(GetWindowHandle(), GCLP_HCURSOR, - reinterpret_cast<LONG_PTR>(cursor)); - if (mouse_hover_control_ != nullptr) ::SetCursor(cursor); - } -} - -void Window::OnDestroyInternal() { - WindowManager::GetInstance()->UnregisterWindow(hwnd_); - hwnd_ = nullptr; - if (delete_this_on_destroy_) InvokeLater([this] { delete this; }); -} +void Window::OnNativeDestroy() { delete this; } -void Window::OnPaintInternal() { +void Window::OnNativePaint() { render_target_->SetAsTarget(); auto device_context = diff --git a/src/ui/window.hpp b/src/ui/window.hpp deleted file mode 100644 index f38743dc..00000000 --- a/src/ui/window.hpp +++ /dev/null @@ -1,162 +0,0 @@ -#pragma once -#include "cru/common/pre_config.hpp" - -#include <map> -#include <memory> - -#include "content_control.hpp" -#include "events/ui_event.hpp" -#include "window_class.hpp" - - -namespace cru::ui { - - -class Window final : public ContentControl { - public: - static constexpr auto control_type = L"Window"; - - public: - static Window* CreateOverlapped(); - static Window* CreatePopup(Window* parent, bool caption = false); - - private: - struct tag_overlapped_constructor {}; - struct tag_popup_constructor {}; - - explicit Window(tag_overlapped_constructor); - Window(tag_popup_constructor, Window* parent, bool caption); - - void BeforeCreateHwnd(); - void AfterCreateHwnd(WindowManager* window_manager); - - public: - 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; - - render::RenderObject* GetRenderObject() const override; - - - - - //*************** region: window operations *************** - - // 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); - - // Set the lefttop of the window relative to screen. - void SetWindowPosition(const Point& position); - - Point PointToScreen(const Point& point); - - Point PointFromScreen(const Point& point); - - // 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: 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: events *************** - public: - Event<events::UiEventArgs>* ActivatedEvent() { return &activated_event_; } - Event<events::UiEventArgs>* DeactivatedEvent() { return &deactivated_event_; } - Event<events::WindowNativeMessageEventArgs>* NativeMessageEvent() { - return &native_message_event_; - } - - private: - Event<events::UiEventArgs> activated_event_; - Event<events::UiEventArgs> deactivated_event_; - Event<events::WindowNativeMessageEventArgs> native_message_event_; - - protected: - void OnChildChanged(Control* old_child, Control* new_child) override; - - private: - Control* HitTest(const Point& point); - - //*************** region: native operations *************** - - // Get the client rect in pixel. - RECT GetClientRectPixel(); - - bool IsMessageInQueue(UINT message); - - void SetCursorInternal(HCURSOR cursor); - - //*************** 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 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: - std::shared_ptr<graph::WindowRenderTarget> render_target_{}; - std::shared_ptr<render::WindowRenderObject> render_object_{}; - - Control* mouse_hover_control_ = nullptr; - - bool window_focus_ = false; - Control* focus_control_ = this; // "focus_control_" can't be nullptr - Control* mouse_capture_control_ = nullptr; -}; -} // namespace cru::ui |