diff options
-rw-r--r-- | CruUI/CruUI.vcxproj | 3 | ||||
-rw-r--r-- | CruUI/CruUI.vcxproj.filters | 9 | ||||
-rw-r--r-- | CruUI/graph/graph.cpp | 8 | ||||
-rw-r--r-- | CruUI/graph/graph.h | 11 | ||||
-rw-r--r-- | CruUI/main.cpp | 4 | ||||
-rw-r--r-- | CruUI/ui/control.cpp | 2 | ||||
-rw-r--r-- | CruUI/ui/control.h | 4 | ||||
-rw-r--r-- | CruUI/ui/controls/linear_layout.h | 9 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.cpp | 10 | ||||
-rw-r--r-- | CruUI/ui/controls/text_block.h | 2 | ||||
-rw-r--r-- | CruUI/ui/controls/toggle_button.cpp | 123 | ||||
-rw-r--r-- | CruUI/ui/controls/toggle_button.h | 59 | ||||
-rw-r--r-- | CruUI/ui/events/ui_event.h | 43 | ||||
-rw-r--r-- | CruUI/ui/layout_base.cpp | 77 | ||||
-rw-r--r-- | CruUI/ui/layout_base.h | 42 | ||||
-rw-r--r-- | CruUI/ui/ui_base.h | 1 | ||||
-rw-r--r-- | CruUI/ui/window.cpp | 66 | ||||
-rw-r--r-- | CruUI/ui/window.h | 37 |
18 files changed, 386 insertions, 124 deletions
diff --git a/CruUI/CruUI.vcxproj b/CruUI/CruUI.vcxproj index 7bf7eb98..4d2538d8 100644 --- a/CruUI/CruUI.vcxproj +++ b/CruUI/CruUI.vcxproj @@ -165,6 +165,7 @@ <ClInclude Include="global_macros.h" /> <ClInclude Include="ui\controls\linear_layout.h" /> <ClInclude Include="ui\controls\text_block.h" /> + <ClInclude Include="ui\controls\toggle_button.h" /> <ClInclude Include="ui\events\ui_event.h" /> <ClInclude Include="ui\layout_base.h" /> <ClInclude Include="ui\window.h" /> @@ -173,12 +174,14 @@ <ItemGroup> <ClCompile Include="application.cpp" /> <ClCompile Include="exception.cpp" /> + <ClCompile Include="ui\layout_base.cpp" /> <ClCompile Include="main.cpp" /> <ClCompile Include="graph\graph.cpp" /> <ClCompile Include="timer.cpp" /> <ClCompile Include="ui\control.cpp" /> <ClCompile Include="ui\controls\linear_layout.cpp" /> <ClCompile Include="ui\controls\text_block.cpp" /> + <ClCompile Include="ui\controls\toggle_button.cpp" /> <ClCompile Include="ui\events\ui_event.cpp" /> <ClCompile Include="ui\window.cpp" /> <ClCompile Include="ui\ui_base.cpp" /> diff --git a/CruUI/CruUI.vcxproj.filters b/CruUI/CruUI.vcxproj.filters index ec7a6de9..64cb4299 100644 --- a/CruUI/CruUI.vcxproj.filters +++ b/CruUI/CruUI.vcxproj.filters @@ -63,6 +63,9 @@ <ClInclude Include="debug_base.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="ui\controls\toggle_button.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="application.cpp"> @@ -98,5 +101,11 @@ <ClCompile Include="ui\controls\linear_layout.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="ui\controls\toggle_button.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="ui\layout_base.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project>
\ No newline at end of file diff --git a/CruUI/graph/graph.cpp b/CruUI/graph/graph.cpp index 00d5137d..94c7029e 100644 --- a/CruUI/graph/graph.cpp +++ b/CruUI/graph/graph.cpp @@ -213,5 +213,13 @@ namespace cru { d2d1_factory_->ReloadSystemMetrics() ); } + + ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color) + { + const auto device_context = graph::GraphManager::GetInstance()->GetD2D1DeviceContext(); + ComPtr<ID2D1SolidColorBrush> solid_color_brush; + device_context->CreateSolidColorBrush(color, &solid_color_brush); + return solid_color_brush; + } } } diff --git a/CruUI/graph/graph.h b/CruUI/graph/graph.h index 990b51b3..fd062787 100644 --- a/CruUI/graph/graph.h +++ b/CruUI/graph/graph.h @@ -164,5 +164,16 @@ namespace cru { return graph_manager_->GetD2D1DeviceContext(); } + + Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> CreateSolidBrush(const D2D1_COLOR_F& color); + + inline void WithTransform(ID2D1DeviceContext* device_context, const D2D1_MATRIX_3X2_F matrix, Action<ID2D1DeviceContext*>&& action) + { + D2D1_MATRIX_3X2_F old_transform; + device_context->GetTransform(&old_transform); + device_context->SetTransform(old_transform * matrix); + action(device_context); + device_context->SetTransform(old_transform); + } } } diff --git a/CruUI/main.cpp b/CruUI/main.cpp index 0d1b4032..8e7a8672 100644 --- a/CruUI/main.cpp +++ b/CruUI/main.cpp @@ -2,12 +2,14 @@ #include "ui/window.h" #include "ui/controls/linear_layout.h" #include "ui/controls/text_block.h" +#include "ui/controls/toggle_button.h" using cru::Application; using cru::ui::Window; using cru::ui::controls::LinearLayout; using cru::ui::controls::TextBlock; +using cru::ui::controls::ToggleButton; int APIENTRY wWinMain( @@ -75,6 +77,8 @@ int APIENTRY wWinMain( layout->AddChild(TextBlock::Create(L"Layout is clicked!")); }); + layout->AddChild(ToggleButton::Create()); + const auto text_block = TextBlock::Create(L"Hello World!!!"); text_block->mouse_click_event.AddHandler([layout](cru::ui::events::MouseButtonEventArgs& args) diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp index 7a705b4b..d2864fce 100644 --- a/CruUI/ui/control.cpp +++ b/CruUI/ui/control.cpp @@ -169,9 +169,9 @@ namespace cru { if (old_position_ == position) // if cache has been refreshed and no pending notify old_position_ = position_; position_ = position; + LayoutManager::GetInstance()->InvalidateControlPositionCache(this); if (auto window = GetWindow()) { - window->GetLayoutManager()->InvalidateControlPositionCache(this); window->Repaint(); } } diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h index b889fcd5..ca2dfb84 100644 --- a/CruUI/ui/control.h +++ b/CruUI/ui/control.h @@ -28,7 +28,7 @@ namespace cru class Control : public Object { friend class Window; - friend class WindowLayoutManager; + friend class LayoutManager; protected: struct WindowConstructorTag {}; //Used for constructor for class Window. @@ -123,7 +123,7 @@ namespace cru //Absolute point to local point. Point AbsoluteToLocal(const Point& point) const; - bool IsPointInside(const Point& point); + virtual bool IsPointInside(const Point& point); //*************** region: graphic *************** diff --git a/CruUI/ui/controls/linear_layout.h b/CruUI/ui/controls/linear_layout.h index 74c504cb..ead56081 100644 --- a/CruUI/ui/controls/linear_layout.h +++ b/CruUI/ui/controls/linear_layout.h @@ -18,9 +18,16 @@ namespace cru::ui::controls return new LinearLayout(orientation); } - private: + 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; + protected: Size OnMeasure(const Size& available_size) override; void OnLayout(const Rect& rect) override; diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp index a3dc23c5..beb799d3 100644 --- a/CruUI/ui/controls/text_block.cpp +++ b/CruUI/ui/controls/text_block.cpp @@ -11,19 +11,13 @@ namespace cru { namespace controls { + using graph::CreateSolidBrush; + inline Microsoft::WRL::ComPtr<IDWriteFactory> GetDWriteFactory() { return graph::GraphManager::GetInstance()->GetDWriteFactory(); } - Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> 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; - } - TextBlock::TextBlock(const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format, const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush) : Control(false) { diff --git a/CruUI/ui/controls/text_block.h b/CruUI/ui/controls/text_block.h index be2a1da2..db22e3c7 100644 --- a/CruUI/ui/controls/text_block.h +++ b/CruUI/ui/controls/text_block.h @@ -51,7 +51,7 @@ namespace cru return text_block; } - private: + protected: explicit TextBlock( const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format = nullptr, const Microsoft::WRL::ComPtr<ID2D1Brush>& init_brush = nullptr diff --git a/CruUI/ui/controls/toggle_button.cpp b/CruUI/ui/controls/toggle_button.cpp new file mode 100644 index 00000000..ea2329ea --- /dev/null +++ b/CruUI/ui/controls/toggle_button.cpp @@ -0,0 +1,123 @@ +#include "toggle_button.h" + +#include "graph/graph.h" + +namespace cru::ui::controls +{ + using graph::CreateSolidBrush; + + // 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() + { + 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_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightBlue)); + off_brush_ = CreateSolidBrush(D2D1::ColorF(D2D1::ColorF::LightGray)); + } + + inline D2D1_POINT_2F ConvertPoint(const Point& point) + { + return D2D1::Point2F(point.x, point.y); + } + + 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(ConvertPoint(point), transform, &contains); + if (!contains) + frame_path_->StrokeContainsPoint(ConvertPoint(point), stroke_width, nullptr, transform, &contains); + return contains != 0; + } + + void ToggleButton::SetState(const bool state) + { + if (state != state_) + { + state_ = state; + OnToggleInternal(state); + Repaint(); + } + } + + void ToggleButton::Toggle() + { + SetState(!GetState()); + } + + void ToggleButton::OnToggle(events::ToggleEventArgs& args) + { + + } + + void ToggleButton::OnDraw(ID2D1DeviceContext* device_context) + { + 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(inner_circle_x, 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(-inner_circle_x, 0), inner_circle_radius, inner_circle_radius), off_brush_.Get()); + } + }); + } + + void ToggleButton::OnMouseClickCore(events::MouseButtonEventArgs& args) + { + Control::OnMouseClickCore(args); + Toggle(); + } + + Size ToggleButton::OnMeasure(const Size& available_size) + { + const auto layout_params = GetLayoutParams(); + + auto&& get_measure_length = [](const MeasureLength& layout_length, const float available_length, const float fix_length) -> float + { + switch (layout_length.mode) + { + case MeasureMode::Exactly: + { + return std::max(std::min(layout_length.length, available_length), fix_length); + } + case MeasureMode::Stretch: + { + return std::max(available_length, fix_length); + } + case MeasureMode::Content: + { + return fix_length; + } + default: + UnreachableCode(); + } + }; + + const Size result_size( + get_measure_length(layout_params->width, available_size.width, half_width * 2 + stroke_width), + get_measure_length(layout_params->height, available_size.height, half_height * 2 + stroke_width) + ); + + return result_size; + } + + void ToggleButton::OnToggleInternal(bool new_state) + { + events::ToggleEventArgs args(this, this, new_state); + OnToggle(args); + toggle_event.Raise(args); + } +} diff --git a/CruUI/ui/controls/toggle_button.h b/CruUI/ui/controls/toggle_button.h new file mode 100644 index 00000000..d2e49473 --- /dev/null +++ b/CruUI/ui/controls/toggle_button.h @@ -0,0 +1,59 @@ +#pragma once + +#include "ui/control.h" + +namespace cru::ui::controls +{ + class ToggleButton : public Control + { + public: + 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; + + bool IsPointInside(const Point& point) override; + + bool GetState() const + { + return state_; + } + + void SetState(bool state); + + void Toggle(); + + public: + events::ToggleEvent toggle_event; + + protected: + virtual void OnToggle(events::ToggleEventArgs& args); + + protected: + void OnDraw(ID2D1DeviceContext* device_context) override; + + void OnMouseClickCore(events::MouseButtonEventArgs& args) override; + + Size OnMeasure(const Size& available_size) override; + + private: + void OnToggleInternal(bool new_state); + + private: + bool state_ = false; + + Microsoft::WRL::ComPtr<ID2D1RoundedRectangleGeometry> frame_path_; + Microsoft::WRL::ComPtr<ID2D1Brush> on_brush_; + Microsoft::WRL::ComPtr<ID2D1Brush> off_brush_; + }; +} diff --git a/CruUI/ui/events/ui_event.h b/CruUI/ui/events/ui_event.h index ddf5f99f..4915d63d 100644 --- a/CruUI/ui/events/ui_event.h +++ b/CruUI/ui/events/ui_event.h @@ -46,7 +46,7 @@ namespace cru MouseEventArgs(Object* sender, Object* original_sender, const std::optional<Point>& point = std::nullopt) : UiEventArgs(sender, original_sender), point_(point) { - + } MouseEventArgs(const MouseEventArgs& other) = default; MouseEventArgs(MouseEventArgs&& other) = default; @@ -67,7 +67,7 @@ namespace cru MouseButtonEventArgs(Object* sender, Object* original_sender, const Point& point, const MouseButton button) : MouseEventArgs(sender, original_sender, point), button_(button) { - + } MouseButtonEventArgs(const MouseButtonEventArgs& other) = default; MouseButtonEventArgs(MouseButtonEventArgs&& other) = default; @@ -91,7 +91,7 @@ namespace cru DrawEventArgs(Object* sender, Object* original_sender, ID2D1DeviceContext* device_context) : UiEventArgs(sender, original_sender), device_context_(device_context) { - + } DrawEventArgs(const DrawEventArgs& other) = default; DrawEventArgs(DrawEventArgs&& other) = default; @@ -115,7 +115,7 @@ namespace cru PositionChangedEventArgs(Object* sender, Object* original_sender, const Point& old_position, const Point& new_position) : UiEventArgs(sender, original_sender), old_position_(old_position), new_position_(new_position) { - + } PositionChangedEventArgs(const PositionChangedEventArgs& other) = default; PositionChangedEventArgs(PositionChangedEventArgs&& other) = default; @@ -145,7 +145,7 @@ namespace cru SizeChangedEventArgs(Object* sender, Object* original_sender, const Size& old_size, const Size& new_size) : UiEventArgs(sender, original_sender), old_size_(old_size), new_size_(new_size) { - + } SizeChangedEventArgs(const SizeChangedEventArgs& other) = default; SizeChangedEventArgs(SizeChangedEventArgs&& other) = default; @@ -171,10 +171,10 @@ namespace cru class FocusChangeEventArgs : public UiEventArgs { public: - FocusChangeEventArgs(Object* sender, Object* original_sender, const bool is_window =false) - : UiEventArgs(sender, original_sender), is_window_(is_window) + FocusChangeEventArgs(Object* sender, Object* original_sender, const bool is_window = false) + : UiEventArgs(sender, original_sender), is_window_(is_window) { - + } FocusChangeEventArgs(const FocusChangeEventArgs& other) = default; FocusChangeEventArgs(FocusChangeEventArgs&& other) = default; @@ -192,6 +192,30 @@ namespace cru bool is_window_; }; + class ToggleEventArgs : public UiEventArgs + { + public: + ToggleEventArgs(Object* sender, Object* original_sender, bool new_state) + : UiEventArgs(sender, original_sender), new_state_(new_state) + { + + } + ToggleEventArgs(const ToggleEventArgs& other) = default; + ToggleEventArgs(ToggleEventArgs&& other) = default; + ToggleEventArgs& operator=(const ToggleEventArgs& other) = default; + ToggleEventArgs& operator=(ToggleEventArgs&& other) = default; + ~ToggleEventArgs() override = default; + + bool GetNewState() const + { + return new_state_; + } + + private: + bool new_state_; + }; + + using UiEvent = Event<UiEventArgs>; using MouseEvent = Event<MouseEventArgs>; using MouseButtonEvent = Event<MouseButtonEventArgs>; @@ -199,6 +223,7 @@ namespace cru using PositionChangedEvent = Event<PositionChangedEventArgs>; using SizeChangedEvent = Event<SizeChangedEventArgs>; using FocusChangeEvent = Event<FocusChangeEventArgs>; + using ToggleEvent = Event<ToggleEventArgs>; } } -} +}
\ No newline at end of file diff --git a/CruUI/ui/layout_base.cpp b/CruUI/ui/layout_base.cpp new file mode 100644 index 00000000..f04d1fe8 --- /dev/null +++ b/CruUI/ui/layout_base.cpp @@ -0,0 +1,77 @@ +#include "layout_base.h" + +#include "application.h" +#include "control.h" + +namespace cru::ui +{ + LayoutManager* LayoutManager::GetInstance() + { + static LayoutManager layout_manager; + return &layout_manager; + } + + void LayoutManager::InvalidateControlPositionCache(Control * control) + { + if (cache_invalid_controls_.count(control) == 1) + return; + + // find descendant then erase it; find ancestor then just return. + for (auto i = cache_invalid_controls_.cbegin(); i != cache_invalid_controls_.cend(); ++i) + { + const auto result = IsAncestorOrDescendant(*i, control); + if (result == control) + cache_invalid_controls_.erase(i); + else if (result != nullptr) + return; // find a ancestor of "control", just return + } + + cache_invalid_controls_.insert(control); + + if (cache_invalid_controls_.size() == 1) // when insert just now and not repeat to "InvokeLater". + { + InvokeLater([this] { + + RefreshInvalidControlPositionCache(); // first refresh position cache. + for (const auto i : cache_invalid_controls_) // traverse all descendants of position-invalid controls and notify position change event + i->TraverseDescendants([](Control* control) + { + control->CheckAndNotifyPositionChanged(); + }); + cache_invalid_controls_.clear(); // after update and notify, clear the set. + + }); + } + } + + void LayoutManager::RefreshInvalidControlPositionCache() + { + for (const auto i : cache_invalid_controls_) + RefreshControlPositionCache(i); + } + + void LayoutManager::RefreshControlPositionCache(Control * control) + { + auto point = Point::zero; + auto parent = control; + while ((parent = parent->GetParent())) { + const auto p = parent->GetPositionRelative(); + point.x += p.x; + point.y += p.y; + } + RefreshControlPositionCacheInternal(control, point); + } + + void LayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute) + { + const auto position = control->GetPositionRelative(); + Point lefttop( + parent_lefttop_absolute.x + position.x, + parent_lefttop_absolute.y + position.y + ); + control->position_cache_.lefttop_position_absolute = lefttop; + control->ForeachChild([lefttop](Control* c) { + RefreshControlPositionCacheInternal(c, lefttop); + }); + } +} diff --git a/CruUI/ui/layout_base.h b/CruUI/ui/layout_base.h index bae01949..08f36769 100644 --- a/CruUI/ui/layout_base.h +++ b/CruUI/ui/layout_base.h @@ -1,9 +1,18 @@ #pragma once +#include "system_headers.h" +#include <unordered_set> + +#include "base.h" +#include "ui_base.h" + namespace cru { namespace ui { + class Control; + + enum class MeasureMode { Exactly, @@ -66,5 +75,38 @@ namespace cru MeasureLength width; MeasureLength height; }; + + + class LayoutManager : public Object + { + public: + static LayoutManager* GetInstance(); + + public: + LayoutManager() = default; + LayoutManager(const LayoutManager& other) = delete; + LayoutManager(LayoutManager&& other) = delete; + LayoutManager& operator=(const LayoutManager& other) = delete; + LayoutManager& operator=(LayoutManager&& other) = delete; + ~LayoutManager() override = default; + + //Mark position cache of the control and its descendants invalid, + //(which is saved as an auto-managed list internal) + //and send a message to refresh them. + void InvalidateControlPositionCache(Control* control); + + //Refresh position cache of the control and its descendants whose cache + //has been marked as invalid. + void RefreshInvalidControlPositionCache(); + + //Refresh position cache of the control and its descendants immediately. + static void RefreshControlPositionCache(Control* control); + + private: + static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); + + private: + std::unordered_set<Control*> cache_invalid_controls_; + }; } } diff --git a/CruUI/ui/ui_base.h b/CruUI/ui/ui_base.h index 15847c1d..8ce82cdf 100644 --- a/CruUI/ui/ui_base.h +++ b/CruUI/ui/ui_base.h @@ -1,5 +1,6 @@ #pragma once + namespace cru { namespace ui diff --git a/CruUI/ui/window.cpp b/CruUI/ui/window.cpp index e09b150e..3f9d9f6c 100644 --- a/CruUI/ui/window.cpp +++ b/CruUI/ui/window.cpp @@ -77,70 +77,6 @@ namespace cru return find_result->second; } - void WindowLayoutManager::InvalidateControlPositionCache(Control * control) - { - if (cache_invalid_controls_.count(control) == 1) - return; - - // find descendant then erase it; find ancestor then just return. - for (auto i = cache_invalid_controls_.cbegin(); i != cache_invalid_controls_.cend(); ++i) - { - const auto result = IsAncestorOrDescendant(*i, control); - if (result == control) - cache_invalid_controls_.erase(i); - else if (result != nullptr) - return; // find a ancestor of "control", just return - } - - cache_invalid_controls_.insert(control); - - if (cache_invalid_controls_.size() == 1) // when insert just now and not repeat to "InvokeLater". - { - InvokeLater([this] { - - RefreshInvalidControlPositionCache(); // first refresh position cache. - for (const auto i : cache_invalid_controls_) // traverse all descendants of position-invalid controls and notify position change event - i->TraverseDescendants([](Control* control) - { - control->CheckAndNotifyPositionChanged(); - }); - cache_invalid_controls_.clear(); // after update and notify, clear the set. - - }); - } - } - - void WindowLayoutManager::RefreshInvalidControlPositionCache() - { - for (const auto i : cache_invalid_controls_) - RefreshControlPositionCache(i); - } - - void WindowLayoutManager::RefreshControlPositionCache(Control * control) - { - auto point = Point::zero; - auto parent = control; - while ((parent = parent->GetParent())) { - const auto p = parent->GetPositionRelative(); - point.x += p.x; - point.y += p.y; - } - RefreshControlPositionCacheInternal(control, point); - } - - void WindowLayoutManager::RefreshControlPositionCacheInternal(Control * control, const Point & parent_lefttop_absolute) - { - const auto position = control->GetPositionRelative(); - Point lefttop( - parent_lefttop_absolute.x + position.x, - parent_lefttop_absolute.y + position.y - ); - control->position_cache_.lefttop_position_absolute = lefttop; - control->ForeachChild([lefttop](Control* c) { - RefreshControlPositionCacheInternal(c, lefttop); - }); - } - inline Point PiToDip(const POINT& pi_point) { return Point( @@ -149,7 +85,7 @@ namespace cru ); } - Window::Window() : Control(WindowConstructorTag{}, this), layout_manager_(new WindowLayoutManager()), control_list_({ this }) { + Window::Window() : Control(WindowConstructorTag{}, this), control_list_({ this }) { const auto app = Application::GetInstance(); hwnd_ = CreateWindowEx(0, app->GetWindowManager()->GetGeneralWindowClass()->GetName(), diff --git a/CruUI/ui/window.h b/CruUI/ui/window.h index 92b084e1..790e3c32 100644 --- a/CruUI/ui/window.h +++ b/CruUI/ui/window.h @@ -76,34 +76,6 @@ namespace cru { }; - class WindowLayoutManager : public Object - { - public: - WindowLayoutManager() = default; - WindowLayoutManager(const WindowLayoutManager& other) = delete; - WindowLayoutManager(WindowLayoutManager&& other) = delete; - WindowLayoutManager& operator=(const WindowLayoutManager& other) = delete; - WindowLayoutManager& operator=(WindowLayoutManager&& other) = delete; - ~WindowLayoutManager() override = default; - - //Mark position cache of the control and its descendants invalid, - //(which is saved as an auto-managed list internal) - //and send a message to refresh them. - void InvalidateControlPositionCache(Control* control); - - //Refresh position cache of the control and its descendants whose cache - //has been marked as invalid. - void RefreshInvalidControlPositionCache(); - - //Refresh position cache of the control and its descendants immediately. - static void RefreshControlPositionCache(Control* control); - - private: - static void RefreshControlPositionCacheInternal(Control* control, const Point& parent_lefttop_absolute); - - private: - std::set<Control*> cache_invalid_controls_; - }; class Window : public Control { @@ -117,13 +89,6 @@ namespace cru { ~Window() override; public: - //*************** region: managers *************** - WindowLayoutManager* GetLayoutManager() const - { - return layout_manager_.get(); - } - - //*************** region: handle *************** //Get the handle of the window. Return null if window is invalid. @@ -273,8 +238,6 @@ namespace cru { void DispatchMouseHoverControlChangeEvent(Control* old_control, Control * new_control, const Point& point); private: - std::unique_ptr<WindowLayoutManager> layout_manager_; - HWND hwnd_ = nullptr; std::shared_ptr<graph::WindowRenderTarget> render_target_{}; |