aboutsummaryrefslogtreecommitdiff
path: root/src/ui/layout_base.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/layout_base.cpp')
-rw-r--r--src/ui/layout_base.cpp79
1 files changed, 79 insertions, 0 deletions
diff --git a/src/ui/layout_base.cpp b/src/ui/layout_base.cpp
new file mode 100644
index 00000000..a26379a0
--- /dev/null
+++ b/src/ui/layout_base.cpp
@@ -0,0 +1,79 @@
+#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.
+ auto i = cache_invalid_controls_.cbegin();
+ while (i != cache_invalid_controls_.cend())
+ {
+ auto current_i = i++;
+ const auto result = IsAncestorOrDescendant(*current_i, control);
+ if (result == control)
+ cache_invalid_controls_.erase(current_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);
+ });
+ }
+}