aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CruUI/CruUI.vcxproj2
-rw-r--r--CruUI/CruUI.vcxproj.filters6
-rw-r--r--CruUI/main.cpp62
-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
12 files changed, 192 insertions, 38 deletions
diff --git a/CruUI/CruUI.vcxproj b/CruUI/CruUI.vcxproj
index 7d02c7c0..ba46d963 100644
--- a/CruUI/CruUI.vcxproj
+++ b/CruUI/CruUI.vcxproj
@@ -160,6 +160,7 @@
<ClInclude Include="timer.h" />
<ClInclude Include="ui\control.h" />
<ClInclude Include="global_macros.h" />
+ <ClInclude Include="ui\controls\linear_layout.h" />
<ClInclude Include="ui\controls\text_block.h" />
<ClInclude Include="ui\events\ui_event.h" />
<ClInclude Include="ui\layout_base.h" />
@@ -174,6 +175,7 @@
<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\events\ui_event.cpp" />
<ClCompile Include="ui\window.cpp" />
diff --git a/CruUI/CruUI.vcxproj.filters b/CruUI/CruUI.vcxproj.filters
index 682c6b5c..a282cfda 100644
--- a/CruUI/CruUI.vcxproj.filters
+++ b/CruUI/CruUI.vcxproj.filters
@@ -57,6 +57,9 @@
<ClInclude Include="ui\controls\text_block.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="ui\controls\linear_layout.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="application.cpp">
@@ -92,5 +95,8 @@
<ClCompile Include="ui\controls\text_block.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="ui\controls\linear_layout.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/CruUI/main.cpp b/CruUI/main.cpp
index 77ee44c0..bd0d3247 100644
--- a/CruUI/main.cpp
+++ b/CruUI/main.cpp
@@ -1,14 +1,13 @@
-#include <random>
-
#include "application.h"
#include "ui/window.h"
-#include "timer.h"
+#include "ui/controls/linear_layout.h"
#include "ui/controls/text_block.h"
using cru::Application;
using cru::ui::Window;
-
+using cru::ui::controls::LinearLayout;
+using cru::ui::controls::TextBlock;
int APIENTRY wWinMain(
@@ -17,9 +16,11 @@ int APIENTRY wWinMain(
LPWSTR lpCmdLine,
int nCmdShow) {
- Application application(hInstance);
+ Application application(hInstance);
Window window;
+ /*
+ // test1
cru::ui::controls::TextBlock text_block;
text_block.SetText(L"Hello world!");
text_block.SetSize(cru::ui::Size(200, 30));
@@ -38,29 +39,46 @@ int APIENTRY wWinMain(
std::uniform_int_distribution<decltype(colors.size())> uni(0, colors.size() - 1); // guaranteed unbiased
- window.draw_event.AddHandler([&](cru::ui::events::DrawEventArgs& args) {
- auto device_context = args.GetDeviceContext();
+ window.draw_event.AddHandler([&](cru::ui::events::DrawEventArgs& args) {
+ auto device_context = args.GetDeviceContext();
+
+ ID2D1SolidColorBrush* brush;
+ device_context->CreateSolidColorBrush(colors[uni(rng)], &brush);
+
+ device_context->FillRectangle(D2D1::RectF(100.0f, 100.0f, 300.0f, 200.0f), brush);
+
+ brush->Release();
+ });
+
+ cru::SetTimeout(2.0, [&window]() {
+ window.Repaint();
- ID2D1SolidColorBrush* brush;
- device_context->CreateSolidColorBrush(colors[uni(rng)], &brush);
+ auto task = cru::SetInterval(0.5, [&window]() {
+ window.Repaint();
+ });
- device_context->FillRectangle(D2D1::RectF(100.0f, 100.0f, 300.0f, 200.0f), brush);
+ cru::SetTimeout(4, [task]() {
+ task->Cancel();
+ task->Cancel(); // test for idempotency.
+ });
+ });
+ */
- brush->Release();
- });
+ //test 2
- cru::SetTimeout(2.0, [&window]() {
- window.Repaint();
+ LinearLayout layout;
+ TextBlock text_block_1;
+ text_block_1.SetText(L"Hello World!!!");
+ TextBlock text_block_2;
+ text_block_2.SetText(L"This is a very very very very very long sentence!!!");
+ TextBlock text_block_3;
+ text_block_3.SetText(L"By crupest!!!");
- auto task = cru::SetInterval(0.5, [&window]() {
- window.Repaint();
- });
+ layout.AddChild(&text_block_1);
+ layout.AddChild(&text_block_2);
+ layout.AddChild(&text_block_3);
- cru::SetTimeout(4, [task]() {
- task->Cancel();
- task->Cancel(); // test for idempotency.
- });
- });
+ window.AddChild(&layout);
window.Show();
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;