diff options
author | crupest <crupest@outlook.com> | 2018-11-07 17:23:43 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2018-11-07 17:23:43 +0800 |
commit | 9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b (patch) | |
tree | 6184328d03e1963c8897a9e91f2c990dcfae053d | |
parent | df0d6e1e282c75d4d8154011715f0b74547b35db (diff) | |
download | cru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.tar.gz cru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.tar.bz2 cru-9f7de7f0775b86e3c82d4c5e3427a6f2fd98810b.zip |
Improve layout system.
-rw-r--r-- | CruUI.vcxproj | 3 | ||||
-rw-r--r-- | CruUI.vcxproj.filters | 9 | ||||
-rw-r--r-- | src/cru_debug.cpp | 11 | ||||
-rw-r--r-- | src/cru_debug.h (renamed from src/debug_base.h) | 8 | ||||
-rw-r--r-- | src/main.cpp | 8 | ||||
-rw-r--r-- | src/ui/control.cpp | 64 | ||||
-rw-r--r-- | src/ui/controls/linear_layout.cpp | 31 | ||||
-rw-r--r-- | src/ui/controls/text_block.h | 2 | ||||
-rw-r--r-- | src/ui/layout_base.h | 9 |
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; |