aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-10 15:53:32 +0800
committercrupest <crupest@outlook.com>2018-11-10 15:53:32 +0800
commit8d5a08e8d054e9504ca31e0bfbfff7a1018c23c0 (patch)
treefdd8ac836b266044de380fea26e8f5fc80a5d9d9 /src
parentac4b0f8d438e7a7c2ecd836af8332b5da1e035c9 (diff)
downloadcru-8d5a08e8d054e9504ca31e0bfbfff7a1018c23c0.tar.gz
cru-8d5a08e8d054e9504ca31e0bfbfff7a1018c23c0.tar.bz2
cru-8d5a08e8d054e9504ca31e0bfbfff7a1018c23c0.zip
Refactor predefine resources. Add check for dead recursion in singletons in debug mode.
Diffstat (limited to 'src')
-rw-r--r--src/application.cpp17
-rw-r--r--src/application.hpp47
-rw-r--r--src/ui/border_property.cpp11
-rw-r--r--src/ui/border_property.hpp3
-rw-r--r--src/ui/control.cpp8
-rw-r--r--src/ui/controls/button.cpp6
-rw-r--r--src/ui/controls/text_block.cpp7
-rw-r--r--src/ui/controls/text_box.cpp14
-rw-r--r--src/ui/controls/text_control.cpp4
-rw-r--r--src/ui/controls/toggle_button.cpp6
-rw-r--r--src/ui/predefine.cpp73
-rw-r--r--src/ui/predefine.hpp59
-rw-r--r--src/ui/ui_manager.cpp96
-rw-r--r--src/ui/ui_manager.hpp92
14 files changed, 236 insertions, 207 deletions
diff --git a/src/application.cpp b/src/application.cpp
index 672ee347..9a98854c 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -4,7 +4,7 @@
#include "timer.hpp"
#include "ui/window.hpp"
#include "ui/cursor.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru {
constexpr auto god_window_class_name = L"GodWindowClass";
@@ -89,17 +89,6 @@ namespace cru {
namespace
{
- CaretInfo 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;
- return caret_info;
- }
-
void LoadSystemCursor(HINSTANCE h_instance)
{
ui::cursors::arrow = std::make_shared<ui::Cursor>(::LoadCursorW(nullptr, IDC_ARROW), false);
@@ -118,10 +107,6 @@ namespace cru {
god_window_ = std::make_unique<GodWindow>(this);
- ui::predefine::InitThemes(&predefine_resource_map_);
-
- caret_info_ = GetSystemCaretInfo();
-
LoadSystemCursor(h_instance);
}
diff --git a/src/application.hpp b/src/application.hpp
index 0c345328..90a43848 100644
--- a/src/application.hpp
+++ b/src/application.hpp
@@ -10,6 +10,10 @@
#include "base.hpp"
#include "any_map.h"
+#ifdef CRU_DEBUG
+#include <unordered_set>
+#endif
+
namespace cru
{
class Application;
@@ -17,26 +21,8 @@ namespace cru
namespace ui
{
class WindowClass;
- class WindowManager;
-
- namespace animations::details
- {
- class AnimationManager;
- }
- }
-
- namespace graph
- {
- class GraphManager;
}
- class TimerManager;
-
- struct CaretInfo
- {
- std::chrono::milliseconds caret_blink_duration;
- float half_caret_width;
- };
class GodWindow : public Object
{
@@ -101,23 +87,19 @@ namespace cru
if (find_result != singleton_map_.cend())
return static_cast<T*>(find_result->second);
+#ifdef CRU_DEBUG
+ const auto type_find_result = singleton_type_set_.find(index);
+ if (type_find_result != singleton_type_set_.cend())
+ throw std::logic_error("The singleton of that type is being constructed. This may cause a dead recursion.");
+ singleton_type_set_.insert(index);
+#endif
+
auto singleton = creator(this);
singleton_map_.emplace(index, static_cast<Object*>(singleton));
singleton_list_.push_back(singleton);
return singleton;
}
-
- CaretInfo GetCaretInfo() const
- {
- return caret_info_;
- }
-
- const AnyMap* GetPredefineResourceMap() const
- {
- return &predefine_resource_map_;
- }
-
private:
HINSTANCE h_instance_;
@@ -125,10 +107,9 @@ namespace cru
std::unordered_map<std::type_index, Object*> singleton_map_;
std::list<Object*> singleton_list_; // used for reverse destroy.
-
- CaretInfo caret_info_;
-
- AnyMap predefine_resource_map_{};
+#ifdef CRU_DEBUG
+ std::unordered_set<std::type_index> singleton_type_set_; // used for dead recursion.
+#endif
};
diff --git a/src/ui/border_property.cpp b/src/ui/border_property.cpp
index bd06a96a..b79bb482 100644
--- a/src/ui/border_property.cpp
+++ b/src/ui/border_property.cpp
@@ -1,10 +1,10 @@
#include "border_property.hpp"
-#include "predefine.hpp"
+#include "ui_manager.hpp"
namespace cru::ui
{
- BorderProperty::BorderProperty(): BorderProperty(predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_border_property_brush))
+ BorderProperty::BorderProperty(): BorderProperty(UiManager::GetInstance()->GetPredefineResources()->border_property_brush)
{
}
@@ -13,4 +13,11 @@ namespace cru::ui
{
}
+
+ BorderProperty::BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush, const float width, const float radius_x,
+ const float radius_y, Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style) :
+ brush_(std::move(brush)), stroke_width_(width), radius_x_(radius_x), radius_y_(radius_y), stroke_style_(std::move(stroke_style))
+ {
+
+ }
}
diff --git a/src/ui/border_property.hpp b/src/ui/border_property.hpp
index a280fe44..7766f5a3 100644
--- a/src/ui/border_property.hpp
+++ b/src/ui/border_property.hpp
@@ -12,6 +12,7 @@ namespace cru::ui
public:
BorderProperty();
explicit BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush);
+ BorderProperty(Microsoft::WRL::ComPtr<ID2D1Brush> brush, float width, float radius_x, float radius_y, Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style = nullptr);
BorderProperty(const BorderProperty& other) = default;
BorderProperty(BorderProperty&& other) = default;
BorderProperty& operator=(const BorderProperty& other) = default;
@@ -76,8 +77,8 @@ namespace cru::ui
private:
Microsoft::WRL::ComPtr<ID2D1Brush> brush_;
float stroke_width_ = 1.0f;
- Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style_ = nullptr;
float radius_x_ = 0.0f;
float radius_y_ = 0.0f;
+ Microsoft::WRL::ComPtr<ID2D1StrokeStyle> stroke_style_ = nullptr;
};
}
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 1ec2f704..63d322b3 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -9,7 +9,7 @@
#include "cru_debug.hpp"
#ifdef CRU_DEBUG_LAYOUT
-#include "predefine.hpp"
+#include "ui_manager.hpp"
#endif
namespace cru::ui
@@ -396,10 +396,10 @@ namespace cru::ui
if (GetWindow()->IsDebugLayout())
{
if (padding_geometry_ != nullptr)
- device_context->FillGeometry(padding_geometry_.Get(), predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_debug_layout_padding_brush).Get());
+ device_context->FillGeometry(padding_geometry_.Get(), UiManager::GetInstance()->GetPredefineResources()->debug_layout_padding_brush.Get());
if (margin_geometry_ != nullptr)
- device_context->FillGeometry(margin_geometry_.Get(), predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_debug_layout_margin_brush).Get());
- device_context->DrawRectangle(Convert(GetRect(RectRange::Margin)), predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_debug_layout_out_border_brush).Get());
+ device_context->FillGeometry(margin_geometry_.Get(), UiManager::GetInstance()->GetPredefineResources()->debug_layout_margin_brush.Get());
+ device_context->DrawRectangle(Convert(GetRect(RectRange::Margin)), UiManager::GetInstance()->GetPredefineResources()->debug_layout_out_border_brush.Get());
}
#endif
diff --git a/src/ui/controls/button.cpp b/src/ui/controls/button.cpp
index a90c218d..0bd6a70d 100644
--- a/src/ui/controls/button.cpp
+++ b/src/ui/controls/button.cpp
@@ -1,13 +1,13 @@
#include "button.hpp"
#include "graph/graph.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru::ui::controls
{
Button::Button() : Control(true),
- normal_border_{predefine::GetPredefineResource<BorderProperty>(predefine::key_button_normal_border)},
- pressed_border_{predefine::GetPredefineResource<BorderProperty>(predefine::key_button_press_border)}
+ normal_border_{UiManager::GetInstance()->GetPredefineResources()->button_normal_border},
+ pressed_border_{UiManager::GetInstance()->GetPredefineResources()->button_press_border}
{
SetBordered(true);
GetBorderProperty() = normal_border_;
diff --git a/src/ui/controls/text_block.cpp b/src/ui/controls/text_block.cpp
index 290ddd58..8276ce4e 100644
--- a/src/ui/controls/text_block.cpp
+++ b/src/ui/controls/text_block.cpp
@@ -1,13 +1,12 @@
#include "text_block.hpp"
-#include "ui/window.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru::ui::controls
{
TextBlock::TextBlock() : TextControl(
- predefine::GetPredefineResourceComPtr<IDWriteTextFormat>(predefine::key_text_block_text_format),
- predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_text_block_text_brush)
+ UiManager::GetInstance()->GetPredefineResources()->text_block_text_format,
+ UiManager::GetInstance()->GetPredefineResources()->text_block_text_brush
)
{
diff --git a/src/ui/controls/text_box.cpp b/src/ui/controls/text_box.cpp
index 0ed1248c..fd357fdb 100644
--- a/src/ui/controls/text_box.cpp
+++ b/src/ui/controls/text_box.cpp
@@ -6,7 +6,7 @@
#include "graph/graph.hpp"
#include "exception.hpp"
#include "application.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru::ui::controls
{
@@ -16,15 +16,15 @@ namespace cru::ui::controls
}
TextBox::TextBox() : TextControl(
- predefine::GetPredefineResourceComPtr<IDWriteTextFormat>(predefine::key_text_box_text_format),
- predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_text_box_text_brush)
+ UiManager::GetInstance()->GetPredefineResources()->text_box_text_format,
+ UiManager::GetInstance()->GetPredefineResources()->text_box_text_brush
)
{
SetSelectable(true);
- caret_brush_ = predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_text_box_caret_brush);
+ caret_brush_ = UiManager::GetInstance()->GetPredefineResources()->text_box_caret_brush;
- GetBorderProperty() = predefine::GetPredefineResource<BorderProperty>(predefine::key_text_box_border);
+ GetBorderProperty() = UiManager::GetInstance()->GetPredefineResources()->text_box_border;
SetBordered(true);
}
@@ -40,7 +40,7 @@ namespace cru::ui::controls
TextControl::OnDrawContent(device_context);
if (is_caret_show_)
{
- const auto caret_half_width = Application::GetInstance()->GetCaretInfo().half_caret_width;
+ 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));
@@ -53,7 +53,7 @@ namespace cru::ui::controls
TextControl::OnGetFocusCore(args);
assert(!caret_timer_.has_value());
is_caret_show_ = true;
- caret_timer_ = SetInterval(Application::GetInstance()->GetCaretInfo().caret_blink_duration, [this]
+ caret_timer_ = SetInterval(UiManager::GetInstance()->GetCaretInfo().caret_blink_duration, [this]
{
is_caret_show_ = !is_caret_show_;
Repaint();
diff --git a/src/ui/controls/text_control.cpp b/src/ui/controls/text_control.cpp
index 42214583..974001b3 100644
--- a/src/ui/controls/text_control.cpp
+++ b/src/ui/controls/text_control.cpp
@@ -5,7 +5,7 @@
#include "ui/window.hpp"
#include "graph/graph.hpp"
#include "exception.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru::ui::controls
{
@@ -23,7 +23,7 @@ namespace cru::ui::controls
brush_ = init_brush;
- selection_brush_ = predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_text_control_selection_brush);
+ selection_brush_ = UiManager::GetInstance()->GetPredefineResources()->text_control_selection_brush;
}
diff --git a/src/ui/controls/toggle_button.cpp b/src/ui/controls/toggle_button.cpp
index a901f650..b16eca23 100644
--- a/src/ui/controls/toggle_button.cpp
+++ b/src/ui/controls/toggle_button.cpp
@@ -2,7 +2,7 @@
#include "graph/graph.hpp"
#include "ui/animations/animation.hpp"
-#include "ui/predefine.hpp"
+#include "ui/ui_manager.hpp"
namespace cru::ui::controls
{
@@ -19,8 +19,8 @@ namespace cru::ui::controls
{
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_ = predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_toggle_button_on_brush);
- off_brush_ = predefine::GetPredefineResourceComPtr<ID2D1Brush>(predefine::key_toggle_button_off_brush);
+ on_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_on_brush;
+ off_brush_ = UiManager::GetInstance()->GetPredefineResources()->toggle_button_off_brush;
}
inline D2D1_POINT_2F ConvertPoint(const Point& point)
diff --git a/src/ui/predefine.cpp b/src/ui/predefine.cpp
deleted file mode 100644
index 259b3a2a..00000000
--- a/src/ui/predefine.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "predefine.hpp"
-
-#include "border_property.hpp"
-#include "graph/graph.hpp"
-#include "exception.hpp"
-
-namespace cru::ui::predefine
-{
- Microsoft::WRL::ComPtr<ID2D1Brush> CreateSolidBrush(const D2D1_COLOR_F& color)
- {
- const auto device_context = graph::GraphManager::GetInstance()->GetD2D1DeviceContext();
- Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> solid_color_brush;
- device_context->CreateSolidColorBrush(color, &solid_color_brush);
- return solid_color_brush;
- }
-
- void InitThemes(AnyMap* resource_map)
- {
- resource_map->SetValue(key_border_property_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)));
-
- BorderProperty button_normal_border{CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::RoyalBlue))};
- button_normal_border.SetStrokeWidth(2);
- button_normal_border.SetRadiusX(6);
- button_normal_border.SetRadiusY(6);
- resource_map->SetValue(key_button_normal_border, std::move(button_normal_border));
-
- BorderProperty button_press_border{CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Blue))};
- button_press_border.SetStrokeWidth(2);
- button_press_border.SetRadiusX(6);
- button_press_border.SetRadiusY(6);
- resource_map->SetValue(key_button_press_border, std::move(button_press_border));
-
-
- const auto dwrite_factory = graph::GraphManager::GetInstance()->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));
-
- resource_map->SetValue(key_text_block_text_format, text_format);
- resource_map->SetValue(key_text_box_text_format, text_format);
-
- auto text_brush = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black));
- resource_map->SetValue(key_text_block_text_brush, text_brush);
- resource_map->SetValue(key_text_box_text_brush, text_brush);
-
- auto text_selection_brush = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightSkyBlue));
- resource_map->SetValue(key_text_control_selection_brush, text_selection_brush);
-
- BorderProperty text_box_border;
- resource_map->SetValue(key_text_box_border, text_box_border);
-
- resource_map->SetValue(key_text_box_caret_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Black)));
-
- resource_map->SetValue(key_toggle_button_on_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::DeepSkyBlue)));
- resource_map->SetValue(key_toggle_button_off_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightGray)));
-
-#ifdef CRU_DEBUG_LAYOUT
- resource_map->SetValue(key_debug_layout_out_border_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::Crimson)));
- resource_map->SetValue(key_debug_layout_margin_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightCoral, 0.25f)));
- resource_map->SetValue(key_debug_layout_padding_brush, CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::SkyBlue, 0.25f)));
-#endif
- }
-}
diff --git a/src/ui/predefine.hpp b/src/ui/predefine.hpp
deleted file mode 100644
index 03e98a98..00000000
--- a/src/ui/predefine.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include "system_headers.hpp"
-
-#include "any_map.h"
-#include "application.hpp"
-
-namespace cru::ui::predefine
-{
-#define CRU_DEFINE_KEY(name, key) \
- constexpr const wchar_t* key_##name = L#key;
-
- //region BorderProperty
- CRU_DEFINE_KEY(border_property_brush, BorderProperty_Brush)
-
- //region Button
- CRU_DEFINE_KEY(button_normal_border, Button_Normal_Border)
- CRU_DEFINE_KEY(button_press_border, Button_Press_Border)
-
- //region TextControl
- CRU_DEFINE_KEY(text_control_selection_brush, TextControl_SelectionBrush)
-
- //region TextBox
- CRU_DEFINE_KEY(text_box_border, TextBox_Border)
- CRU_DEFINE_KEY(text_box_text_brush, TextBox_TextBrush)
- CRU_DEFINE_KEY(text_box_text_format, TextBox_TextFormat)
- CRU_DEFINE_KEY(text_box_caret_brush, TextBox_CaretBrush)
-
- //region TextBlock
- CRU_DEFINE_KEY(text_block_text_brush, TextBlock_TextBrush)
- CRU_DEFINE_KEY(text_block_text_format, TextBlock_TextFormat)
-
- //region ToggleButton
- CRU_DEFINE_KEY(toggle_button_on_brush, ToggleButton_On_Brush)
- CRU_DEFINE_KEY(toggle_button_off_brush, ToggleButton_Off_Brush)
-
-#ifdef CRU_DEBUG_LAYOUT
- //region debug
- CRU_DEFINE_KEY(debug_layout_out_border_brush, Debug_Layout_Out_Border_Brush)
- CRU_DEFINE_KEY(debug_layout_margin_brush, Debug_Layout_Margin_Brush)
- CRU_DEFINE_KEY(debug_layout_padding_brush, Debug_Layout_Padding_Brush)
-#endif
-
-#undef CRU_DEFINE_KEY
-
- void InitThemes(AnyMap* resource_map);
-
- template<typename T>
- T GetPredefineResource(const String& key)
- {
- return Application::GetInstance()->GetPredefineResourceMap()->GetValue<T>(key);
- }
-
- template<typename T>
- Microsoft::WRL::ComPtr<T> GetPredefineResourceComPtr(const String& key)
- {
- return GetPredefineResource<Microsoft::WRL::ComPtr<T>>(key);
- }
-}
diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp
new file mode 100644
index 00000000..3918b2d5
--- /dev/null
+++ b/src/ui/ui_manager.cpp
@@ -0,0 +1,96 @@
+#include "ui_manager.hpp"
+
+#include "application.hpp"
+#include "border_property.hpp"
+#include "graph/graph.hpp"
+#include "exception.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;
+ }
+
+ 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)},
+
+ toggle_button_on_brush{CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::DeepSkyBlue))},
+ toggle_button_off_brush{CreateSolidBrush(graph_manager, D2D1::ColorF(D2D1::ColorF::LightGray))}
+
+#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
+ {
+
+ }
+
+ UiManager* UiManager::GetInstance()
+ {
+ return Application::GetInstance()->ResolveSingleton<UiManager>([](auto)
+ {
+ return new UiManager{};
+ });
+ }
+
+ UiManager::UiManager()
+ : predefine_resources_(graph::GraphManager::GetInstance())
+ {
+ GetSystemCaretInfo(&caret_info_);
+ }
+}
diff --git a/src/ui/ui_manager.hpp b/src/ui/ui_manager.hpp
new file mode 100644
index 00000000..753da907
--- /dev/null
+++ b/src/ui/ui_manager.hpp
@@ -0,0 +1,92 @@
+#pragma once
+
+#include "system_headers.hpp"
+
+#include "base.hpp"
+#include "border_property.hpp"
+
+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;
+
+#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_;
+ };
+}