diff options
author | crupest <crupest@outlook.com> | 2019-03-20 19:26:55 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2019-03-20 19:26:55 +0800 |
commit | 616ebd78b543876388cb3d64f108abea041d4983 (patch) | |
tree | 8cae90f29695a3bd534b3ae5e32218d79719ba91 /src | |
parent | d518396a7fcdb2add413a9a37bb34515ff4f4cc4 (diff) | |
download | cru-616ebd78b543876388cb3d64f108abea041d4983.tar.gz cru-616ebd78b543876388cb3d64f108abea041d4983.tar.bz2 cru-616ebd78b543876388cb3d64f108abea041d4983.zip |
...
Diffstat (limited to 'src')
27 files changed, 239 insertions, 2106 deletions
diff --git a/src/ui/control.cpp b/src/ui/control.cpp index ee2abad0..98986d3c 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -1,20 +1,9 @@ #include "control.hpp" -#include <algorithm> #include <cassert> -#include "application.hpp" -#include "cru_debug.hpp" -#include "d2d_util.hpp" -#include "exception.hpp" -#include "graph/graph.hpp" -#include "math_util.hpp" #include "window.hpp" -#ifdef CRU_DEBUG_LAYOUT -#include "ui_manager.hpp" -#endif - namespace cru::ui { void Control::_SetParent(Control* parent) { @@ -122,11 +111,11 @@ void ControlAddChildCheck(Control* control) { throw std::invalid_argument("Can't add a window as child."); } -MultiChildControl::~MultiChildControl() { +Layout::~Layout() { for (const auto child : children_) delete child; } -void MultiChildControl::AddChild(Control* control, const int position) { +void Layout::AddChild(Control* control, const int position) { ControlAddChildCheck(control); if (position < 0 || static_cast<decltype(children_.size())>(position) > @@ -138,10 +127,10 @@ void MultiChildControl::AddChild(Control* control, const int position) { control->_SetParent(this); control->_SetDescendantWindow(GetWindow()); - OnAddChild(control); + OnAddChild(control, position); } -void MultiChildControl::RemoveChild(const int position) { +void Layout::RemoveChild(const int position) { if (position < 0 || static_cast<decltype(this->children_.size())>(position) >= this->children_.size()) throw std::invalid_argument("The position is out of range."); @@ -154,12 +143,12 @@ void MultiChildControl::RemoveChild(const int position) { child->_SetParent(nullptr); child->_SetDescendantWindow(nullptr); - OnRemoveChild(child); + OnRemoveChild(child, position); } -void MultiChildControl::OnAddChild(Control* child) {} +void Layout::OnAddChild(Control* child, int position) {} -void MultiChildControl::OnRemoveChild(Control* child) {} +void Layout::OnRemoveChild(Control* child, int position) {} std::list<Control*> GetAncestorList(Control* control) { std::list<Control*> l; diff --git a/src/ui/control.hpp b/src/ui/control.hpp index e85d0e6d..5f8ac02a 100644 --- a/src/ui/control.hpp +++ b/src/ui/control.hpp @@ -1,9 +1,6 @@ #pragma once #include "pre.hpp" -#include <any> -#include <unordered_map> -#include <utility> #include "system_headers.hpp" #include "base.hpp" @@ -15,6 +12,10 @@ namespace cru::ui { class Window; +namespace render { +class RenderObject; +} + class Control : public Object { friend class Window; @@ -50,6 +51,9 @@ class Control : public Object { static void TraverseDescendantsInternal( Control* control, const std::function<void(Control*)>& predicate); + public: + virtual render::RenderObject* GetRenderObject() const = 0; + //*************** region: focus *************** public: bool RequestFocus(); @@ -152,16 +156,16 @@ class ContentControl : public Control { Control*& child_; }; -class MultiChildControl : public Control { +class Layout : public Control { protected: - MultiChildControl() = default; + Layout() = default; public: - MultiChildControl(const MultiChildControl& other) = delete; - MultiChildControl(MultiChildControl&& other) = delete; - MultiChildControl& operator=(const MultiChildControl& other) = delete; - MultiChildControl& operator=(MultiChildControl&& other) = delete; - ~MultiChildControl() override; + Layout(const Layout& other) = delete; + Layout(Layout&& other) = delete; + Layout& operator=(const Layout& other) = delete; + Layout& operator=(Layout&& other) = delete; + ~Layout() override; const std::vector<Control*>& GetChildren() const override final { return children_; @@ -172,8 +176,8 @@ class MultiChildControl : public Control { void RemoveChild(int position); protected: - virtual void OnAddChild(Control* child); - virtual void OnRemoveChild(Control* child); + virtual void OnAddChild(Control* child, int position); + virtual void OnRemoveChild(Control* child, int position); private: std::vector<Control*> children_; diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp deleted file mode 100644 index d4537f54..00000000 --- a/src/ui/controls/button.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "button.hpp" - -#include "graph/graph.hpp" -#include "ui/ui_manager.hpp" - -namespace cru::ui::controls -{ - Button::Button() : - normal_border_{UiManager::GetInstance()->GetPredefineResources()->button_normal_border}, - pressed_border_{UiManager::GetInstance()->GetPredefineResources()->button_press_border} - { - SetBordered(true); - GetBorderProperty() = normal_border_; - - SetCursor(cursors::hand); - } - - StringView Button::GetControlType() const - { - return control_type; - } - - void Button::OnMouseClickBegin(MouseButton button) - { - GetBorderProperty() = pressed_border_; - UpdateBorder(); - } - - void Button::OnMouseClickEnd(MouseButton button) - { - GetBorderProperty() = normal_border_; - UpdateBorder(); - } -} diff --git a/src/ui/controls/button.hpp b/src/ui/controls/button.hpp deleted file mode 100644 index 6436f7c0..00000000 --- a/src/ui/controls/button.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include <initializer_list> - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - class Button : public ContentControl - { - public: - static constexpr auto control_type = L"Button"; - - static Button* Create(Control* child = nullptr) - { - const auto button = new Button(); - button->SetChild(child); - return button; - } - - protected: - Button(); - - public: - Button(const Button& other) = delete; - Button(Button&& other) = delete; - Button& operator=(const Button& other) = delete; - Button& operator=(Button&& other) = delete; - ~Button() override = default; - - StringView GetControlType() const override final; - - protected: - void OnMouseClickBegin(MouseButton button) override final; - void OnMouseClickEnd(MouseButton button) override final; - - private: - BorderProperty normal_border_; - BorderProperty pressed_border_; - }; -} diff --git a/src/ui/controls/flex_layout.cpp b/src/ui/controls/flex_layout.cpp new file mode 100644 index 00000000..ebe61a6d --- /dev/null +++ b/src/ui/controls/flex_layout.cpp @@ -0,0 +1,19 @@ +#include "flex_layout.hpp" + +#include "ui/render/flex_layout_render_object.hpp" + +namespace cru::ui::controls { +using render::FlexLayoutRenderObject; + +FlexLayout::FlexLayout() { render_object_ = new FlexLayoutRenderObject(); } + +FlexLayout::~FlexLayout() { delete render_object_; } + +void FlexLayout::OnAddChild(Control* child, int position) { + render_object_->AddChild(child->GetRenderObject(), position); +} + +void FlexLayout::OnRemoveChild(Control* child, int position) { + render_object_->RemoveChild(position); +} +} // namespace cru::ui::controls diff --git a/src/ui/controls/flex_layout.hpp b/src/ui/controls/flex_layout.hpp new file mode 100644 index 00000000..6acd25dc --- /dev/null +++ b/src/ui/controls/flex_layout.hpp @@ -0,0 +1,37 @@ +#pragma once +#include "pre.hpp" + +#include "ui/control.hpp" + +namespace cru::ui::render { +class FlexLayoutRenderObject; +} + +namespace cru::ui::controls { + +class FlexLayout : public Layout { + public: + static constexpr auto control_type = L"FlexLayout"; + + public: + FlexLayout(); + FlexLayout(const FlexLayout& other) = delete; + FlexLayout(FlexLayout&& other) = delete; + FlexLayout& operator=(const FlexLayout& other) = delete; + FlexLayout& operator=(FlexLayout&& other) = delete; + ~FlexLayout() override; + + StringView GetControlType() const override final { return control_type; } + + render::RenderObject* GetRenderObject() const override { + return render_object_; + } + + protected: + void OnAddChild(Control* child, int position) override; + void OnRemoveChild(Control* child, int position) override; + + private: + render::FlexLayoutRenderObject* render_object_; +}; +} // namespace cru::ui::controls diff --git a/src/ui/controls/frame_layout.cpp b/src/ui/controls/frame_layout.cpp deleted file mode 100644 index d68bc338..00000000 --- a/src/ui/controls/frame_layout.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "frame_layout.hpp" - -namespace cru::ui::controls -{ - FrameLayout::FrameLayout() = default; - - FrameLayout::~FrameLayout() = default; - - StringView FrameLayout::GetControlType() const - { - return control_type; - } - - Size FrameLayout::OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) - { - auto max_child_size = Size::Zero(); - for (auto control: GetChildren()) - { - control->Measure(available_size, additional_info); - const auto&& size = control->GetDesiredSize(); - if (max_child_size.width < size.width) - max_child_size.width = size.width; - if (max_child_size.height < size.height) - max_child_size.height = size.height; - } - - // coerce size fro stretch. - for (auto control: GetChildren()) - { - auto size = control->GetDesiredSize(); - const auto layout_params = control->GetLayoutParams(); - if (layout_params->width.mode == MeasureMode::Stretch) - size.width = max_child_size.width; - if (layout_params->height.mode == MeasureMode::Stretch) - size.height = max_child_size.height; - control->SetDesiredSize(size); - } - - return max_child_size; - } - - void FrameLayout::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) - { - for (auto control: GetChildren()) - { - const auto layout_params = control->GetLayoutParams(); - const auto size = control->GetDesiredSize(); - - auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float - { - switch (alignment) - { - case Alignment::Center: - return anchor + (layout_length - control_length) / 2; - case Alignment::Start: - return anchor; - case Alignment::End: - return anchor + layout_length - control_length; - default: - UnreachableCode(); - } - }; - - control->Layout(Rect(Point( - calculate_anchor(rect.left, layout_params->width.alignment, rect.width, size.width), - calculate_anchor(rect.top, layout_params->height.alignment, rect.height, size.height) - ), size), additional_info); - } - } -} diff --git a/src/ui/controls/frame_layout.hpp b/src/ui/controls/frame_layout.hpp deleted file mode 100644 index c2d6f0d6..00000000 --- a/src/ui/controls/frame_layout.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include <initializer_list> - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - class FrameLayout : public MultiChildControl - { - public: - static constexpr auto control_type = L"FrameLayout"; - - static FrameLayout* Create(const std::initializer_list<Control*>& children = std::initializer_list<Control*>{}) - { - const auto layout = new FrameLayout(); - for (auto child : children) - layout->AddChild(child); - return layout; - } - - protected: - FrameLayout(); - public: - FrameLayout(const FrameLayout& other) = delete; - FrameLayout(FrameLayout&& other) = delete; - FrameLayout& operator=(const FrameLayout& other) = delete; - FrameLayout& operator=(FrameLayout&& other) = delete; - ~FrameLayout() override; - - StringView GetControlType() const override final; - - protected: - Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) override; - void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) override; - }; -} diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp deleted file mode 100644 index c3de7ca3..00000000 --- a/src/ui/controls/linear_layout.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "linear_layout.hpp" - -#include <algorithm> - -#include "math_util.hpp" - -namespace cru::ui::controls -{ - LinearLayout::LinearLayout(const Orientation orientation) - : orientation_(orientation) - { - - } - - StringView LinearLayout::GetControlType() const - { - return control_type; - } - - Size LinearLayout::OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) - { - auto actual_size_for_children = Size::Zero(); - - float secondary_side_child_max_length = 0; - - std::list<Control*> stretch_control_list; - - // First measure Content and Exactly and count Stretch. - if (orientation_ == Orientation::Horizontal) - for(auto control: GetChildren()) - { - const auto mode = control->GetLayoutParams()->width.mode; - if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) - { - Size current_available_size(AtLeast0(available_size.width - actual_size_for_children.width), available_size.height); - control->Measure(current_available_size, additional_info); - const auto size = control->GetDesiredSize(); - actual_size_for_children.width += size.width; - secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length); - } - else - stretch_control_list.push_back(control); - } - else - for(auto control: GetChildren()) - { - const auto mode = control->GetLayoutParams()->height.mode; - if (mode == MeasureMode::Content || mode == MeasureMode::Exactly) - { - Size current_available_size(available_size.width, AtLeast0(available_size.height - actual_size_for_children.height)); - control->Measure(current_available_size, additional_info); - const auto size = control->GetDesiredSize(); - actual_size_for_children.height += size.height; - secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length); - } - else - stretch_control_list.push_back(control); - } - - if (orientation_ == Orientation::Horizontal) - { - const auto available_width = AtLeast0(available_size.width - actual_size_for_children.width) / stretch_control_list.size(); - for (const auto control : stretch_control_list) - { - control->Measure(Size(available_width, available_size.height), additional_info); - const auto size = control->GetDesiredSize(); - actual_size_for_children.width += size.width; - secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length); - } - } - else - { - const auto available_height = AtLeast0(available_size.height - actual_size_for_children.height) / stretch_control_list.size(); - for (const auto control : stretch_control_list) - { - control->Measure(Size(available_size.width, available_height), additional_info); - const auto size = control->GetDesiredSize(); - actual_size_for_children.height += size.height; - secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length); - } - } - - if (orientation_ == Orientation::Horizontal) - { - for (auto control : GetChildren()) - { - if (control->GetLayoutParams()->height.mode == MeasureMode::Stretch) - { - control->SetDesiredSize(Size(control->GetDesiredSize().width, secondary_side_child_max_length)); - } - } - actual_size_for_children.height = secondary_side_child_max_length; - } - else - { - for (auto control : GetChildren()) - { - if (control->GetLayoutParams()->width.mode == MeasureMode::Stretch) - { - control->SetDesiredSize(Size(secondary_side_child_max_length, control->GetDesiredSize().height)); - } - } - - actual_size_for_children.width = secondary_side_child_max_length; - } - - return actual_size_for_children; - } - - void LinearLayout::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) - { - float current_main_side_anchor = 0; - for(auto control: GetChildren()) - { - const auto layout_params = control->GetLayoutParams(); - const auto size = control->GetDesiredSize(); - const auto alignment = orientation_ == Orientation::Horizontal ? layout_params->height.alignment : layout_params->width.alignment; - - auto&& calculate_secondary_side_anchor = [alignment](const float layout_length, const float control_length) -> float - { - switch (alignment) - { - case Alignment::Center: - return (layout_length - control_length) / 2; - case Alignment::Start: - return 0; - case Alignment::End: - return layout_length - control_length; - default: - UnreachableCode(); - } - }; - - auto&& calculate_rect = [rect, size](const float anchor_left, const float anchor_top) - { - return Rect(Point(rect.left + anchor_left, rect.top + anchor_top), size); - }; - - if (orientation_ == Orientation::Horizontal) - { - control->Layout(calculate_rect(current_main_side_anchor, calculate_secondary_side_anchor(rect.height, size.height)), additional_info); - current_main_side_anchor += size.width; - } - else - { - control->Layout(calculate_rect(calculate_secondary_side_anchor(rect.width, size.width), current_main_side_anchor), additional_info); - current_main_side_anchor += size.height; - } - } - } -} diff --git a/src/ui/controls/linear_layout.hpp b/src/ui/controls/linear_layout.hpp deleted file mode 100644 index ceb1c4e6..00000000 --- a/src/ui/controls/linear_layout.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - // Min length of main side in layout params is of no meaning. - // All children will layout from start and redundant length is blank. - class LinearLayout : public MultiChildControl - { - public: - static constexpr auto control_type = L"LinearLayout"; - - enum class Orientation - { - Horizontal, - Vertical - }; - - static LinearLayout* Create(const Orientation orientation = Orientation::Vertical, const std::initializer_list<Control*>& children = std::initializer_list<Control*>()) - { - const auto linear_layout = new LinearLayout(orientation); - for (const auto control : children) - linear_layout->AddChild(control); - return linear_layout; - } - - protected: - explicit LinearLayout(Orientation orientation = Orientation::Vertical); - - public: - LinearLayout(const LinearLayout& other) = delete; - LinearLayout(LinearLayout&& other) = delete; - LinearLayout& operator=(const LinearLayout& other) = delete; - LinearLayout& operator=(LinearLayout&& other) = delete; - ~LinearLayout() override = default; - - StringView GetControlType() const override final; - - protected: - Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) override; - void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) override; - - private: - Orientation orientation_; - }; -} diff --git a/src/ui/controls/list_item.cpp b/src/ui/controls/list_item.cpp deleted file mode 100644 index 6dd37fe9..00000000 --- a/src/ui/controls/list_item.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "list_item.hpp" - -#include "ui/ui_manager.hpp" -#include "ui/d2d_util.hpp" - -namespace cru::ui::controls -{ - ListItem::ListItem() - { - const auto predefine_resources = UiManager::GetInstance()->GetPredefineResources(); - - brushes_[State::Normal].border_brush = predefine_resources->list_item_normal_border_brush; - brushes_[State::Normal].fill_brush = predefine_resources->list_item_normal_fill_brush; - brushes_[State::Hover] .border_brush = predefine_resources->list_item_hover_border_brush; - brushes_[State::Hover] .fill_brush = predefine_resources->list_item_hover_fill_brush; - brushes_[State::Select].border_brush = predefine_resources->list_item_select_border_brush; - brushes_[State::Select].fill_brush = predefine_resources->list_item_select_fill_brush; - - draw_foreground_event.AddHandler([this](events::DrawEventArgs& args) - { - const auto device_context = args.GetDeviceContext(); - const auto rect = Rect(Point::Zero(), GetRect(RectRange::Padding).GetSize()); - device_context->FillRectangle(Convert(rect), brushes_[state_].fill_brush.Get()); - device_context->DrawRectangle(Convert(rect.Shrink(Thickness(0.5))), brushes_[state_].border_brush.Get(), 1); - }); - - mouse_enter_event.direct.AddHandler([this](events::MouseEventArgs& args) - { - if (GetState() == State::Select) - return; - - if (IsAnyMouseButtonDown()) - return; - - SetState(State::Hover); - }); - - mouse_leave_event.direct.AddHandler([this](events::MouseEventArgs& args) - { - if (GetState() == State::Select) - return; - - SetState(State::Normal); - }); - - mouse_click_event.direct.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left) - SetState(State::Select); - }); - } - - StringView ListItem::GetControlType() const - { - return control_type; - } - - void ListItem::SetState(const State state) - { - state_ = state; - InvalidateDraw(); - } -} diff --git a/src/ui/controls/list_item.hpp b/src/ui/controls/list_item.hpp deleted file mode 100644 index bf8f8d8e..00000000 --- a/src/ui/controls/list_item.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include <map> -#include <initializer_list> - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - class ListItem : public ContentControl - { - public: - static constexpr auto control_type = L"ListItem"; - - enum class State - { - Normal, - Hover, - Select - }; - - private: - struct StateBrush - { - Microsoft::WRL::ComPtr<ID2D1Brush> border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> fill_brush; - }; - - public: - static ListItem* Create(Control* child = nullptr) - { - const auto list_item = new ListItem(); - list_item->SetChild(child); - return list_item; - } - - private: - ListItem(); - public: - ListItem(const ListItem& other) = delete; - ListItem(ListItem&& other) = delete; - ListItem& operator=(const ListItem& other) = delete; - ListItem& operator=(ListItem&& other) = delete; - ~ListItem() override = default; - - StringView GetControlType() const override; - - State GetState() const - { - return state_; - } - - void SetState(State state); - - private: - State state_ = State::Normal; - std::map<State, StateBrush> brushes_{}; - }; -} diff --git a/src/ui/controls/popup_menu.cpp b/src/ui/controls/popup_menu.cpp deleted file mode 100644 index fbe9039d..00000000 --- a/src/ui/controls/popup_menu.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "popup_menu.hpp" - -#include "ui/window.hpp" -#include "text_block.hpp" -#include "list_item.hpp" -#include "linear_layout.hpp" -#include "ui/events/ui_event.hpp" - -namespace cru::ui::controls -{ - Window* CreatePopupMenu(const Point& anchor, const std::vector<MenuItemInfo>& items, Window* parent) - { - const auto popup = Window::CreatePopup(parent); - - popup->lose_focus_event.bubble.AddHandler([popup](events::FocusChangeEventArgs& args) - { - if (args.IsWindow()) - popup->Close(); - }); - - const auto create_menu_item = [popup](const String& text, const std::function<void()>& action) -> ListItem* - { - auto text_block = TextBlock::Create(text); - text_block->GetLayoutParams()->width.alignment = Alignment::Start; - - auto list_item = CreateWithLayout<ListItem>( - LayoutSideParams::Stretch(Alignment::Center), - LayoutSideParams::Content(Alignment::Start), - text_block - ); - - list_item->mouse_click_event.bubble.AddHandler([popup, action](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left) - { - action(); - popup->Close(); - } - }); - - return list_item; - }; - - const auto menu = LinearLayout::Create(LinearLayout::Orientation::Vertical); - - menu->SetBordered(true); - - for (const auto& item : items) - menu->AddChild(create_menu_item(item.first, item.second)); - - popup->SetChild(menu); - - popup->SetSizeFitContent(); - popup->SetWindowPosition(anchor); - - return popup; - } -} diff --git a/src/ui/controls/popup_menu.hpp b/src/ui/controls/popup_menu.hpp deleted file mode 100644 index a2916590..00000000 --- a/src/ui/controls/popup_menu.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include <vector> -#include <utility> -#include <functional> - -#include "base.hpp" -#include "ui/ui_base.hpp" - -namespace cru::ui -{ - class Window; -} - -namespace cru::ui::controls -{ - using MenuItemInfo = std::pair<String, std::function<void()>>; - - Window* CreatePopupMenu(const Point& anchor, const std::vector<MenuItemInfo>& items, Window* parent = nullptr); -} diff --git a/src/ui/controls/scroll_control.cpp b/src/ui/controls/scroll_control.cpp deleted file mode 100644 index a202e355..00000000 --- a/src/ui/controls/scroll_control.cpp +++ /dev/null @@ -1,384 +0,0 @@ -#include "scroll_control.hpp" - -#include <limits> - -#include "cru_debug.hpp" -#include "ui/d2d_util.hpp" -#include "exception.hpp" -#include "math_util.hpp" -#include "ui/ui_manager.hpp" -#include "ui/window.hpp" - -namespace cru::ui::controls -{ - constexpr auto scroll_bar_width = 15.0f; - - ScrollControl::ScrollControl(const bool container) - { - SetClipContent(true); - - draw_foreground_event.AddHandler([this](events::DrawEventArgs& args) - { - const auto device_context = args.GetDeviceContext(); - const auto predefined = UiManager::GetInstance()->GetPredefineResources(); - - if (is_horizontal_scroll_bar_visible_) - { - device_context->FillRectangle( - Convert(horizontal_bar_info_.border), - predefined->scroll_bar_background_brush.Get() - ); - - device_context->FillRectangle( - Convert(horizontal_bar_info_.bar), - predefined->scroll_bar_brush.Get() - ); - - device_context->DrawLine( - Convert(horizontal_bar_info_.border.GetLeftTop()), - Convert(horizontal_bar_info_.border.GetRightTop()), - predefined->scroll_bar_border_brush.Get() - ); - } - - if (is_vertical_scroll_bar_visible_) - { - device_context->FillRectangle( - Convert(vertical_bar_info_.border), - predefined->scroll_bar_background_brush.Get() - ); - - device_context->FillRectangle( - Convert(vertical_bar_info_.bar), - predefined->scroll_bar_brush.Get() - ); - - device_context->DrawLine( - Convert(vertical_bar_info_.border.GetLeftTop()), - Convert(vertical_bar_info_.border.GetLeftBottom()), - predefined->scroll_bar_border_brush.Get() - ); - } - }); - - mouse_down_event.tunnel.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left) - { - const auto point = args.GetPoint(this); - if (is_vertical_scroll_bar_visible_ && vertical_bar_info_.bar.IsPointInside(point)) - { - GetWindow()->CaptureMouseFor(this); - is_pressing_scroll_bar_ = Orientation::Vertical; - pressing_delta_ = point.y - vertical_bar_info_.bar.top; - args.SetHandled(); - return; - } - - if (is_horizontal_scroll_bar_visible_ && horizontal_bar_info_.bar.IsPointInside(point)) - { - GetWindow()->CaptureMouseFor(this); - pressing_delta_ = point.x - horizontal_bar_info_.bar.left; - is_pressing_scroll_bar_ = Orientation::Horizontal; - args.SetHandled(); - return; - } - } - }); - - mouse_move_event.tunnel.AddHandler([this](events::MouseEventArgs& args) - { - const auto mouse_point = args.GetPoint(this); - - if (is_pressing_scroll_bar_ == Orientation::Horizontal) - { - const auto new_head_position = mouse_point.x - pressing_delta_; - const auto new_offset = new_head_position / horizontal_bar_info_.border.width * view_width_; - SetScrollOffset(new_offset, std::nullopt); - args.SetHandled(); - return; - } - - if (is_pressing_scroll_bar_ == Orientation::Vertical) - { - const auto new_head_position = mouse_point.y - pressing_delta_; - const auto new_offset = new_head_position / vertical_bar_info_.border.height * view_height_; - SetScrollOffset(std::nullopt, new_offset); - args.SetHandled(); - return; - } - }); - - mouse_up_event.tunnel.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left && is_pressing_scroll_bar_.has_value()) - { - GetWindow()->ReleaseCurrentMouseCapture(); - is_pressing_scroll_bar_ = std::nullopt; - args.SetHandled(); - } - }); - - mouse_wheel_event.bubble.AddHandler([this](events::MouseWheelEventArgs& args) - { - constexpr const auto view_delta = 30.0f; - - if (args.GetDelta() == 0.0f) - return; - - const auto content_rect = GetRect(RectRange::Content); - if (IsVerticalScrollEnabled() && GetScrollOffsetY() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewHeight() - content_rect.height))) - { - SetScrollOffset(std::nullopt, GetScrollOffsetY() - args.GetDelta() / WHEEL_DELTA * view_delta); - args.SetHandled(); - return; - } - - if (IsHorizontalScrollEnabled() && GetScrollOffsetX() != (args.GetDelta() > 0.0f ? 0.0f : AtLeast0(GetViewWidth() - content_rect.width))) - { - SetScrollOffset(GetScrollOffsetX() - args.GetDelta() / WHEEL_DELTA * view_delta, std::nullopt); - args.SetHandled(); - return; - } - }); - } - - ScrollControl::~ScrollControl() - { - - } - - StringView ScrollControl::GetControlType() const - { - return control_type; - } - - void ScrollControl::SetHorizontalScrollEnabled(const bool enable) - { - horizontal_scroll_enabled_ = enable; - InvalidateLayout(); - InvalidateDraw(); - } - - void ScrollControl::SetVerticalScrollEnabled(const bool enable) - { - vertical_scroll_enabled_ = enable; - InvalidateLayout(); - InvalidateDraw(); - } - - void ScrollControl::SetHorizontalScrollBarVisibility(const ScrollBarVisibility visibility) - { - if (visibility != horizontal_scroll_bar_visibility_) - { - horizontal_scroll_bar_visibility_ = visibility; - switch (visibility) - { - case ScrollBarVisibility::Always: - is_horizontal_scroll_bar_visible_ = true; - break; - case ScrollBarVisibility::None: - is_horizontal_scroll_bar_visible_ = false; - break; - case ScrollBarVisibility::Auto: - UpdateScrollBarVisibility(); - } - InvalidateDraw(); - } - } - - void ScrollControl::SetVerticalScrollBarVisibility(const ScrollBarVisibility visibility) - { - if (visibility != vertical_scroll_bar_visibility_) - { - vertical_scroll_bar_visibility_ = visibility; - switch (visibility) - { - case ScrollBarVisibility::Always: - is_vertical_scroll_bar_visible_ = true; - break; - case ScrollBarVisibility::None: - is_vertical_scroll_bar_visible_ = false; - break; - case ScrollBarVisibility::Auto: - UpdateScrollBarVisibility(); - } - InvalidateDraw(); - } - - } - - void ScrollControl::SetScrollOffset(std::optional<float> x, std::optional<float> y) - { - CoerceAndSetOffsets(x.value_or(GetScrollOffsetX()), y.value_or(GetScrollOffsetY())); - } - - void ScrollControl::SetViewWidth(const float length) - { - view_width_ = length; - } - - void ScrollControl::SetViewHeight(const float length) - { - view_height_ = length; - } - - Size ScrollControl::OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) - { - const auto layout_params = GetLayoutParams(); - - auto available_size_for_children = available_size; - if (IsHorizontalScrollEnabled()) - { - if (layout_params->width.mode == MeasureMode::Content) - debug::DebugMessage(L"ScrollControl: Width measure mode is Content and horizontal scroll is enabled. So Stretch is used instead."); - - available_size_for_children.width = std::numeric_limits<float>::max(); - } - - if (IsVerticalScrollEnabled()) - { - if (layout_params->height.mode == MeasureMode::Content) - debug::DebugMessage(L"ScrollControl: Height measure mode is Content and vertical scroll is enabled. So Stretch is used instead."); - - available_size_for_children.height = std::numeric_limits<float>::max(); - } - - const auto child = GetChild(); - - auto size = Size::Zero(); - if (child) - { - child->Measure(available_size_for_children, AdditionalMeasureInfo{false, false}); - size = child->GetDesiredSize(); - } - - - auto result = size; - if (IsHorizontalScrollEnabled()) - { - SetViewWidth(size.width); - result.width = available_size.width; - } - if (IsVerticalScrollEnabled()) - { - SetViewHeight(size.height); - result.height = available_size.height; - } - - return result; - } - - void ScrollControl::OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) - { - auto layout_rect = rect; - - if (IsHorizontalScrollEnabled()) - layout_rect.width = GetViewWidth(); - if (IsVerticalScrollEnabled()) - layout_rect.height = GetViewHeight(); - - const auto child = GetChild(); - - if (child) - { - const auto layout_params = child->GetLayoutParams(); - const auto size = child->GetDesiredSize(); - - auto&& calculate_anchor = [](const float anchor, const Alignment alignment, const float layout_length, const float control_length) -> float - { - switch (alignment) - { - case Alignment::Center: - return anchor + (layout_length - control_length) / 2; - case Alignment::Start: - return anchor; - case Alignment::End: - return anchor + layout_length - control_length; - default: - UnreachableCode(); - } - }; - - child->Layout(Rect(Point( - IsHorizontalScrollEnabled() ? layout_rect.left + offset_x_ : calculate_anchor(layout_rect.left, layout_params->width.alignment, layout_rect.width, size.width), - IsVerticalScrollEnabled() ? layout_rect.top + offset_y_ : calculate_anchor(layout_rect.top, layout_params->height.alignment, layout_rect.height, size.height) - ), size), additional_info); - } - } - - void ScrollControl::OnRectChange(const Rect& old_rect, const Rect& new_rect) - { - UpdateScrollBarBorderInfo(); - CoerceAndSetOffsets(offset_x_, offset_y_, false); - UpdateScrollBarVisibility(); - } - - void ScrollControl::CoerceAndSetOffsets(const float offset_x, const float offset_y, const bool update_children) - { - const auto old_offset_x = offset_x_; - const auto old_offset_y = offset_y_; - - const auto content_rect = GetRect(RectRange::Content); - offset_x_ = Coerce(offset_x, 0.0f, AtLeast0(view_width_ - content_rect.width)); - offset_y_ = Coerce(offset_y, 0.0f, AtLeast0(view_height_ - content_rect.height)); - UpdateScrollBarBarInfo(); - - if (update_children) - { - if (const auto child = GetChild()) - { - const auto old_position = child->GetOffset(); - child->SetRect(Rect(Point( - old_position.x + old_offset_x - offset_x_, - old_position.y + old_offset_y - offset_y_ - ), child->GetSize())); - child->RefreshDescendantPositionCache(); - } - } - InvalidateDraw(); - } - - void ScrollControl::UpdateScrollBarVisibility() - { - const auto content_rect = GetRect(RectRange::Content); - if (GetHorizontalScrollBarVisibility() == ScrollBarVisibility::Auto) - is_horizontal_scroll_bar_visible_ = view_width_ > content_rect.width; - if (GetVerticalScrollBarVisibility() == ScrollBarVisibility::Auto) - is_vertical_scroll_bar_visible_ = view_height_ > content_rect.height; - } - - void ScrollControl::UpdateScrollBarBorderInfo() - { - const auto content_rect = GetRect(RectRange::Content); - horizontal_bar_info_.border = Rect(content_rect.left, content_rect.GetBottom() - scroll_bar_width, content_rect.width, scroll_bar_width); - vertical_bar_info_.border = Rect(content_rect.GetRight() - scroll_bar_width , content_rect.top, scroll_bar_width, content_rect.height); - } - - void ScrollControl::UpdateScrollBarBarInfo() - { - const auto content_rect = GetRect(RectRange::Content); - { - const auto& border = horizontal_bar_info_.border; - if (view_width_ <= content_rect.width) - horizontal_bar_info_.bar = border; - else - { - const auto bar_length = border.width * content_rect.width / view_width_; - const auto offset = border.width * offset_x_ / view_width_; - horizontal_bar_info_.bar = Rect(border.left + offset, border.top, bar_length, border.height); - } - } - { - const auto& border = vertical_bar_info_.border; - if (view_height_ <= content_rect.height) - vertical_bar_info_.bar = border; - else - { - const auto bar_length = border.height * content_rect.height / view_height_; - const auto offset = border.height * offset_y_ / view_height_; - vertical_bar_info_.bar = Rect(border.left, border.top + offset, border.width, bar_length); - } - } - } -} diff --git a/src/ui/controls/scroll_control.hpp b/src/ui/controls/scroll_control.hpp deleted file mode 100644 index 84ebca30..00000000 --- a/src/ui/controls/scroll_control.hpp +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include <optional> -#include <initializer_list> - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - // Done: OnMeasureContent - // Done: OnLayoutContent - // Done: HitTest(no need) - // Done: Draw(no need) - // Done: API - // Done: ScrollBar - // Done: MouseEvent - class ScrollControl : public ContentControl - { - private: - struct ScrollBarInfo - { - Rect border = Rect(); - Rect bar = Rect(); - }; - - enum class Orientation - { - Horizontal, - Vertical - }; - - public: - enum class ScrollBarVisibility - { - None, - Auto, - Always - }; - - static ScrollControl* Create(Control* child = nullptr) - { - const auto control = new ScrollControl(true); - control->SetChild(child); - return control; - } - - static constexpr auto control_type = L"ScrollControl"; - - protected: - explicit ScrollControl(bool container); - public: - ScrollControl(const ScrollControl& other) = delete; - ScrollControl(ScrollControl&& other) = delete; - ScrollControl& operator=(const ScrollControl& other) = delete; - ScrollControl& operator=(ScrollControl&& other) = delete; - ~ScrollControl() override; - - StringView GetControlType() const override final; - - bool IsHorizontalScrollEnabled() const - { - return horizontal_scroll_enabled_; - } - - void SetHorizontalScrollEnabled(bool enable); - - bool IsVerticalScrollEnabled() const - { - return vertical_scroll_enabled_; - } - - void SetVerticalScrollEnabled(bool enable); - - - ScrollBarVisibility GetHorizontalScrollBarVisibility() const - { - return horizontal_scroll_bar_visibility_; - } - - void SetHorizontalScrollBarVisibility(ScrollBarVisibility visibility); - - ScrollBarVisibility GetVerticalScrollBarVisibility() const - { - return vertical_scroll_bar_visibility_; - } - - void SetVerticalScrollBarVisibility(ScrollBarVisibility visibility); - - float GetViewWidth() const - { - return view_width_; - } - - float GetViewHeight() const - { - return view_height_; - } - - float GetScrollOffsetX() const - { - return offset_x_; - } - - float GetScrollOffsetY() const - { - return offset_y_; - } - - // nullopt for not set. value is auto-coerced. - void SetScrollOffset(std::optional<float> x, std::optional<float> y); - - protected: - void SetViewWidth(float length); - void SetViewHeight(float length); - - Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo& additional_info) override final; - void OnLayoutContent(const Rect& rect, const AdditionalLayoutInfo& additional_info) override final; - - void OnRectChange(const Rect& old_rect, const Rect& new_rect) override; - - private: - void CoerceAndSetOffsets(float offset_x, float offset_y, bool update_children = true); - void UpdateScrollBarVisibility(); - void UpdateScrollBarBorderInfo(); - void UpdateScrollBarBarInfo(); - - private: - bool horizontal_scroll_enabled_ = true; - bool vertical_scroll_enabled_ = true; - - ScrollBarVisibility horizontal_scroll_bar_visibility_ = ScrollBarVisibility::Auto; - ScrollBarVisibility vertical_scroll_bar_visibility_ = ScrollBarVisibility::Auto; - - bool is_horizontal_scroll_bar_visible_ = false; - bool is_vertical_scroll_bar_visible_ = false; - - float offset_x_ = 0.0f; - float offset_y_ = 0.0f; - - float view_width_ = 0.0f; - float view_height_ = 0.0f; - - ScrollBarInfo horizontal_bar_info_; - ScrollBarInfo vertical_bar_info_; - - std::optional<Orientation> is_pressing_scroll_bar_ = std::nullopt; - float pressing_delta_ = 0.0f; - }; -} diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp index 8276ce4e..123dbc86 100644 --- a/src/ui/controls/text_block.cpp +++ b/src/ui/controls/text_block.cpp @@ -1,19 +1,23 @@ #include "text_block.hpp" +#include "ui/render/text_render_object.hpp" #include "ui/ui_manager.hpp" -namespace cru::ui::controls -{ - TextBlock::TextBlock() : TextControl( - UiManager::GetInstance()->GetPredefineResources()->text_block_text_format, - UiManager::GetInstance()->GetPredefineResources()->text_block_text_brush - ) - { +namespace cru::ui::controls { +using render::TextRenderObject; - } - - StringView TextBlock::GetControlType() const - { - return control_type; - } +TextBlock::TextBlock() { + const auto predefined_resources = + UiManager::GetInstance()->GetPredefineResources(); + render_object_ = + new TextRenderObject(predefined_resources->text_block_text_brush, + predefined_resources->text_block_text_format, + predefined_resources->text_block_selection_brush); } + +TextBlock::~TextBlock() { delete render_object_; } + +String TextBlock::GetText() const { return render_object_->GetText(); } + +void TextBlock::SetText(const String& text) { render_object_->SetText(text); } +} // namespace cru::ui::controls diff --git a/src/ui/controls/text_block.hpp b/src/ui/controls/text_block.hpp index 66f5defa..ce8977a5 100644 --- a/src/ui/controls/text_block.hpp +++ b/src/ui/controls/text_block.hpp @@ -1,35 +1,35 @@ #pragma once - -// ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" -#include "text_control.hpp" - -namespace cru::ui::controls -{ - class TextBlock : public TextControl - { - public: - static constexpr auto control_type = L"TextBlock"; - - static TextBlock* Create(const String& text = L"") - { - const auto text_block = new TextBlock(); - text_block->SetText(text); - return text_block; - } - - protected: - TextBlock(); - public: - TextBlock(const TextBlock& other) = delete; - TextBlock(TextBlock&& other) = delete; - TextBlock& operator=(const TextBlock& other) = delete; - TextBlock& operator=(TextBlock&& other) = delete; - ~TextBlock() override = default; - - StringView GetControlType() const override final; - - using TextControl::SetSelectable; // Make this public. - }; +#include "ui/control.hpp" + +namespace cru::ui::render { +class TextRenderObject; } + +namespace cru::ui::controls { +class TextBlock : public NoChildControl { + public: + static constexpr auto control_type = L"TextBlock"; + + public: + TextBlock(); + TextBlock(const TextBlock& other) = delete; + TextBlock(TextBlock&& other) = delete; + TextBlock& operator=(const TextBlock& other) = delete; + TextBlock& operator=(TextBlock&& other) = delete; + ~TextBlock() override; + + StringView GetControlType() const override final { return control_type; } + + render::RenderObject* GetRenderObject() const override { + return render_object_; + } + + String GetText() const; + void SetText(const String& text); + + private: + render::TextRenderObject* render_object_; +}; +} // namespace cru::ui::controls diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp deleted file mode 100644 index 893d6e8d..00000000 --- a/src/ui/controls/text_box.cpp +++ /dev/null @@ -1,198 +0,0 @@ -#include "text_box.hpp" - -#include <cwctype> -#include <cassert> - -#include "graph/graph.hpp" -#include "exception.hpp" -#include "ui/ui_manager.hpp" - -namespace cru::ui::controls -{ - TextBox::TextBox() : TextControl( - UiManager::GetInstance()->GetPredefineResources()->text_box_text_format, - UiManager::GetInstance()->GetPredefineResources()->text_box_text_brush - ) - { - SetSelectable(true); - - caret_brush_ = UiManager::GetInstance()->GetPredefineResources()->text_box_caret_brush; - - GetBorderProperty() = UiManager::GetInstance()->GetPredefineResources()->text_box_border; - SetBordered(true); - - draw_content_event.AddHandler([this](events::DrawEventArgs& args) - { - const auto device_context = args.GetDeviceContext(); - if (is_caret_show_) - { - const auto caret_half_width = UiManager::GetInstance()->GetCaretInfo().half_caret_width; - FLOAT x, y; - DWRITE_HIT_TEST_METRICS metrics{}; - ThrowIfFailed(text_layout_->HitTestTextPosition(caret_position_, FALSE, &x, &y, &metrics)); - device_context->FillRectangle(D2D1::RectF(metrics.left - caret_half_width, metrics.top, metrics.left + caret_half_width, metrics.top + metrics.height), caret_brush_.Get()); - } - }); - - get_focus_event.direct.AddHandler([this](events::FocusChangeEventArgs& args) - { - assert(!caret_timer_.has_value()); - is_caret_show_ = true; - caret_timer_ = SetInterval(UiManager::GetInstance()->GetCaretInfo().caret_blink_duration, [this] - { - is_caret_show_ = !is_caret_show_; - InvalidateDraw(); - }); - }); - - lose_focus_event.direct.AddHandler([this](events::FocusChangeEventArgs& args) - { - assert(caret_timer_.has_value()); - caret_timer_->Cancel(); - caret_timer_ = std::nullopt; - is_caret_show_ = false; - }); - - key_down_event.bubble.AddHandler([this](events::KeyEventArgs& args) - { - if (args.GetVirtualCode() == VK_LEFT && caret_position_ > 0) - { - if (IsKeyDown(VK_SHIFT)) - { - if (GetCaretSelectionSide()) - ShiftLeftSelectionRange(-1); - else - ShiftRightSelectionRange(-1); - } - else - { - const auto selection = GetSelectedRange(); - if (selection.has_value()) - { - ClearSelection(); - caret_position_ = selection.value().position; - } - else - caret_position_--; - } - InvalidateDraw(); - } - - if (args.GetVirtualCode() == VK_RIGHT && caret_position_ < GetText().size()) - { - if (IsKeyDown(VK_SHIFT)) - { - if (GetCaretSelectionSide()) - ShiftLeftSelectionRange(1); - else - ShiftRightSelectionRange(1); - } - else - { - const auto selection = GetSelectedRange(); - if (selection.has_value()) - { - ClearSelection(); - caret_position_ = selection.value().position + selection.value().count; - } - else - caret_position_++; - } - } - }); - - char_event.bubble.AddHandler([this](events::CharEventArgs& args) - { - if (args.GetChar() == L'\b') - { - if (GetSelectedRange().has_value()) - { - const auto selection_range = GetSelectedRange().value(); - auto text = GetText(); - text.erase(text.cbegin() + selection_range.position, text.cbegin() + selection_range.position + selection_range.count); - SetText(text); - caret_position_ = selection_range.position; - ClearSelection(); - } - else - { - if (caret_position_ > 0) - { - auto text = GetText(); - if (!text.empty()) - { - const auto position = --caret_position_; - text.erase(text.cbegin() + position); - SetText(text); - } - } - } - return; - } - - if (std::iswprint(args.GetChar())) - { - if (GetSelectedRange().has_value()) - { - const auto selection_range = GetSelectedRange().value(); - auto text = GetText(); - text.erase(selection_range.position, selection_range.count); - text.insert(text.cbegin() + selection_range.position, args.GetChar()); - SetText(text); - caret_position_ = selection_range.position + 1; - ClearSelection(); - } - else - { - ClearSelection(); - const auto position = caret_position_++; - auto text = GetText(); - text.insert(text.cbegin() + position, { args.GetChar() }); - SetText(text); - } - } - }); - } - - TextBox::~TextBox() = default; - - StringView TextBox::GetControlType() const - { - return control_type; - } - - void TextBox::RequestChangeCaretPosition(const unsigned position) - { - caret_position_ = position; - InvalidateDraw(); - } - - bool TextBox::GetCaretSelectionSide() const - { - const auto selection = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); - if (selection.first == caret_position_) - return true; - if (selection.second == caret_position_) - return false; - assert(false); - return true; - } - - void TextBox::ShiftLeftSelectionRange(const int count) - { - const auto selection_range_side = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); - int new_left = selection_range_side.first + count; - new_left = new_left < 0 ? 0 : new_left; // at least 0 - caret_position_ = new_left; - SetSelectedRange(TextRange::FromTwoSides(static_cast<unsigned>(new_left), selection_range_side.second)); - } - - void TextBox::ShiftRightSelectionRange(const int count) - { - const auto selection_range_side = TextRange::ToTwoSides(GetSelectedRange(), caret_position_); - int new_right = selection_range_side.second + count; - new_right = new_right < 0 ? 0 : new_right; // at least 0 - caret_position_ = new_right; - SetSelectedRange(TextRange::FromTwoSides(selection_range_side.first, static_cast<unsigned>(new_right))); - } -} diff --git a/src/ui/controls/text_box.hpp b/src/ui/controls/text_box.hpp deleted file mode 100644 index e5cd7545..00000000 --- a/src/ui/controls/text_box.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "text_control.hpp" -#include "timer.hpp" - -namespace cru::ui::controls -{ - class TextBox : public TextControl - { - public: - static constexpr auto control_type = L"TextBox"; - - static TextBox* Create() - { - return new TextBox(); - } - - protected: - TextBox(); - public: - TextBox(const TextBox& other) = delete; - TextBox(TextBox&& other) = delete; - TextBox& operator=(const TextBox& other) = delete; - TextBox& operator=(TextBox&& other) = delete; - ~TextBox() override; - - StringView GetControlType() const override final; - - protected: - void RequestChangeCaretPosition(unsigned position) override final; - - private: - // return true if left - bool GetCaretSelectionSide() const; - void ShiftLeftSelectionRange(int count); - void ShiftRightSelectionRange(int count); - - private: - unsigned caret_position_ = 0; - std::optional<TimerTask> caret_timer_{}; - Microsoft::WRL::ComPtr<ID2D1Brush> caret_brush_; - bool is_caret_show_ = false; - }; -} diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp deleted file mode 100644 index fcfcb90c..00000000 --- a/src/ui/controls/text_control.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "text_control.hpp" - -#include <cassert> - -#include "ui/window.hpp" -#include "graph/graph.hpp" -#include "exception.hpp" -#include "ui/ui_manager.hpp" - -namespace cru::ui::controls -{ - namespace - { - unsigned TextLayoutHitTest(IDWriteTextLayout* text_layout, const Point& point) - { - BOOL is_trailing, is_inside; - DWRITE_HIT_TEST_METRICS metrics{}; - text_layout->HitTestPoint(point.x, point.y, &is_trailing, &is_inside, &metrics); - return is_trailing == 0 ? metrics.textPosition : metrics.textPosition + 1; - } - - - } - - TextControl::TextControl(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format, - const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) - { - text_format_ = init_text_format; - - RecreateTextLayout(); - - brush_ = init_brush; - - selection_brush_ = UiManager::GetInstance()->GetPredefineResources()->text_control_selection_brush; - - SetClipContent(true); - - draw_content_event.AddHandler([this](events::DrawEventArgs& args) - { - }); - - mouse_down_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (is_selectable_ && args.GetMouseButton() == MouseButton::Left && GetRect(RectRange::Padding).IsPointInside(args.GetPoint(this, RectRange::Margin))) - { - selected_range_ = std::nullopt; - const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this)); - RequestChangeCaretPosition(hit_test_result); - mouse_down_position_ = hit_test_result; - is_selecting_ = true; - GetWindow()->CaptureMouseFor(this); - InvalidateDraw(); - } - }); - - mouse_move_event.bubble.AddHandler([this](events::MouseEventArgs& args) - { - if (is_selecting_) - { - const auto hit_test_result = TextLayoutHitTest(text_layout_.Get(), args.GetPoint(this)); - RequestChangeCaretPosition(hit_test_result); - selected_range_ = TextRange::FromTwoSides(hit_test_result, mouse_down_position_); - InvalidateDraw(); - } - UpdateCursor(args.GetPoint(this, RectRange::Margin)); - }); - - - mouse_up_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left) - { - if (is_selecting_) - { - is_selecting_ = false; - GetWindow()->ReleaseCurrentMouseCapture(); - } - } - }); - - lose_focus_event.direct.AddHandler([this](events::FocusChangeEventArgs& args) - { - if (is_selecting_) - { - is_selecting_ = false; - GetWindow()->ReleaseCurrentMouseCapture(); - } - if (!args.IsWindow()) // If the focus lose is triggered window-wide, then save the selection state. Otherwise, clear selection. - { - selected_range_ = std::nullopt; - InvalidateDraw(); - } - }); - } - - - void TextControl::SetText(const String& text) - { - if (text_ != text) - { - const auto old_text = text_; - text_ = text; - OnTextChangedCore(old_text, text); - } - } - - void TextControl::SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush) - { - brush_ = brush; - InvalidateDraw(); - } - - void TextControl::SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format) - { - text_format_ = text_format; - RecreateTextLayout(); - InvalidateDraw(); - } - - void TextControl::SetSelectable(const bool is_selectable) - { - if (is_selectable_ != is_selectable) - { - if (!is_selectable) - { - if (is_selecting_) - { - is_selecting_ = false; - GetWindow()->ReleaseCurrentMouseCapture(); - } - selected_range_ = std::nullopt; - InvalidateDraw(); - } - is_selectable_ = is_selectable; - UpdateCursor(std::nullopt); - } - } - - void TextControl::SetSelectedRange(std::optional<TextRange> text_range) - { - if (is_selectable_) - { - selected_range_ = text_range; - InvalidateDraw(); - } - } - - - - void TextControl::RequestChangeCaretPosition(unsigned position) - { - - } - - void TextControl::OnRectChange(const Rect& old_rect, const Rect& new_rect) - { - const auto content = GetRect(RectRange::Content); - ThrowIfFailed(text_layout_->SetMaxWidth(content.width)); - ThrowIfFailed(text_layout_->SetMaxHeight(content.height)); - } - - void TextControl::OnTextChangedCore(const String& old_text, const String& new_text) - { - RecreateTextLayout(); - InvalidateLayout(); - InvalidateDraw(); - } - - void TextControl::UpdateCursor(const std::optional<Point>& point) - { - if (!is_selectable_) - { - SetCursor(nullptr); - return; - } - - const auto window = GetWindow(); - if (window == nullptr) - { - SetCursor(nullptr); - return; - } - - if (is_selecting_) - { - SetCursor(cursors::i_beam); - return; - } - - const auto p = point.value_or(WindowToControl(window->GetMousePosition())); - if (GetRect(RectRange::Padding).IsPointInside(p)) - SetCursor(cursors::i_beam); - else - SetCursor(nullptr); - } -} diff --git a/src/ui/controls/text_control.hpp b/src/ui/controls/text_control.hpp deleted file mode 100644 index 83d4753f..00000000 --- a/src/ui/controls/text_control.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - class TextControl : public NoChildControl - { - protected: - TextControl( - const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format, - const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush - ); - public: - TextControl(const TextControl& other) = delete; - TextControl(TextControl&& other) = delete; - TextControl& operator=(const TextControl& other) = delete; - TextControl& operator=(TextControl&& other) = delete; - ~TextControl() override = default; - - String GetText() const - { - return text_; - } - - void SetText(const String& text); - - Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const - { - return brush_; - } - - void SetBrush(const Microsoft::WRL::ComPtr<ID2D1Brush>& brush); - - Microsoft::WRL::ComPtr<IDWriteTextFormat> GetTextFormat() const - { - return text_format_; - } - - void SetTextFormat(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& text_format); - - bool IsSelectable() const - { - return is_selectable_; - } - - std::optional<TextRange> GetSelectedRange() const - { - return selected_range_; - } - - void SetSelectedRange(std::optional<TextRange> text_range); - - void ClearSelection() - { - SetSelectedRange(std::nullopt); - } - - protected: - void SetSelectable(bool is_selectable); - - - virtual void RequestChangeCaretPosition(unsigned position); - - void OnRectChange(const Rect& old_rect, const Rect& new_rect) override; - - private: - void OnTextChangedCore(const String& old_text, const String& new_text); - - void RecreateTextLayout(); - - // param point is the mouse point relative to this control. - void UpdateCursor(const std::optional<Point>& point); - - private: - String text_; - - Microsoft::WRL::ComPtr<ID2D1Brush> brush_; - Microsoft::WRL::ComPtr<ID2D1Brush> selection_brush_; - Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format_; - Microsoft::WRL::ComPtr<IDWriteTextLayout> text_layout_; - - bool is_selectable_ = false; - std::optional<TextRange> selected_range_ = std::nullopt; - - bool is_selecting_ = false; - unsigned mouse_down_position_ = 0; - }; -} diff --git a/src/ui/controls/toggle_button.cpp b/src/ui/controls/toggle_button.cpp deleted file mode 100644 index db72d7bb..00000000 --- a/src/ui/controls/toggle_button.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "toggle_button.hpp" - -#include "graph/graph.hpp" -#include "ui/animations/animation.hpp" -#include "ui/ui_manager.hpp" -#include "ui/d2d_util.hpp" - -namespace cru::ui::controls -{ - using animations::AnimationBuilder; - - // ui length parameters of toggle button. - constexpr float half_height = 15; - constexpr float half_width = half_height * 2; - constexpr float stroke_width = 3; - constexpr float inner_circle_radius = half_height - stroke_width; - constexpr float inner_circle_x = half_width - half_height; - - ToggleButton::ToggleButton() : current_circle_position_(-inner_circle_x) - { - graph::GraphManager::GetInstance()->GetD2D1Factory()->CreateRoundedRectangleGeometry(D2D1::RoundedRect(D2D1::RectF(-half_width, -half_height, half_width, half_height), half_height, half_height), &frame_path_); - - on_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_on_brush; - off_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_off_brush; - - draw_content_event.AddHandler([this](events::DrawEventArgs& args) - { - const auto device_context = args.GetDeviceContext(); - const auto size = GetSize(); - graph::WithTransform(device_context, D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2), [this](ID2D1DeviceContext* device_context) - { - if (state_) - { - device_context->DrawGeometry(frame_path_.Get(), on_brush_.Get(), stroke_width); - device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), on_brush_.Get()); - } - else - { - device_context->DrawGeometry(frame_path_.Get(), off_brush_.Get(), stroke_width); - device_context->FillEllipse(D2D1::Ellipse(D2D1::Point2F(current_circle_position_, 0), inner_circle_radius, inner_circle_radius), off_brush_.Get()); - } - }); - }); - - mouse_click_event.bubble.AddHandler([this](events::MouseButtonEventArgs& args) - { - if (args.GetMouseButton() == MouseButton::Left) - Toggle(); - }); - } - - - StringView ToggleButton::GetControlType() const - { - return control_type; - } - - bool ToggleButton::IsPointInside(const Point& point) - { - const auto size = GetSize(); - const auto transform = D2D1::Matrix3x2F::Translation(size.width / 2, size.height / 2); - BOOL contains; - frame_path_->FillContainsPoint(Convert(point), transform, &contains); - if (!contains) - frame_path_->StrokeContainsPoint(Convert(point), stroke_width, nullptr, transform, &contains); - return contains != 0; - } - - void ToggleButton::SetState(const bool state) - { - if (state != state_) - { - state_ = state; - float destination_x; - - if (state) - destination_x = inner_circle_x; - else - destination_x = -inner_circle_x; - - const auto previous_position = current_circle_position_; - const auto delta = destination_x - current_circle_position_; - - constexpr auto total_time = FloatSecond(0.2); - - const auto time = total_time * (std::abs(delta) / (inner_circle_x * 2)); - - // ReSharper disable once CppExpressionWithoutSideEffects - AnimationBuilder(Format(L"ToggleButton {}", reinterpret_cast<size_t>(this)), time) - .AddStepHandler([=](auto, const double percentage) - { - current_circle_position_ = static_cast<float>(previous_position + delta * percentage); - InvalidateDraw(); - }) - .Start(); - - events::ToggleEventArgs args(this, this, state); - toggle_event.Raise(args); - InvalidateDraw(); - } - } - - void ToggleButton::Toggle() - { - SetState(!GetState()); - } - - Size ToggleButton::OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo&) - { - const Size result_size( - half_width * 2 + stroke_width, - half_height * 2 + stroke_width - ); - - return result_size; - } -} diff --git a/src/ui/controls/toggle_button.hpp b/src/ui/controls/toggle_button.hpp deleted file mode 100644 index dee655d4..00000000 --- a/src/ui/controls/toggle_button.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -// ReSharper disable once CppUnusedIncludeDirective -#include "pre.hpp" - -#include "ui/control.hpp" - -namespace cru::ui::controls -{ - class ToggleButton : public NoChildControl - { - public: - static constexpr auto control_type = L"ToggleButton"; - - static ToggleButton* Create() - { - return new ToggleButton(); - } - - protected: - ToggleButton(); - - public: - ToggleButton(const ToggleButton& other) = delete; - ToggleButton(ToggleButton&& other) = delete; - ToggleButton& operator=(const ToggleButton& other) = delete; - ToggleButton& operator=(ToggleButton&& other) = delete; - ~ToggleButton() override = default; - - StringView GetControlType() const override final; - - bool IsPointInside(const Point& point) override; - - bool GetState() const - { - return state_; - } - - void SetState(bool state); - - void Toggle(); - - Event<events::ToggleEventArgs> toggle_event; - - protected: - Size OnMeasureContent(const Size& available_size, const AdditionalMeasureInfo&) override; - - private: - bool state_ = false; - - float current_circle_position_; - - Microsoft::WRL::ComPtr<ID2D1RoundedRectangleGeometry> frame_path_; - Microsoft::WRL::ComPtr<ID2D1Brush> on_brush_; - Microsoft::WRL::ComPtr<ID2D1Brush> off_brush_; - }; -} diff --git a/src/ui/render/text_render_object.hpp b/src/ui/render/text_render_object.hpp index b868796d..d1d91034 100644 --- a/src/ui/render/text_render_object.hpp +++ b/src/ui/render/text_render_object.hpp @@ -18,7 +18,10 @@ class TextRenderObject : public RenderObject { ~TextRenderObject() override = default; String GetText() const { return text_; } - void SetText(String new_text) { text_ = std::move(new_text); } + void SetText(String new_text) { + text_ = std::move(new_text); + RecreateTextLayout(); + } Microsoft::WRL::ComPtr<ID2D1Brush> GetBrush() const { return brush_; } void SetBrush(Microsoft::WRL::ComPtr<ID2D1Brush> new_brush) { @@ -31,6 +34,7 @@ class TextRenderObject : public RenderObject { void SetTextFormat( Microsoft::WRL::ComPtr<IDWriteTextFormat> new_text_format) { text_format_ = std::move(new_text_format); + RecreateTextLayout(); } std::optional<TextRange> GetSelectionRange() const { diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp index 689a04a2..bcda4133 100644 --- a/src/ui/ui_manager.cpp +++ b/src/ui/ui_manager.cpp @@ -1,107 +1,66 @@ #include "ui_manager.hpp" #include "application.hpp" -#include "border_property.hpp" -#include "graph/graph.hpp" #include "exception.hpp" +#include "graph/graph.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; +} -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; - } - - Microsoft::WRL::ComPtr<ID2D1Brush> CreateSolidBrush(graph::GraphManager* graph_manager, const D2D1_COLOR_F& color) - { - const auto device_context = graph_manager->GetD2D1DeviceContext(); - Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solid_color_brush; - device_context->CreateSolidColorBrush(color, &solid_color_brush); - return solid_color_brush; - } - - Microsoft::WRL::ComPtr<IDWriteTextFormat> CreateDefaultTextFormat(graph::GraphManager* graph_manager) - { - const auto dwrite_factory = graph_manager->GetDWriteFactory(); - - Microsoft::WRL::ComPtr<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; - } - } - - - //!!! never use default constructor of border at here, because it will recursively call this method! - PredefineResources::PredefineResources(graph::GraphManager* graph_manager) : - border_property_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, - - button_normal_border {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::RoyalBlue)), 2, 6, 6}, - button_press_border {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Blue)), 2, 6, 6}, - - text_control_selection_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::LightSkyBlue))}, - - text_box_border {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, - text_box_text_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, - text_box_text_format {CreateDefaultTextFormat(graph_manager)}, - text_box_caret_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, - - text_block_text_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, - text_block_text_format {CreateDefaultTextFormat(graph_manager)}, +Microsoft::WRL::ComPtr<ID2D1Brush> CreateSolidBrush( + graph::GraphManager* graph_manager, const D2D1_COLOR_F& color) { + const auto device_context = graph_manager->GetD2D1DeviceContext(); + Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solid_color_brush; + device_context->CreateSolidColorBrush(color, &solid_color_brush); + return solid_color_brush; +} - toggle_button_on_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DeepSkyBlue))}, - toggle_button_off_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::LightGray))}, +Microsoft::WRL::ComPtr<IDWriteTextFormat> CreateDefaultTextFormat( + graph::GraphManager* graph_manager) { + const auto dwrite_factory = graph_manager->GetDWriteFactory(); - list_item_normal_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::White, 0))}, - list_item_normal_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::White, 0))}, - list_item_hover_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue))}, - list_item_hover_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.3f))}, - list_item_select_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::MediumBlue))}, - list_item_select_fill_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.3f))}, + Microsoft::WRL::ComPtr<IDWriteTextFormat> text_format; - scroll_bar_background_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Gainsboro, 0.3f))}, - scroll_bar_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DimGray))}, - scroll_bar_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DimGray))} + 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)); -#ifdef CRU_DEBUG_LAYOUT - , - debug_layout_out_border_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Crimson))}, - debug_layout_margin_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::LightCoral, 0.25f))}, - debug_layout_padding_brush {CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.25f))} -#endif - { - - } + ThrowIfFailed(text_format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER)); + ThrowIfFailed( + text_format->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER)); - UiManager* UiManager::GetInstance() - { - return Application::GetInstance()->ResolveSingleton<UiManager>([](auto) - { - return new UiManager{}; - }); - } + return text_format; +} +} // namespace + +PredefineResources::PredefineResources(graph::GraphManager* graph_manager) + : text_block_selection_brush{CreateSolidBrush( + graph_manager, D2D1::ColorF(D2D1::ColorF::LightSkyBlue))}, + text_block_text_brush{ + CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Black))}, + text_block_text_format{CreateDefaultTextFormat(graph_manager)}, + debug_layout_out_border_brush{ + CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::Crimson))}, + debug_layout_margin_brush{CreateSolidBrush( + graph_manager, D2D1::ColorF(D2D1::ColorF::LightCoral, 0.25f))}, + debug_layout_padding_brush{CreateSolidBrush( + graph_manager, D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.25f))} {} + +UiManager* UiManager::GetInstance() { + return Application::GetInstance()->ResolveSingleton<UiManager>( + [](auto) { return new UiManager{}; }); +} - UiManager::UiManager() - : predefine_resources_(graph::GraphManager::GetInstance()) - { - GetSystemCaretInfo(&caret_info_); - } +UiManager::UiManager() + : predefine_resources_(graph::GraphManager::GetInstance()) { + GetSystemCaretInfo(&caret_info_); } +} // namespace cru::ui diff --git a/src/ui/ui_manager.hpp b/src/ui/ui_manager.hpp index f0e1e8ce..3fd2adc9 100644 --- a/src/ui/ui_manager.hpp +++ b/src/ui/ui_manager.hpp @@ -1,108 +1,63 @@ #pragma once - -// ReSharper disable once CppUnusedIncludeDirective #include "pre.hpp" #include "system_headers.hpp" #include "base.hpp" -#include "border_property.hpp" -namespace cru::graph -{ - class GraphManager; +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: - explicit PredefineResources(graph::GraphManager* graph_manager); - PredefineResources(const PredefineResources& other) = delete; - PredefineResources(PredefineResources&& other) = delete; - PredefineResources& operator=(const PredefineResources& other) = delete; - PredefineResources& operator=(PredefineResources&& other) = delete; - ~PredefineResources() override = default; - - //region BorderProperty - Microsoft::WRL::ComPtr<ID2D1Brush> border_property_brush; - - //region Button - BorderProperty button_normal_border; - BorderProperty button_press_border; - - //region TextControl - Microsoft::WRL::ComPtr<ID2D1Brush> text_control_selection_brush; - - //region TextBox - BorderProperty text_box_border; - Microsoft::WRL::ComPtr<ID2D1Brush> text_box_text_brush; - Microsoft::WRL::ComPtr<IDWriteTextFormat> text_box_text_format; - Microsoft::WRL::ComPtr<ID2D1Brush> text_box_caret_brush; - - //region TextBlock - Microsoft::WRL::ComPtr<ID2D1Brush> text_block_text_brush; - Microsoft::WRL::ComPtr<IDWriteTextFormat> text_block_text_format; - - //region ToggleButton - Microsoft::WRL::ComPtr<ID2D1Brush> toggle_button_on_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> toggle_button_off_brush; - - //region ListItem - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_normal_border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_normal_fill_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_hover_border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_hover_fill_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_select_border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> list_item_select_fill_brush; - - //region ScrollControl - Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_background_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> scroll_bar_brush; - -#ifdef CRU_DEBUG_LAYOUT - //region debug - Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_out_border_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_margin_brush; - Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_padding_brush; -#endif - }; - - 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 { +struct CaretInfo { + std::chrono::milliseconds caret_blink_duration; + float half_caret_width; +}; + +class PredefineResources : public Object { + public: + explicit PredefineResources(graph::GraphManager* graph_manager); + PredefineResources(const PredefineResources& other) = delete; + PredefineResources(PredefineResources&& other) = delete; + PredefineResources& operator=(const PredefineResources& other) = delete; + PredefineResources& operator=(PredefineResources&& other) = delete; + ~PredefineResources() override = default; + + // region TextBlock + Microsoft::WRL::ComPtr<ID2D1Brush> text_block_selection_brush; + Microsoft::WRL::ComPtr<ID2D1Brush> text_block_text_brush; + Microsoft::WRL::ComPtr<IDWriteTextFormat> text_block_text_format; + + // region debug + Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_out_border_brush; + Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_margin_brush; + Microsoft::WRL::ComPtr<ID2D1Brush> debug_layout_padding_brush; +}; + +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 |