aboutsummaryrefslogtreecommitdiff
path: root/CruUI/ui
diff options
context:
space:
mode:
Diffstat (limited to 'CruUI/ui')
-rw-r--r--CruUI/ui/control.cpp13
-rw-r--r--CruUI/ui/control.h2
-rw-r--r--CruUI/ui/controls/linear_layout.cpp88
-rw-r--r--CruUI/ui/controls/linear_layout.h25
-rw-r--r--CruUI/ui/controls/text_block.cpp18
-rw-r--r--CruUI/ui/layout_base.h2
-rw-r--r--CruUI/ui/ui_base.h5
-rw-r--r--CruUI/ui/window.cpp5
-rw-r--r--CruUI/ui/window.h2
9 files changed, 144 insertions, 16 deletions
diff --git a/CruUI/ui/control.cpp b/CruUI/ui/control.cpp
index 20aeb900..ee6db284 100644
--- a/CruUI/ui/control.cpp
+++ b/CruUI/ui/control.cpp
@@ -19,7 +19,7 @@ namespace cru {
size_(Size::zero),
position_cache_(),
is_mouse_inside_(false),
- layout_params_(nullptr),
+ layout_params_(new BasicLayoutParams()),
desired_size_(Size::zero)
{
@@ -27,14 +27,12 @@ namespace cru {
void Control::ForeachChild(Action<Control*>&& predicate) const
{
- ThrowIfNotContainer();
for (const auto child : children_)
predicate(child);
}
void Control::ForeachChild(FlowControlAction<Control*>&& predicate) const
{
- ThrowIfNotContainer();
for (const auto child : children_)
{
if (predicate(child) == FlowControl::Break)
@@ -130,7 +128,6 @@ namespace cru {
void Control::TraverseDescendants(Action<Control*>&& predicate)
{
- ThrowIfNotContainer();
TraverseDescendantsInternal(this, predicate);
}
@@ -231,6 +228,12 @@ namespace cru {
return window->GetFocusControl() == this;
}
+ void Control::Relayout()
+ {
+ OnMeasure(GetSize());
+ OnLayout(Rect(GetPositionRelative(), GetSize()));
+ }
+
void Control::Measure(const Size& available_size)
{
SetDesiredSize(OnMeasure(available_size));
@@ -409,7 +412,7 @@ namespace cru {
}
};
- Size size_for_children;
+ Size size_for_children; // NOLINT(cppcoreguidelines-pro-type-member-init)
size_for_children.width = get_available_length_for_child(layout_params->width, available_size.width);
size_for_children.height = get_available_length_for_child(layout_params->height, available_size.height);
diff --git a/CruUI/ui/control.h b/CruUI/ui/control.h
index b9dccf19..f4302e80 100644
--- a/CruUI/ui/control.h
+++ b/CruUI/ui/control.h
@@ -136,6 +136,8 @@ namespace cru
//*************** region: layout ***************
+ void Relayout();
+
void Measure(const Size& available_size);
void Layout(const Rect& rect);
diff --git a/CruUI/ui/controls/linear_layout.cpp b/CruUI/ui/controls/linear_layout.cpp
new file mode 100644
index 00000000..f639720d
--- /dev/null
+++ b/CruUI/ui/controls/linear_layout.cpp
@@ -0,0 +1,88 @@
+#include "linear_layout.h"
+
+namespace cru::ui::controls
+{
+ LinearLayout::LinearLayout(const Orientation orientation)
+ : Control(true), orientation_(orientation)
+ {
+
+ }
+
+ Size LinearLayout::OnMeasure(const Size& available_size)
+ {
+ const auto layout_params = GetLayoutParams();
+
+ if (!layout_params->Validate())
+ throw std::runtime_error("LayoutParams is not valid. Please check it.");
+
+ auto&& get_available_length_for_child = [](const MeasureLength& layout_length, const float available_length) -> float
+ {
+ switch (layout_length.mode)
+ {
+ case MeasureMode::Exactly:
+ {
+ return std::min(layout_length.length, available_length);
+ }
+ case MeasureMode::Stretch:
+ case MeasureMode::Content:
+ {
+ return available_length;
+ }
+ default:
+ UnreachableCode();
+ }
+ };
+
+ Size total_available_size_for_children(
+ get_available_length_for_child(layout_params->width, available_size.width),
+ get_available_length_for_child(layout_params->height, available_size.height)
+ );
+
+ auto rest_available_size_for_children = total_available_size_for_children;
+
+ ForeachChild([this, &rest_available_size_for_children](Control* const control)
+ {
+ control->Measure(rest_available_size_for_children);
+ if (orientation_ == Orientation::Horizontal)
+ rest_available_size_for_children.width -= control->GetDesiredSize().width;
+ else
+ rest_available_size_for_children.height -= control->GetDesiredSize().height;
+ });
+
+ auto actual_size_for_children = total_available_size_for_children - rest_available_size_for_children;
+
+ auto&& calculate_final_length = [](const MeasureLength& layout_length, const float length_for_children, const float max_child_length) -> float
+ {
+ switch (layout_length.mode)
+ {
+ case MeasureMode::Exactly:
+ case MeasureMode::Stretch:
+ return length_for_children;
+ case MeasureMode::Content:
+ return max_child_length;
+ default:
+ UnreachableCode();
+ }
+ };
+
+ return Size(
+ calculate_final_length(layout_params->width, total_available_size_for_children.width, actual_size_for_children.width),
+ calculate_final_length(layout_params->height, total_available_size_for_children.height, actual_size_for_children.height)
+ );
+ }
+
+ void LinearLayout::OnLayout(const Rect& rect)
+ {
+ auto current_anchor = Point::zero;
+ ForeachChild([this, &current_anchor](Control* control)
+ {
+ const auto size = control->GetDesiredSize();
+ control->Layout(Rect(current_anchor, size));
+
+ if (orientation_ == Orientation::Horizontal)
+ current_anchor.x += size.width;
+ else
+ current_anchor.y += size.height;
+ });
+ }
+}
diff --git a/CruUI/ui/controls/linear_layout.h b/CruUI/ui/controls/linear_layout.h
new file mode 100644
index 00000000..b8722b6f
--- /dev/null
+++ b/CruUI/ui/controls/linear_layout.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "ui/control.h"
+
+namespace cru::ui::controls
+{
+ class LinearLayout : public Control
+ {
+ public:
+ enum class Orientation
+ {
+ Horizontal,
+ Vertical
+ };
+
+ explicit LinearLayout(Orientation orientation = Orientation::Vertical);
+
+ protected:
+ Size OnMeasure(const Size& available_size) override;
+ void OnLayout(const Rect& rect) override;
+
+ private:
+ Orientation orientation_;
+ };
+}
diff --git a/CruUI/ui/controls/text_block.cpp b/CruUI/ui/controls/text_block.cpp
index 86d01896..3649aea6 100644
--- a/CruUI/ui/controls/text_block.cpp
+++ b/CruUI/ui/controls/text_block.cpp
@@ -53,7 +53,8 @@ namespace cru
void TextBlock::OnDraw(ID2D1DeviceContext* device_context)
{
- device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
+ if (text_layout_ != nullptr)
+ device_context->DrawTextLayout(D2D1::Point2F(), text_layout_.Get(), brush_.Get());
}
Size TextBlock::OnMeasure(const Size& available_size)
@@ -67,7 +68,7 @@ namespace cru
if (layout_params->width.mode == MeasureMode::Stretch && layout_params->height.mode == MeasureMode::Stretch)
return available_size;
- Size measure_size;
+ Size measure_size; // NOLINT(cppcoreguidelines-pro-type-member-init)
auto&& get_measure_length = [](const MeasureLength& layout_length, const float available_length) -> float
{
@@ -95,8 +96,9 @@ namespace cru
const auto dwrite_factory = GetDWriteFactory();
- dwrite_factory->CreateTextLayout(text_.c_str(), text_.size(),
- text_format_.Get(), measure_size.width, measure_size.height, &measure_text_layout);
+ ThrowIfFailed(dwrite_factory->CreateTextLayout(text_.c_str(), text_.size(),
+ text_format_.Get(), measure_size.width, measure_size.height, &measure_text_layout)
+ );
DWRITE_TEXT_METRICS metrics{};
measure_text_layout->GetMetrics(&metrics);
@@ -113,10 +115,12 @@ namespace cru
return measure_result_length;
};
- return Size(
+ const Size result_size(
calculate_final_length(layout_params->width, measure_size.width, measure_result.width),
calculate_final_length(layout_params->height, measure_size.height, measure_result.height)
);
+
+ return result_size;
}
void TextBlock::OnTextChangedCore(const String& old_text, const String& new_text)
@@ -162,12 +166,12 @@ namespace cru
const auto&& size = GetSize();
- dwrite_factory->CreateTextLayout(
+ ThrowIfFailed(dwrite_factory->CreateTextLayout(
text_.c_str(), text_.size(),
text_format_.Get(),
size.width, size.height,
&text_layout_
- );
+ ));
std::for_each(text_layout_handlers_.cbegin(), text_layout_handlers_.cend(), [this](const std::shared_ptr<TextLayoutHandler>& handler)
{
diff --git a/CruUI/ui/layout_base.h b/CruUI/ui/layout_base.h
index 0213b879..bae01949 100644
--- a/CruUI/ui/layout_base.h
+++ b/CruUI/ui/layout_base.h
@@ -13,7 +13,7 @@ namespace cru
struct MeasureLength final
{
- explicit MeasureLength(const float length = 0.0, const MeasureMode mode = MeasureMode::Exactly)
+ explicit MeasureLength(const float length = 0.0, const MeasureMode mode = MeasureMode::Content)
: length(length), mode(mode)
{
diff --git a/CruUI/ui/ui_base.h b/CruUI/ui/ui_base.h
index 43b4a6dc..15847c1d 100644
--- a/CruUI/ui/ui_base.h
+++ b/CruUI/ui/ui_base.h
@@ -36,6 +36,11 @@ namespace cru
float height;
};
+ inline Size operator - (const Size& left, const Size& right)
+ {
+ return Size(left.width - right.width, left.height - right.height);
+ }
+
struct Rect
{
Rect() = default;
diff --git a/CruUI/ui/window.cpp b/CruUI/ui/window.cpp
index 4ab38cad..2c731a1e 100644
--- a/CruUI/ui/window.cpp
+++ b/CruUI/ui/window.cpp
@@ -136,7 +136,7 @@ namespace cru
});
}
- Window::Window() : layout_manager_(new WindowLayoutManager()), control_list_({ this }) {
+ Window::Window() : Control(true), layout_manager_(new WindowLayoutManager()), control_list_({ this }) {
auto app = Application::GetInstance();
hwnd_ = CreateWindowEx(0,
app->GetWindowManager()->GetGeneralWindowClass()->GetName(),
@@ -342,7 +342,7 @@ namespace cru
void Window::SetSize(const Size & size)
{
- SetClientSize(size);
+
}
void Window::RefreshControlList() {
@@ -429,6 +429,7 @@ namespace cru
void Window::OnResizeInternal(int new_width, int new_height) {
render_target_->ResizeBuffer(new_width, new_height);
+ Relayout();
}
void Window::OnSetFocusInternal()
diff --git a/CruUI/ui/window.h b/CruUI/ui/window.h
index cdc67362..7ecea456 100644
--- a/CruUI/ui/window.h
+++ b/CruUI/ui/window.h
@@ -184,7 +184,7 @@ namespace cru {
//Get the size of client area for a window.
Size GetSize() override final;
- //Set the size of client area for a window.
+ //This method has no effect for a window. Use SetClientSize instead.
void SetSize(const Size& size) override final;