aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2018-11-07 17:23:43 +0800
committercrupest <crupest@outlook.com>2018-11-07 17:23:43 +0800
commit9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b (patch)
tree6184328d03e1963c8897a9e91f2c990dcfae053d
parentdf0d6e1e282c75d4d8154011715f0b74547b35db (diff)
downloadcru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.tar.gz
cru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.tar.bz2
cru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.zip
Improve layout system.
-rw-r--r--CruUI.vcxproj3
-rw-r--r--CruUI.vcxproj.filters9
-rw-r--r--src/cru_debug.cpp11
-rw-r--r--src/cru_debug.h (renamed from src/debug_base.h)8
-rw-r--r--src/main.cpp8
-rw-r--r--src/ui/control.cpp64
-rw-r--r--src/ui/controls/linear_layout.cpp31
-rw-r--r--src/ui/controls/text_block.h2
-rw-r--r--src/ui/layout_base.h9
9 files changed, 79 insertions, 66 deletions
diff --git a/CruUI.vcxproj b/CruUI.vcxproj
index 03bb8e3d..e5eb1950 100644
--- a/CruUI.vcxproj
+++ b/CruUI.vcxproj
@@ -117,6 +117,7 @@
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
+ <ClCompile Include="src\cru_debug.cpp" />
<ClCompile Include="src\application.cpp" />
<ClCompile Include="src\base.cpp" />
<ClCompile Include="src\exception.cpp" />
@@ -144,7 +145,7 @@
<ClInclude Include="src\application.h" />
<ClInclude Include="src\base.h" />
<ClInclude Include="src\cru_event.h" />
- <ClInclude Include="src\debug_base.h" />
+ <ClInclude Include="src\cru_debug.h" />
<ClInclude Include="src\exception.h" />
<ClInclude Include="src\global_macros.h" />
<ClInclude Include="src\graph\graph.h" />
diff --git a/CruUI.vcxproj.filters b/CruUI.vcxproj.filters
index 2696b52c..17672509 100644
--- a/CruUI.vcxproj.filters
+++ b/CruUI.vcxproj.filters
@@ -72,6 +72,9 @@
<ClCompile Include="src\ui\cursor.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="src\cru_debug.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\application.h">
@@ -83,9 +86,6 @@
<ClInclude Include="src\cru_event.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="src\debug_base.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="src\exception.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -146,6 +146,9 @@
<ClInclude Include="src\format.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="src\cru_debug.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\application.cpp">
diff --git a/src/cru_debug.cpp b/src/cru_debug.cpp
new file mode 100644
index 00000000..0007d21b
--- /dev/null
+++ b/src/cru_debug.cpp
@@ -0,0 +1,11 @@
+#include "cru_debug.h"
+
+#include "system_headers.h"
+
+namespace cru::debug
+{
+ void DebugMessage(const StringView& message)
+ {
+ ::OutputDebugStringW(message.data());
+ }
+}
diff --git a/src/debug_base.h b/src/cru_debug.h
index c750ad31..a9800774 100644
--- a/src/debug_base.h
+++ b/src/cru_debug.h
@@ -1,7 +1,5 @@
#pragma once
-
-#include "system_headers.h"
#include <functional>
#include "base.h"
@@ -9,6 +7,8 @@
namespace cru::debug
{
+ void DebugMessage(const StringView& message);
+
#ifdef CRU_DEBUG
inline void DebugTime(const std::function<void()>& action, const StringView& hint_message)
{
@@ -16,7 +16,7 @@ namespace cru::debug
action();
const auto after = std::chrono::steady_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
- OutputDebugStringW(Format(L"{}: {}ms.\n", hint_message, duration.count()).c_str());
+ DebugMessage(Format(L"{}: {}ms.\n", hint_message, duration.count()));
}
template<typename TReturn>
@@ -26,7 +26,7 @@ namespace cru::debug
auto&& result = action();
const auto after = std::chrono::steady_clock::now();
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
- OutputDebugStringW(Format(L"{}: {}ms.\n", hint_message, duration.count()).c_str());
+ DebugMessage(Format(L"{}: {}ms.\n", hint_message, duration.count()));
return std::move(result);
}
#else
diff --git a/src/main.cpp b/src/main.cpp
index ab641075..a15fa4da 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -84,7 +84,7 @@ int APIENTRY wWinMain(
});
*/
- /*
+
//test 2
const auto layout = CreateWithLayout<LinearLayout>(LayoutSideParams::Exactly(500), LayoutSideParams::Content());
@@ -112,7 +112,8 @@ int APIENTRY wWinMain(
{
const auto button = Button::Create();
- button->AddChild(MarginContainer::Create(Thickness(20, 5), { TextBlock::Create(L"button") }));
+ button->GetLayoutParams()->padding = Thickness(20, 5);
+ button->AddChild(TextBlock::Create(L"button"));
layout->AddChild(button);
}
@@ -138,7 +139,6 @@ int APIENTRY wWinMain(
window.AddChild(layout);
- */
/*
window.AddChild(
@@ -149,6 +149,7 @@ int APIENTRY wWinMain(
));
*/
+ /* test 3
const auto linear_layout = CreateWithLayout<LinearLayout>(Thickness(50, 50), Thickness(50, 50), LinearLayout::Orientation::Vertical, ControlList{
Button::Create({
TextBlock::Create(L"Button")
@@ -159,6 +160,7 @@ int APIENTRY wWinMain(
linear_layout->SetBordered(true);
window.AddChild(linear_layout);
+ */
window.Show();
diff --git a/src/ui/control.cpp b/src/ui/control.cpp
index 93d26e81..79def066 100644
--- a/src/ui/control.cpp
+++ b/src/ui/control.cpp
@@ -5,6 +5,7 @@
#include "window.h"
#include "graph/graph.h"
#include "exception.h"
+#include "cru_debug.h"
namespace cru {
namespace ui {
@@ -697,6 +698,9 @@ namespace cru {
{
const auto layout_params = GetLayoutParams();
+ if (!layout_params->Validate())
+ throw std::runtime_error("LayoutParams is not valid. Please check it.");
+
auto border_size = Size::Zero();
if (is_bordered_)
{
@@ -704,54 +708,39 @@ namespace cru {
border_size = Size(border_width * 2.0f, border_width * 2.0f);
}
+ // the total size of padding, border and margin
const auto outer_size = ThicknessToSize(layout_params->padding) +
ThicknessToSize(layout_params->margin) + border_size;
- if (!layout_params->Validate())
- throw std::runtime_error("LayoutParams is not valid. Please check it.");
- auto&& get_available_length_for_child = [](const LayoutSideParams& layout_length, const float available_length) -> float
+ auto&& get_content_measure_length = [](const LayoutSideParams& layout_length, const float available_length, const float outer_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();
- }
+ if (layout_length.mode == MeasureMode::Exactly)
+ return layout_length.length;
+ if (available_length > outer_length)
+ return available_length - outer_length;
+ return 0.0;
};
- const auto size_for_children = AtLeast0(Size(
- get_available_length_for_child(layout_params->width, available_size.width),
- get_available_length_for_child(layout_params->height, available_size.height)
- ) - outer_size);
+ // if padding, margin and border exceeded, then content size is 0.
+ const auto content_measure_size = Size(
+ get_content_measure_length(layout_params->width, available_size.width, outer_size.width),
+ get_content_measure_length(layout_params->height, available_size.height, outer_size.height)
+ );
- const auto actual_size_for_children = OnMeasureContent(size_for_children);
+ const auto content_actual_size = OnMeasureContent(content_measure_size);
- auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float length_for_children, const float actual_length_for_children) -> float
+ auto&& calculate_final_length = [](const LayoutSideParams& layout_length, const float measure_length, const float actual_length) -> float
{
- switch (layout_length.mode)
- {
- case MeasureMode::Exactly:
- case MeasureMode::Stretch:
- return length_for_children;
- case MeasureMode::Content:
- return actual_length_for_children;
- default:
- UnreachableCode();
- }
+ // only use measure length when stretch and actual length is smaller than measure length, that is "stretch"
+ if (layout_length.mode == MeasureMode::Stretch && actual_length < measure_length)
+ return measure_length;
+ return actual_length;
};
const auto final_size = Size(
- calculate_final_length(layout_params->width, size_for_children.width, actual_size_for_children.width),
- calculate_final_length(layout_params->height, size_for_children.height, actual_size_for_children.height)
+ calculate_final_length(layout_params->width, content_measure_size.width, content_actual_size.width),
+ calculate_final_length(layout_params->height, content_measure_size.height, content_actual_size.height)
) + outer_size;
return final_size;
@@ -774,6 +763,11 @@ namespace cru {
rect.height - layout_params->padding.GetVerticalTotal() - layout_params->margin.GetVerticalTotal() - border_width * 2.0f
);
+ if (content_rect.width < 0.0)
+ throw std::runtime_error(Format("Width to layout must sufficient. But in {}, width for content is {}.", ToUtf8String(GetControlType()), content_rect.width));
+ if (content_rect.height < 0.0)
+ throw std::runtime_error(Format("Height to layout must sufficient. But in {}, height for content is {}.", ToUtf8String(GetControlType()), content_rect.height));
+
OnLayoutContent(content_rect);
}
diff --git a/src/ui/controls/linear_layout.cpp b/src/ui/controls/linear_layout.cpp
index c23957ed..ed445f4c 100644
--- a/src/ui/controls/linear_layout.cpp
+++ b/src/ui/controls/linear_layout.cpp
@@ -27,7 +27,7 @@ namespace cru::ui::controls
Size LinearLayout::OnMeasureContent(const Size& available_size)
{
- auto rest_available_size_for_children = available_size;
+ auto actual_size_for_children = Size::Zero();
float secondary_side_child_max_length = 0;
@@ -40,9 +40,10 @@ namespace cru::ui::controls
const auto mode = control->GetLayoutParams()->width.mode;
if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
{
- control->Measure(AtLeast0(rest_available_size_for_children));
+ Size current_available_size(AtLeast0(available_size.width - actual_size_for_children.width), available_size.height);
+ control->Measure(current_available_size);
const auto size = control->GetDesiredSize();
- rest_available_size_for_children.width -= size.width;
+ actual_size_for_children.width += size.width;
secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length);
}
else
@@ -54,9 +55,10 @@ namespace cru::ui::controls
const auto mode = control->GetLayoutParams()->height.mode;
if (mode == MeasureMode::Content || mode == MeasureMode::Exactly)
{
- control->Measure(AtLeast0(rest_available_size_for_children));
+ Size current_available_size(available_size.width, AtLeast0(available_size.height - actual_size_for_children.height));
+ control->Measure(current_available_size);
const auto size = control->GetDesiredSize();
- rest_available_size_for_children.height -= size.height;
+ actual_size_for_children.height += size.height;
secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length);
}
else
@@ -65,38 +67,31 @@ namespace cru::ui::controls
if (orientation_ == Orientation::Horizontal)
{
- const auto available_width = rest_available_size_for_children.width / stretch_control_list.size();
+ const auto available_width = AtLeast0(available_size.width - actual_size_for_children.width) / stretch_control_list.size();
for (const auto control : stretch_control_list)
{
- control->Measure(Size(AtLeast0(available_width), rest_available_size_for_children.height));
+ control->Measure(Size(available_width, available_size.height));
const auto size = control->GetDesiredSize();
- rest_available_size_for_children.width -= size.width;
+ actual_size_for_children.width += size.width;
secondary_side_child_max_length = std::max(size.height, secondary_side_child_max_length);
}
}
else
{
- const auto available_height = rest_available_size_for_children.height / stretch_control_list.size();
+ const auto available_height = AtLeast0(available_size.height - actual_size_for_children.height) / stretch_control_list.size();
for (const auto control : stretch_control_list)
{
- control->Measure(Size(rest_available_size_for_children.width, AtLeast0(available_height)));
+ control->Measure(Size(available_size.width, available_height));
const auto size = control->GetDesiredSize();
- rest_available_size_for_children.height -= size.height;
+ actual_size_for_children.height += size.height;
secondary_side_child_max_length = std::max(size.width, secondary_side_child_max_length);
}
}
- auto actual_size_for_children = available_size;
if (orientation_ == Orientation::Horizontal)
- {
- actual_size_for_children.width -= rest_available_size_for_children.width;
actual_size_for_children.height = secondary_side_child_max_length;
- }
else
- {
actual_size_for_children.width = secondary_side_child_max_length;
- actual_size_for_children.height -= rest_available_size_for_children.height;
- }
return actual_size_for_children;
}
diff --git a/src/ui/controls/text_block.h b/src/ui/controls/text_block.h
index cd0af1cc..681dc47b 100644
--- a/src/ui/controls/text_block.h
+++ b/src/ui/controls/text_block.h
@@ -19,6 +19,8 @@ namespace cru::ui::controls
return text_block;
}
+ using TextControl::SetSelectable; // Make this public.
+
protected:
TextBlock(
const Microsoft::WRL::ComPtr<IDWriteTextFormat>& init_text_format,
diff --git a/src/ui/layout_base.h b/src/ui/layout_base.h
index 0d924436..662210bd 100644
--- a/src/ui/layout_base.h
+++ b/src/ui/layout_base.h
@@ -63,6 +63,11 @@ namespace cru
return top + bottom;
}
+ float Validate() const
+ {
+ return left >= 0.0 && top >= 0.0 && right >= 0.0 && bottom >= 0.0;
+ }
+
float left;
float top;
float right;
@@ -96,7 +101,7 @@ namespace cru
constexpr bool Validate() const
{
- return !(mode == MeasureMode::Exactly && length < 0.0);
+ return length >= 0.0;
}
float length = 0.0;
@@ -115,7 +120,7 @@ namespace cru
bool Validate() const
{
- return width.Validate() && height.Validate();
+ return width.Validate() && height.Validate() && margin.Validate() && padding.Validate();
}
LayoutSideParams width;