diff --git a/include/eepp/ui/flexlayouter.hpp b/include/eepp/ui/flexlayouter.hpp index ef05dabb3..5c5f20e94 100644 --- a/include/eepp/ui/flexlayouter.hpp +++ b/include/eepp/ui/flexlayouter.hpp @@ -89,6 +89,7 @@ class EE_API FlexLayouter : public UILayouter { Float getMaxIntrinsicWidth() override; Float getBaseline() const { return mContainerBaseline; } + bool isMeasuringItems() const { return mMeasuringItems; } protected: struct Axis { @@ -141,6 +142,7 @@ class EE_API FlexLayouter : public UILayouter { SmallVector mItems; Float mContainerBaseline{ 0.f }; + bool mMeasuringItems{ false }; CSSFlexDirection mDirection{ CSSFlexDirection::Row }; CSSFlexWrap mWrap{ CSSFlexWrap::NoWrap }; CSSJustifyContent mJustify{ CSSJustifyContent::FlexStart }; diff --git a/src/eepp/ui/blocklayouter.cpp b/src/eepp/ui/blocklayouter.cpp index 5d4e10270..660a31c86 100644 --- a/src/eepp/ui/blocklayouter.cpp +++ b/src/eepp/ui/blocklayouter.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -10,13 +11,21 @@ namespace EE { namespace UI { -static bool isStretchedFlexItem( UIHTMLWidget* widget ) { +static bool isStretchedFlexItemInAxis( UIHTMLWidget* widget, bool horizontalAxis ) { Node* parent = widget->getParent(); if ( !parent || !parent->isWidget() || !parent->isType( UI_TYPE_HTML_WIDGET ) ) return false; UIHTMLWidget* parentHtml = parent->asType(); if ( !parentHtml->isFlex() ) return false; + if ( static_cast( parentHtml->getLayouter() )->isMeasuringItems() ) + return false; + + CSSFlexDirection direction = parentHtml->getFlexDirection(); + bool crossAxisIsHorizontal = + direction == CSSFlexDirection::Column || direction == CSSFlexDirection::ColumnReverse; + if ( horizontalAxis != crossAxisIsHorizontal ) + return false; CSSAlignSelf alignSelf = widget->getAlignSelf(); if ( alignSelf == CSSAlignSelf::Stretch ) @@ -179,9 +188,11 @@ void BlockLayouter::updateLayout() { } } - if ( totW != mContainer->getPixelsSize().getWidth() || - ( mContainer->getLayoutWidthPolicy() == SizePolicy::WrapContent && - !isStretchedFlexItem( widget ) ) ) + bool preserveStretchedWidth = mContainer->getLayoutWidthPolicy() == SizePolicy::WrapContent && + isStretchedFlexItemInAxis( widget, true ); + if ( !preserveStretchedWidth && + ( totW != mContainer->getPixelsSize().getWidth() || + mContainer->getLayoutWidthPolicy() == SizePolicy::WrapContent ) ) mContainer->setInternalPixelsWidth( totW ); Float totH = mContainer->getPixelsSize().getHeight(); @@ -207,9 +218,11 @@ void BlockLayouter::updateLayout() { } } - if ( totH != mContainer->getPixelsSize().getHeight() || - ( mContainer->getLayoutHeightPolicy() == SizePolicy::WrapContent && - !isStretchedFlexItem( widget ) ) ) + bool preserveStretchedHeight = mContainer->getLayoutHeightPolicy() == SizePolicy::WrapContent && + isStretchedFlexItemInAxis( widget, false ); + if ( !preserveStretchedHeight && + ( totH != mContainer->getPixelsSize().getHeight() || + mContainer->getLayoutHeightPolicy() == SizePolicy::WrapContent ) ) mContainer->setInternalPixelsHeight( totH ); mContainer->endAttributesTransaction(); diff --git a/src/eepp/ui/flexlayouter.cpp b/src/eepp/ui/flexlayouter.cpp index 49e70bd3f..2e251971e 100644 --- a/src/eepp/ui/flexlayouter.cpp +++ b/src/eepp/ui/flexlayouter.cpp @@ -1223,8 +1223,8 @@ void FlexLayouter::updateLayout() { return; RichText* richText = widget->isType( UI_TYPE_RICHTEXT ) - ? widget->asType()->getRichTextPtr() - : nullptr; + ? widget->asType()->getRichTextPtr() + : nullptr; bool preserveFloatConstrainedBFCWidth = widget->establishesBlockFormattingContext() && widget->getLayoutWidthPolicy() == SizePolicy::MatchParent && richText != nullptr && @@ -1387,6 +1387,7 @@ void FlexLayouter::updateLayout() { bool indefiniteMainSize = ( mainAxis.horizontal && widthPolicy == SizePolicy::WrapContent ) || ( !mainAxis.horizontal && heightPolicy == SizePolicy::WrapContent ); + mMeasuringItems = true; measureFlexItems( mainAxis, crossAxis, containerCrossSize, containerWidth, containerHeight, containerPadding, indefiniteMainSize, indefiniteCrossSize ); @@ -1410,6 +1411,7 @@ void FlexLayouter::updateLayout() { alignMainAxis( line, containerMainSize, mColumnGap ); resolveCrossSizes( line, crossAxis, mainAxis ); } + mMeasuringItems = false; alignCrossAxis( lines, containerCrossSize, mRowGap, crossAxis ); diff --git a/src/tests/unit_tests/uihtml_tests.cpp b/src/tests/unit_tests/uihtml_tests.cpp index 2fb357659..b34530cd5 100644 --- a/src/tests/unit_tests/uihtml_tests.cpp +++ b/src/tests/unit_tests/uihtml_tests.cpp @@ -5136,6 +5136,47 @@ UTEST( UIHTML, FlexLiItemsWrapContentWidth ) { Engine::destroySingleton(); } +UTEST( UIHTML, FlexStretchPreservesAutoCrossSizeAfterChildLayout ) { + Engine::instance()->createWindow( + WindowSettings( 1024, 768, "Flex Stretch Auto Cross Size Test", WindowStyle::Default, + WindowBackend::Default, 32, {}, 1, false, true ), + ContextSettings( false, 0, 0, GLv_default, true, false ) ); + + UISceneNode* sceneNode = init_test_inline_block(); + sceneNode->loadLayoutFromString( HTMLFormatter::HTMLtoXML( R"html( + +
+ +
+
+ + )html" ) ); + + sceneNode->update( Seconds( 1 ) ); + sceneNode->updateDirtyLayouts(); + + auto* containerNode = sceneNode->getRoot()->findByClass( "container" ); + auto* shortItemNode = sceneNode->getRoot()->findByClass( "short" ); + auto* tallItemNode = sceneNode->getRoot()->findByClass( "tall" ); + ASSERT_TRUE( containerNode != nullptr ); + ASSERT_TRUE( shortItemNode != nullptr ); + ASSERT_TRUE( tallItemNode != nullptr ); + auto* container = containerNode->asType(); + auto* shortItem = shortItemNode->asType(); + auto* tallItem = tallItemNode->asType(); + + EXPECT_NEAR( container->getPixelsSize().getHeight(), tallItem->getPixelsSize().getHeight(), + 1.f ); + EXPECT_NEAR( shortItem->getPixelsSize().getHeight(), tallItem->getPixelsSize().getHeight(), + 1.f ); + + Engine::destroySingleton(); +} + UTEST( UIHTML, ImagePercentageWidthRespectsParentMaxWidth ) { auto win = Engine::instance()->createWindow( WindowSettings( 1024, 768, "img pct width respects parent max-width", WindowStyle::Default,