aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/common/self_resolvable.hpp45
-rw-r--r--include/cru/ui/controls/flex_layout.hpp22
-rw-r--r--include/cru/ui/render/flex_layout_render_object.hpp39
-rw-r--r--include/cru/ui/ui_manager.hpp1
-rw-r--r--include/cru/ui/window.hpp10
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/ui/render/flex_layout_render_object.cpp30
-rw-r--r--src/ui/window.cpp15
8 files changed, 140 insertions, 23 deletions
diff --git a/include/cru/common/self_resolvable.hpp b/include/cru/common/self_resolvable.hpp
new file mode 100644
index 00000000..edeb1434
--- /dev/null
+++ b/include/cru/common/self_resolvable.hpp
@@ -0,0 +1,45 @@
+#pragma once
+#include "pre_config.hpp"
+
+#include <memory>
+
+namespace cru {
+template <typename T>
+class SelfResovable;
+
+template <typename T>
+class ObjectResovler {
+ friend SelfResovable<T>;
+
+ private:
+ ObjectResovler(const std::shared_ptr<T*>& resolver) : resolver_(resolver) {}
+
+ public:
+ ObjectResovler(const ObjectResovler&) = default;
+ ObjectResovler& operator=(const ObjectResovler&) = default;
+ ObjectResovler(ObjectResovler&&) = default;
+ ObjectResovler& operator=(ObjectResovler&&) = default;
+ ~ObjectResovler() = default;
+
+ T* Resolve() const { return *resolver_; }
+
+ private:
+ std::shared_ptr<T*> resolver_;
+};
+
+template <typename T>
+class SelfResovable {
+ public:
+ SelfResovable() : resolver_(new T*(static_cast<T*>(this))) {}
+ SelfResovable(const SelfResovable&) = delete;
+ SelfResovable& operator=(const SelfResovable&) = delete;
+ SelfResovable(SelfResovable&&) = delete;
+ SelfResovable& operator=(SelfResovable&&) = delete;
+ virtual ~SelfResovable() { (*resolver_) = nullptr; }
+
+ ObjectResovler<T> CreateResolver() { return ObjectResovler<T>(resolver_); }
+
+ private:
+ std::shared_ptr<T*> resolver_;
+};
+} // namespace cru
diff --git a/include/cru/ui/controls/flex_layout.hpp b/include/cru/ui/controls/flex_layout.hpp
index 7422bc05..46c4ea55 100644
--- a/include/cru/ui/controls/flex_layout.hpp
+++ b/include/cru/ui/controls/flex_layout.hpp
@@ -1,13 +1,17 @@
#pragma once
#include "../layout_control.hpp"
-#include <memory>
+#include "../render/flex_layout_render_object.hpp"
+#include "../window.hpp"
-namespace cru::ui::render {
-class FlexLayoutRenderObject;
-}
+#include <memory>
namespace cru::ui::controls {
+// import these basic entities
+using render::FlexChildLayoutData;
+using render::FlexCrossAlignment;
+using render::FlexDirection;
+using render::FlexMainAlignment;
class FlexLayout : public LayoutControl {
public:
@@ -31,6 +35,16 @@ class FlexLayout : public LayoutControl {
render::RenderObject* GetRenderObject() const override;
+ FlexMainAlignment GetContentMainAlign() const {
+ return render_object_->GetContentMainAlign();
+ }
+
+ void SetContentMainAlign(FlexMainAlignment value) {
+ if (value == GetContentMainAlign()) return;
+ render_object_->SetContentMainAlign(value);
+ GetWindow()->InvalidateLayout();
+ }
+
protected:
void OnAddChild(Control* child, int position) override;
void OnRemoveChild(Control* child, int position) override;
diff --git a/include/cru/ui/render/flex_layout_render_object.hpp b/include/cru/ui/render/flex_layout_render_object.hpp
index 99ec1247..8d881239 100644
--- a/include/cru/ui/render/flex_layout_render_object.hpp
+++ b/include/cru/ui/render/flex_layout_render_object.hpp
@@ -11,13 +11,32 @@ enum class FlexDirection {
VertivalReverse
};
-enum class Alignment { Start, End, Center };
+namespace internal {
+constexpr int align_start = 0;
+constexpr int align_end = align_start + 1;
+constexpr int align_center = align_end + 1;
+//constexpr int align_stretch = align_center + 1;
+} // namespace internal
+
+enum class FlexMainAlignment {
+ Start = internal::align_start,
+ End = internal::align_end,
+ Center = internal::align_center
+};
+enum class FlexCrossAlignment {
+ Start = internal::align_start,
+ End = internal::align_end,
+ Center = internal::align_center,
+// Stretch = internal::align_stretch
+};
struct FlexChildLayoutData {
- std::optional<float> flex_basis; // nullopt stands for content
+ // nullopt stands for looking at my content
+ std::optional<float> flex_basis = std::nullopt;
float flex_grow = 0;
float flex_shrink = 0;
- Alignment alignment = Alignment::Center;
+ // nullopt stands for looking at parent's setting
+ std::optional<FlexCrossAlignment> cross_alignment = std::nullopt;
};
class FlexLayoutRenderObject : public RenderObject {
@@ -33,8 +52,15 @@ class FlexLayoutRenderObject : public RenderObject {
FlexDirection GetFlexDirection() const { return direction_; }
void SetFlexDirection(FlexDirection direction) { direction_ = direction; }
- Alignment GetContentMainAlign() const { return content_main_align_; }
- void SetContentMainAlign(Alignment align) { content_main_align_ = align; }
+ FlexMainAlignment GetContentMainAlign() const { return content_main_align_; }
+ void SetContentMainAlign(FlexMainAlignment align) {
+ content_main_align_ = align;
+ }
+
+ FlexCrossAlignment GetItemCrossAlign() const { return item_cross_align_; }
+ void SetItemCrossAlign(FlexCrossAlignment align) {
+ item_cross_align_ = align;
+ }
FlexChildLayoutData* GetChildLayoutData(int position);
@@ -51,7 +77,8 @@ class FlexLayoutRenderObject : public RenderObject {
private:
FlexDirection direction_ = FlexDirection::Horizontal;
- Alignment content_main_align_ = Alignment::Start;
+ FlexMainAlignment content_main_align_ = FlexMainAlignment::Start;
+ FlexCrossAlignment item_cross_align_ = FlexCrossAlignment::Center;
std::vector<FlexChildLayoutData> child_layout_data_{};
};
} // namespace cru::ui::render
diff --git a/include/cru/ui/ui_manager.hpp b/include/cru/ui/ui_manager.hpp
index 2dc9cf6b..f3f78722 100644
--- a/include/cru/ui/ui_manager.hpp
+++ b/include/cru/ui/ui_manager.hpp
@@ -9,6 +9,7 @@ struct IFontDescriptor;
} // namespace cru::platform
namespace cru::ui {
+//TODO: Make this theme resource.
class PredefineResources : public Object {
public:
PredefineResources();
diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp
index 4bc0e41d..e175b234 100644
--- a/include/cru/ui/window.hpp
+++ b/include/cru/ui/window.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "content_control.hpp"
+#include "cru/common/self_resolvable.hpp"
#include "cru/platform/native/native_event.hpp"
#include "event/ui_event.hpp"
@@ -16,7 +17,7 @@ namespace render {
class WindowRenderObject;
}
-class Window final : public ContentControl {
+class Window final : public ContentControl, public SelfResovable<Window> {
public:
static constexpr auto control_type = L"Window";
@@ -46,6 +47,11 @@ class Window final : public ContentControl {
Control* GetMouseHoverControl() const { return mouse_hover_control_; }
+ //*************** region: layout ***************
+ void Relayout();
+
+ void InvalidateLayout();
+
//*************** region: focus ***************
// Request focus for specified control.
@@ -93,5 +99,7 @@ class Window final : public ContentControl {
Control* mouse_hover_control_;
Control* focus_control_; // "focus_control_" can't be nullptr
+
+ bool need_layout_ = false;
};
} // namespace cru::ui
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e7f0edbb..16e0c10f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,6 +7,7 @@ target_sources(cru_base INTERFACE
${CRU_BASE_INCLUDE_DIR}/event.hpp
${CRU_BASE_INCLUDE_DIR}/format.hpp
${CRU_BASE_INCLUDE_DIR}/pre_config.hpp
+ ${CRU_BASE_INCLUDE_DIR}/self_resolvable.hpp
${CRU_BASE_INCLUDE_DIR}/ui_base.hpp
)
target_include_directories(cru_base INTERFACE ${CRU_INCLUDE_DIR})
diff --git a/src/ui/render/flex_layout_render_object.cpp b/src/ui/render/flex_layout_render_object.cpp
index 0093f1ad..a9841813 100644
--- a/src/ui/render/flex_layout_render_object.cpp
+++ b/src/ui/render/flex_layout_render_object.cpp
@@ -161,15 +161,15 @@ Size FlexLayoutRenderObject::OnMeasureContent(const Size& available_size) {
}
void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
- auto calculate_anchor = [](Alignment alignment, float start_point,
+ auto calculate_anchor = [](int alignment, float start_point,
float total_length,
float content_length) -> float {
switch (alignment) {
- case Alignment::Start:
+ case internal::align_start:
return start_point;
- case Alignment::Center:
+ case internal::align_center:
return start_point + (total_length - content_length) / 2.0f;
- case Alignment::End:
+ case internal::align_end:
return start_point + total_length - content_length;
default:
return 0;
@@ -184,8 +184,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
actual_content_width += child->GetPreferredSize().width;
}
- const float content_anchor_x = calculate_anchor(
- content_main_align_, 0, content_rect.width, actual_content_width);
+ const float content_anchor_x =
+ calculate_anchor(static_cast<int>(content_main_align_), 0,
+ content_rect.width, actual_content_width);
float anchor_x = 0;
for (int i = 0; i < children.size(); i++) {
@@ -199,8 +200,10 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
real_anchor_x = content_rect.GetRight() - real_anchor_x;
child->Layout(Rect{
real_anchor_x,
- calculate_anchor(child_layout_data_[i].alignment, content_rect.top,
- content_rect.height, size.height),
+ calculate_anchor(
+ static_cast<int>(child_layout_data_[i].cross_alignment.value_or(
+ this->item_cross_align_)),
+ content_rect.top, content_rect.height, size.height),
size.width, size.height});
anchor_x += size.width;
@@ -211,8 +214,9 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
actual_content_height = child->GetPreferredSize().height;
}
- const float content_anchor_y = calculate_anchor(
- content_main_align_, 0, content_rect.height, actual_content_height);
+ const float content_anchor_y =
+ calculate_anchor(static_cast<int>(content_main_align_), 0,
+ content_rect.height, actual_content_height);
float anchor_y = 0;
for (int i = 0; i < children.size(); i++) {
@@ -227,8 +231,10 @@ void FlexLayoutRenderObject::OnLayoutContent(const Rect& content_rect) {
}
child->Layout(Rect{
real_anchor_y,
- calculate_anchor(child_layout_data_[i].alignment, content_rect.left,
- content_rect.width, size.width),
+ calculate_anchor(
+ static_cast<int>(child_layout_data_[i].cross_alignment.value_or(
+ this->item_cross_align_)),
+ content_rect.left, content_rect.width, size.width),
size.width, size.height});
anchor_y += size.height;
diff --git a/src/ui/window.cpp b/src/ui/window.cpp
index 2215826a..4a1bc108 100644
--- a/src/ui/window.cpp
+++ b/src/ui/window.cpp
@@ -147,6 +147,21 @@ render::RenderObject* Window::GetRenderObject() const {
return render_object_.get();
}
+void Window::Relayout() { this->render_object_->MeasureAndLayout(); }
+
+void Window::InvalidateLayout() {
+ if (!need_layout_) {
+ platform::native::IUiApplication::GetInstance()->InvokeLater(
+ [resolver = this->CreateResolver()] {
+ if (const auto window = resolver.Resolve()) {
+ window->Relayout();
+ window->need_layout_ = false;
+ }
+ });
+ need_layout_ = true;
+ }
+}
+
bool Window::RequestFocusFor(Control* control) {
assert(control != nullptr); // The control to request focus can't be null.
// You can set it as the window.