aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-10-30 13:14:34 +0800
committercrupest <crupest@outlook.com>2020-10-30 13:14:34 +0800
commit93265251d56c91b05f160423077ce95339786f87 (patch)
tree96627217a4a3ed3bca6a21e35ca6310ef6217936
parenta176c40ba0f913f98e966f11bad557833ae6dc57 (diff)
downloadcru-93265251d56c91b05f160423077ce95339786f87.tar.gz
cru-93265251d56c91b05f160423077ce95339786f87.tar.bz2
cru-93265251d56c91b05f160423077ce95339786f87.zip
...
-rw-r--r--include/cru/platform/gui/UiApplication.hpp4
-rw-r--r--include/cru/ui/host/LayoutPaintCycler.hpp39
-rw-r--r--include/cru/ui/host/WindowHost.hpp8
-rw-r--r--src/ui/CMakeLists.txt2
-rw-r--r--src/ui/host/LayoutPaintCycler.cpp35
-rw-r--r--src/ui/host/WindowHost.cpp33
6 files changed, 105 insertions, 16 deletions
diff --git a/include/cru/platform/gui/UiApplication.hpp b/include/cru/platform/gui/UiApplication.hpp
index 6a2eb067..ff947dfc 100644
--- a/include/cru/platform/gui/UiApplication.hpp
+++ b/include/cru/platform/gui/UiApplication.hpp
@@ -67,6 +67,10 @@ class TimerAutoCanceler {
return *this;
}
+ TimerAutoCanceler& operator=(long long other) {
+ return this->operator=(TimerAutoCanceler(other));
+ }
+
~TimerAutoCanceler() { Reset(); }
long long Release() {
diff --git a/include/cru/ui/host/LayoutPaintCycler.hpp b/include/cru/ui/host/LayoutPaintCycler.hpp
new file mode 100644
index 00000000..ed543afa
--- /dev/null
+++ b/include/cru/ui/host/LayoutPaintCycler.hpp
@@ -0,0 +1,39 @@
+#pragma once
+#include "../Base.hpp"
+
+#include "cru/platform/gui/UiApplication.hpp"
+
+#include <chrono>
+
+namespace cru::ui::host {
+class LayoutPaintCycler {
+ public:
+ explicit LayoutPaintCycler(WindowHost* host);
+
+ CRU_DELETE_COPY(LayoutPaintCycler)
+ CRU_DELETE_MOVE(LayoutPaintCycler)
+
+ ~LayoutPaintCycler();
+
+ public:
+ void InvalidateLayout();
+ void InvalidatePaint();
+
+ bool IsLayoutDirty() { return layout_dirty_; }
+
+ private:
+ void OnCycle();
+
+ private:
+ WindowHost* host_;
+
+ platform::gui::TimerAutoCanceler timer_canceler_;
+
+ bool layout_dirty_ = true;
+ bool paint_dirty_ = true;
+
+ std::chrono::steady_clock::time_point last_cycle_time_;
+ std::chrono::steady_clock::duration cycle_threshold_ =
+ std::chrono::milliseconds(1000) / 144;
+};
+} // namespace cru::ui::host
diff --git a/include/cru/ui/host/WindowHost.hpp b/include/cru/ui/host/WindowHost.hpp
index 77ed937f..81eabb52 100644
--- a/include/cru/ui/host/WindowHost.hpp
+++ b/include/cru/ui/host/WindowHost.hpp
@@ -7,8 +7,11 @@
#include "../render/Base.hpp"
#include <functional>
+#include <memory>
namespace cru::ui::host {
+class LayoutPaintCycler;
+
struct AfterLayoutEventArgs {};
// The bridge between control tree and native window.
@@ -43,6 +46,8 @@ class WindowHost : public Object {
void Relayout();
void Relayout(const Size& available_size);
+ void Repaint();
+
// Is layout is invalid, wait for relayout and then run the action. Otherwist
// run it right now.
void RunAfterLayoutStable(std::function<void()> action);
@@ -125,7 +130,8 @@ class WindowHost : public Object {
platform::gui::INativeWindow* native_window_ = nullptr;
- bool need_layout_ = false;
+ std::unique_ptr<LayoutPaintCycler> layout_paint_cycler_;
+
Event<AfterLayoutEventArgs> after_layout_event_;
std::vector<std::function<void()> > after_layout_stable_action_;
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index d7b924cb..449fb4d9 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(cru_ui STATIC
controls/TextBlock.cpp
controls/TextBox.cpp
controls/TextControlService.hpp
+ host/LayoutPaintCycler.cpp
host/WindowHost.cpp
render/BorderRenderObject.cpp
render/CanvasRenderObject.cpp
@@ -50,6 +51,7 @@ target_sources(cru_ui PUBLIC
${CRU_UI_INCLUDE_DIR}/controls/StackLayout.hpp
${CRU_UI_INCLUDE_DIR}/controls/TextBox.hpp
${CRU_UI_INCLUDE_DIR}/controls/TextBlock.hpp
+ ${CRU_UI_INCLUDE_DIR}/host/LayoutPaintCycler.hpp
${CRU_UI_INCLUDE_DIR}/host/WindowHost.hpp
${CRU_UI_INCLUDE_DIR}/render/Base.hpp
${CRU_UI_INCLUDE_DIR}/render/BorderRenderObject.hpp
diff --git a/src/ui/host/LayoutPaintCycler.cpp b/src/ui/host/LayoutPaintCycler.cpp
new file mode 100644
index 00000000..9b319da4
--- /dev/null
+++ b/src/ui/host/LayoutPaintCycler.cpp
@@ -0,0 +1,35 @@
+#include "cru/ui/host/LayoutPaintCycler.hpp"
+#include <chrono>
+
+#include "../Helper.hpp"
+#include "cru/ui/Base.hpp"
+#include "cru/ui/host/WindowHost.hpp"
+
+namespace cru::ui::host {
+LayoutPaintCycler::LayoutPaintCycler(WindowHost* host) : host_(host) {
+ timer_canceler_ = GetUiApplication()->SetInterval(
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ this->cycle_threshold_),
+ [this] { OnCycle(); });
+}
+
+LayoutPaintCycler::~LayoutPaintCycler() = default;
+
+void LayoutPaintCycler::InvalidateLayout() { layout_dirty_ = true; }
+
+void LayoutPaintCycler::InvalidatePaint() { paint_dirty_ = true; }
+
+void LayoutPaintCycler::OnCycle() {
+ last_cycle_time_ = std::chrono::steady_clock::now();
+ if (layout_dirty_) {
+ host_->Relayout();
+ host_->Repaint();
+ } else {
+ if (paint_dirty_) {
+ host_->Repaint();
+ }
+ }
+ layout_dirty_ = true;
+ paint_dirty_ = true;
+}
+} // namespace cru::ui::host
diff --git a/src/ui/host/WindowHost.cpp b/src/ui/host/WindowHost.cpp
index eac247c1..e04fdf31 100644
--- a/src/ui/host/WindowHost.cpp
+++ b/src/ui/host/WindowHost.cpp
@@ -1,6 +1,7 @@
#include "cru/ui/host/WindowHost.hpp"
#include "RoutedEventDispatch.hpp"
+#include "cru/common/Base.hpp"
#include "cru/common/Logger.hpp"
#include "cru/platform/graphics/Painter.hpp"
#include "cru/platform/gui/InputMethod.hpp"
@@ -8,10 +9,12 @@
#include "cru/platform/gui/Window.hpp"
#include "cru/ui/DebugFlags.hpp"
#include "cru/ui/Window.hpp"
+#include "cru/ui/host/LayoutPaintCycler.hpp"
#include "cru/ui/render/MeasureRequirement.hpp"
#include "cru/ui/render/RenderObject.hpp"
#include <cstddef>
+#include <memory>
namespace cru::ui::host {
using platform::gui::INativeWindow;
@@ -113,6 +116,8 @@ WindowHost::WindowHost(Control* root_control)
root_render_object_ = root_control->GetRenderObject();
root_render_object_->SetWindowHostRecursive(this);
+ this->layout_paint_cycler_ = std::make_unique<LayoutPaintCycler>(this);
+
BindNativeEvent(this, native_window, native_window->DestroyEvent(),
&WindowHost::OnNativeDestroy, event_revoker_guards_);
BindNativeEvent(this, native_window, native_window->PaintEvent(),
@@ -141,13 +146,10 @@ WindowHost::~WindowHost() {
}
}
-void WindowHost::InvalidatePaint() {
- if (native_window_) native_window_->RequestRepaint();
-}
+void WindowHost::InvalidatePaint() { layout_paint_cycler_->InvalidatePaint(); }
void WindowHost::InvalidateLayout() {
- need_layout_ = true;
- this->InvalidatePaint();
+ layout_paint_cycler_->InvalidateLayout();
}
bool WindowHost::IsLayoutPreferToFillWindow() const {
@@ -186,6 +188,13 @@ void WindowHost::Relayout(const Size& available_size) {
log::TagDebug(log_tag, u"A relayout is finished.");
}
+void WindowHost::Repaint() {
+ auto painter = native_window_->BeginPaint();
+ painter->Clear(colors::white);
+ root_render_object_->Draw(painter.get());
+ painter->EndDraw();
+}
+
Control* WindowHost::GetFocusControl() { return focus_control_; }
void WindowHost::SetFocusControl(Control* control) {
@@ -236,7 +245,7 @@ Control* WindowHost::GetMouseCaptureControl() {
}
void WindowHost::RunAfterLayoutStable(std::function<void()> action) {
- if (need_layout_) {
+ if (layout_paint_cycler_->IsLayoutDirty()) {
after_layout_stable_action_.push_back(std::move(action));
} else {
action();
@@ -249,14 +258,8 @@ void WindowHost::OnNativeDestroy(INativeWindow* window, std::nullptr_t) {
}
void WindowHost::OnNativePaint(INativeWindow* window, std::nullptr_t) {
- if (need_layout_) {
- Relayout();
- need_layout_ = false;
- }
- auto painter = window->BeginPaint();
- painter->Clear(colors::white);
- root_render_object_->Draw(painter.get());
- painter->EndDraw();
+ CRU_UNUSED(window)
+ layout_paint_cycler_->InvalidatePaint();
}
void WindowHost::OnNativeResize(INativeWindow* window, const Size& size) {
@@ -397,4 +400,4 @@ Control* WindowHost::HitTest(const Point& point) {
}
return root_control_;
}
-} // namespace cru::ui
+} // namespace cru::ui::host